version number accordingly. If you have not installed the
BuildTools, but e.g. Professional, adjust the
product ID accordingly.
-
IBM XL C/C++
-
Please consult the AIX section of the Supported
-Build Platforms OpenJDK Build Wiki page for details about which
-versions of XLC are supported.
+
IBM Open XL C/C++
+
The minimum accepted version of Open XL is 17.1.1.4. This is in
+essence clang 15, and will be treated as such by the OpenJDK build
+system.
Boot JDK Requirements
Paradoxically, building the JDK requires a pre-existing JDK. This is
called the "boot JDK". The boot JDK does not, however, have to be a JDK
diff --git a/doc/building.md b/doc/building.md
index 5812b7529e3..d60f7e94164 100644
--- a/doc/building.md
+++ b/doc/building.md
@@ -487,11 +487,10 @@ that the " characters are essential)
accordingly. If you have not installed the `BuildTools`, but e.g.
`Professional`, adjust the product ID accordingly.
-### IBM XL C/C++
+### IBM Open XL C/C++
-Please consult the AIX section of the [Supported Build Platforms](
-https://wiki.openjdk.org/display/Build/Supported+Build+Platforms) OpenJDK Build
-Wiki page for details about which versions of XLC are supported.
+The minimum accepted version of Open XL is 17.1.1.4. This is in essence clang
+15, and will be treated as such by the OpenJDK build system.
## Boot JDK Requirements
diff --git a/make/autoconf/build-performance.m4 b/make/autoconf/build-performance.m4
index 40ca9d41d33..4414ea0d93c 100644
--- a/make/autoconf/build-performance.m4
+++ b/make/autoconf/build-performance.m4
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2024, 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
@@ -359,9 +359,6 @@ AC_DEFUN_ONCE([BPERF_SETUP_PRECOMPILED_HEADERS],
if test "x$ICECC" != "x"; then
AC_MSG_RESULT([no, does not work effectively with icecc])
PRECOMPILED_HEADERS_AVAILABLE=false
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- AC_MSG_RESULT([no, does not work with xlc])
- PRECOMPILED_HEADERS_AVAILABLE=false
elif test "x$TOOLCHAIN_TYPE" = xgcc; then
# Check that the compiler actually supports precomp headers.
echo "int alfa();" > conftest.h
diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4
index dc4426d1d45..78bca110357 100644
--- a/make/autoconf/flags-cflags.m4
+++ b/make/autoconf/flags-cflags.m4
@@ -77,12 +77,6 @@ AC_DEFUN([FLAGS_SETUP_SHARED_LIBS],
fi
fi
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- SHARED_LIBRARY_FLAGS="-qmkshrobj -bM:SRE -bnoentry"
- SET_EXECUTABLE_ORIGIN=""
- SET_SHARED_LIBRARY_ORIGIN=''
- SET_SHARED_LIBRARY_NAME=''
-
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
SHARED_LIBRARY_FLAGS="-dll"
SET_EXECUTABLE_ORIGIN=''
@@ -152,8 +146,6 @@ AC_DEFUN([FLAGS_SETUP_DEBUG_SYMBOLS],
CFLAGS_DEBUG_SYMBOLS="-g ${GDWARF_FLAGS}"
ASFLAGS_DEBUG_SYMBOLS="-g"
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- CFLAGS_DEBUG_SYMBOLS="-g1"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
CFLAGS_DEBUG_SYMBOLS="-Z7"
fi
@@ -219,11 +211,7 @@ AC_DEFUN([DEBUG_PREFIX_MAP_GCC_INCLUDE_PATHS],
AC_DEFUN([FLAGS_SETUP_WARNINGS],
[
# Set default value.
- if test "x$TOOLCHAIN_TYPE" != xxlc; then
- WARNINGS_AS_ERRORS_DEFAULT=true
- else
- WARNINGS_AS_ERRORS_DEFAULT=false
- fi
+ WARNINGS_AS_ERRORS_DEFAULT=true
UTIL_ARG_ENABLE(NAME: warnings-as-errors, DEFAULT: $WARNINGS_AS_ERRORS_DEFAULT,
RESULT: WARNINGS_AS_ERRORS,
@@ -273,15 +261,6 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS],
DISABLED_WARNINGS="unknown-warning-option unused-parameter unused"
;;
-
- xlc)
- DISABLE_WARNING_PREFIX="-Wno-"
- CFLAGS_WARNINGS_ARE_ERRORS="-qhalt=w"
-
- # Possibly a better subset than "all" is "lan:trx:ret:zea:cmp:ret"
- WARNINGS_ENABLE_ALL="-qinfo=all -qformat=all"
- DISABLED_WARNINGS=""
- ;;
esac
AC_SUBST(DISABLE_WARNING_PREFIX)
AC_SUBST(BUILD_CC_DISABLE_WARNING_PREFIX)
@@ -363,15 +342,6 @@ AC_DEFUN([FLAGS_SETUP_OPTIMIZATION],
C_O_FLAG_SIZE="-Os"
C_O_FLAG_DEBUG="-O0"
C_O_FLAG_NONE="-O0"
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- C_O_FLAG_HIGHEST_JVM="-O3 -qhot=level=1 -qinline -qinlglue"
- C_O_FLAG_HIGHEST="-O3 -qhot=level=1 -qinline -qinlglue"
- C_O_FLAG_HI="-O3 -qinline -qinlglue"
- C_O_FLAG_NORM="-O2"
- C_O_FLAG_DEBUG="-qnoopt"
- # FIXME: Value below not verified.
- C_O_FLAG_DEBUG_JVM=""
- C_O_FLAG_NONE="-qnoopt"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
C_O_FLAG_HIGHEST_JVM="-O2 -Oy-"
C_O_FLAG_HIGHEST="-O2"
@@ -524,12 +494,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
else
DEBUG_CFLAGS_JDK="-DDEBUG"
- if test "x$TOOLCHAIN_TYPE" = xxlc; then
- # We need '-qminimaltoc' or '-qpic=large -bbigtoc' if the TOC overflows.
- # Hotspot now overflows its 64K TOC (currently only for debug),
- # so for debug we build with '-qpic=large -bbigtoc'.
- DEBUG_CFLAGS_JVM="-qpic=large"
- fi
if test "x$TOOLCHAIN_TYPE" = xclang && test "x$OPENJDK_TARGET_OS" = xaix; then
DEBUG_CFLAGS_JVM="-fpic -mcmodel=large"
fi
@@ -546,9 +510,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
ALWAYS_DEFINES_JVM="-D_GNU_SOURCE -D_REENTRANT"
elif test "x$TOOLCHAIN_TYPE" = xclang; then
ALWAYS_DEFINES_JVM="-D_GNU_SOURCE"
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- ALWAYS_DEFINES_JVM="-D_REENTRANT"
- ALWAYS_DEFINES_JDK="-D_GNU_SOURCE -D_REENTRANT -DSTDC"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
# Access APIs for Windows 8 and above
# see https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt?view=msvc-170
@@ -612,12 +573,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
TOOLCHAIN_CFLAGS_JDK_CONLY="-fno-strict-aliasing" # technically NOT for CXX
fi
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- # Suggested additions: -qsrcmsg to get improved error reporting
- # set -qtbtable=full for a better traceback table/better stacks in hs_err when xlc16 is used
- TOOLCHAIN_CFLAGS_JDK="-qtbtable=full -qchars=signed -qfullpath -qsaveopt -qstackprotect" # add on both CFLAGS
- TOOLCHAIN_CFLAGS_JVM="-qtbtable=full -qtune=balanced -fno-exceptions \
- -qalias=noansi -qstrict -qtls=default -qnortti -qnoeh -qignerrno -qstackprotect"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
# The -utf-8 option sets source and execution character sets to UTF-8 to enable correct
# compilation of all source files regardless of the active code page on Windows.
@@ -626,7 +581,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
fi
# CFLAGS C language level for JDK sources (hotspot only uses C++)
- if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang || test "x$TOOLCHAIN_TYPE" = xxlc; then
+ if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
LANGSTD_CFLAGS="-std=c11"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
LANGSTD_CFLAGS="-std:c11"
@@ -634,12 +589,12 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
TOOLCHAIN_CFLAGS_JDK_CONLY="$LANGSTD_CFLAGS $TOOLCHAIN_CFLAGS_JDK_CONLY"
# CXXFLAGS C++ language level for all of JDK, including Hotspot.
- if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang || test "x$TOOLCHAIN_TYPE" = xxlc; then
+ if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
LANGSTD_CXXFLAGS="-std=c++14"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
LANGSTD_CXXFLAGS="-std:c++14"
else
- AC_MSG_ERROR([Don't know how to enable C++14 for this toolchain])
+ AC_MSG_ERROR([Cannot enable C++14 for this toolchain])
fi
TOOLCHAIN_CFLAGS_JDK_CXXONLY="$TOOLCHAIN_CFLAGS_JDK_CXXONLY $LANGSTD_CXXFLAGS"
TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM $LANGSTD_CXXFLAGS"
@@ -658,8 +613,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
WARNING_CFLAGS="$WARNINGS_ENABLE_ALL"
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- WARNING_CFLAGS="" # currently left empty
fi
# Set some additional per-OS defines.
@@ -684,31 +637,16 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
PICFLAG="-fPIC"
PIEFLAG="-fPIE"
- elif test "x$TOOLCHAIN_TYPE" = xclang && test "x$OPENJDK_TARGET_OS" = xaix; then
- JVM_PICFLAG="-fpic -mcmodel=large -Wl,-bbigtoc
- JDK_PICFLAG="-fpic
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- # '-qpic' defaults to 'qpic=small'. This means that the compiler generates only
- # one instruction for accessing the TOC. If the TOC grows larger than 64K, the linker
- # will have to patch this single instruction with a call to some out-of-order code which
- # does the load from the TOC. This is of course slower, and we also would have
- # to use '-bbigtoc' for linking anyway so we could also change the PICFLAG to 'qpic=large'.
- # With 'qpic=large' the compiler will by default generate a two-instruction sequence which
- # can be patched directly by the linker and does not require a jump to out-of-order code.
- #
- # Since large TOC causes perf. overhead, only pay it where we must. Currently this is
- # for all libjvm variants (both gtest and normal) but no other binaries. So, build
- # libjvm with -qpic=large and link with -bbigtoc.
- JVM_PICFLAG="-qpic=large"
- JDK_PICFLAG="-qpic"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
PICFLAG=""
fi
- if test "x$TOOLCHAIN_TYPE" != xxlc; then
+ if test "x$TOOLCHAIN_TYPE" = xclang && test "x$OPENJDK_TARGET_OS" = xaix; then
+ JVM_PICFLAG="-fpic -mcmodel=large"
+ else
JVM_PICFLAG="$PICFLAG"
- JDK_PICFLAG="$PICFLAG"
fi
+ JDK_PICFLAG="$PICFLAG"
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
# Linking is different on MacOSX
@@ -758,8 +696,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
$1_DEFINES_CPU_JDK="${$1_DEFINES_CPU_JDK} -DARCH='\"$FLAGS_CPU_LEGACY\"' \
-D$FLAGS_CPU_LEGACY"
- if test "x$FLAGS_CPU_BITS" = x64 && test "x$FLAGS_OS" != xaix; then
- # xlc on AIX defines _LP64=1 by default and issues a warning if we redefine it.
+ if test "x$FLAGS_CPU_BITS" = x64; then
$1_DEFINES_CPU_JDK="${$1_DEFINES_CPU_JDK} -D_LP64=1"
$1_DEFINES_CPU_JVM="${$1_DEFINES_CPU_JVM} -D_LP64=1"
fi
@@ -836,11 +773,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
$1_CFLAGS_CPU="-mcpu=pwr8"
fi
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- if test "x$FLAGS_CPU" = xppc64; then
- $1_CFLAGS_CPU_JVM="-qarch=ppc64"
- fi
-
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
if test "x$FLAGS_CPU" = xx86; then
$1_CFLAGS_CPU_JVM="-arch:IA32"
diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4
index 58bc4a44bfb..b0f56a53a3d 100644
--- a/make/autoconf/flags-ldflags.m4
+++ b/make/autoconf/flags-ldflags.m4
@@ -86,11 +86,6 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
-Wl,-bernotok -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k"
BASIC_LDFLAGS_JVM_ONLY="$BASIC_LDFLAGS_JVM_ONLY -Wl,-lC_r -Wl,-bbigtoc"
fi
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- BASIC_LDFLAGS="-b64 -brtl -bnorwexec -bnolibpath -bnoexpall -bernotok -btextpsize:64K \
- -bdatapsize:64K -bstackpsize:64K"
- # libjvm.so has gotten too large for normal TOC size; compile with qpic=large and link with bigtoc
- BASIC_LDFLAGS_JVM_ONLY="-Wl,-lC_r -bbigtoc"
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
BASIC_LDFLAGS="-opt:ref"
@@ -120,14 +115,6 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER],
fi
fi
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- # We need '-qminimaltoc' or '-qpic=large -bbigtoc' if the TOC overflows.
- # Hotspot now overflows its 64K TOC (currently only for debug),
- # so we build with '-qpic=large -bbigtoc'.
- if test "x$DEBUG_LEVEL" != xrelease; then
- DEBUGLEVEL_LDFLAGS_JVM_ONLY="$DEBUGLEVEL_LDFLAGS_JVM_ONLY -bbigtoc"
- fi
-
elif test "x$TOOLCHAIN_TYPE" = xclang && test "x$OPENJDK_TARGET_OS" = xaix; then
# We need '-fpic' or '-fpic -mcmodel=large -Wl,-bbigtoc' if the TOC overflows.
# Hotspot now overflows its 64K TOC (currently only for debug),
diff --git a/make/autoconf/flags.m4 b/make/autoconf/flags.m4
index 147382f398e..d50538108a4 100644
--- a/make/autoconf/flags.m4
+++ b/make/autoconf/flags.m4
@@ -261,12 +261,9 @@ AC_DEFUN_ONCE([FLAGS_PRE_TOOLCHAIN],
# The sysroot flags are needed for configure to be able to run the compilers
FLAGS_SETUP_SYSROOT_FLAGS
- # For xlc, the word size flag is required for correct behavior.
# For clang/gcc, the flag is only strictly required for reduced builds, but
# set it always where possible (x86 and ppc).
- if test "x$TOOLCHAIN_TYPE" = xxlc; then
- MACHINE_FLAG="-q${OPENJDK_TARGET_CPU_BITS}"
- elif test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
+ if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
if test "x$OPENJDK_TARGET_CPU_ARCH" = xx86 &&
test "x$OPENJDK_TARGET_CPU" != xx32 ||
test "x$OPENJDK_TARGET_CPU_ARCH" = xppc; then
@@ -321,47 +318,6 @@ AC_DEFUN_ONCE([FLAGS_PRE_TOOLCHAIN],
AC_DEFUN([FLAGS_SETUP_TOOLCHAIN_CONTROL],
[
- # COMPILER_TARGET_BITS_FLAG : option for selecting 32- or 64-bit output
- # COMPILER_COMMAND_FILE_FLAG : option for passing a command file to the compiler
- # COMPILER_BINDCMD_FILE_FLAG : option for specifying a file which saves the binder
- # commands produced by the link step (currently AIX only)
- if test "x$TOOLCHAIN_TYPE" = xxlc; then
- COMPILER_TARGET_BITS_FLAG="-q"
- COMPILER_COMMAND_FILE_FLAG="-f"
- COMPILER_BINDCMD_FILE_FLAG="-bloadmap:"
- else
- COMPILER_TARGET_BITS_FLAG="-m"
- COMPILER_COMMAND_FILE_FLAG="@"
- COMPILER_BINDCMD_FILE_FLAG=""
-
- # Check if @file is supported by gcc
- if test "x$TOOLCHAIN_TYPE" = xgcc; then
- AC_MSG_CHECKING([if @file is supported by gcc])
- # Extra empty "" to prevent ECHO from interpreting '--version' as argument
- $ECHO "" "--version" > command.file
- # Redirect stderr and stdout to config.log (AS_MESSAGE_LOG_FD) via merge
- if $CXX @command.file 2>&AS_MESSAGE_LOG_FD >&AS_MESSAGE_LOG_FD; then
- AC_MSG_RESULT(yes)
- COMPILER_COMMAND_FILE_FLAG="@"
- else
- AC_MSG_RESULT(no)
- COMPILER_COMMAND_FILE_FLAG=
- fi
- $RM command.file
- fi
- fi
-
- AC_SUBST(COMPILER_TARGET_BITS_FLAG)
- AC_SUBST(COMPILER_COMMAND_FILE_FLAG)
- AC_SUBST(COMPILER_BINDCMD_FILE_FLAG)
-
- # Check that the compiler supports -mX (or -qX on AIX) flags
- # Set COMPILER_SUPPORTS_TARGET_BITS_FLAG to 'true' if it does
- FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}],
- IF_TRUE: [COMPILER_SUPPORTS_TARGET_BITS_FLAG=true],
- IF_FALSE: [COMPILER_SUPPORTS_TARGET_BITS_FLAG=false])
- AC_SUBST(COMPILER_SUPPORTS_TARGET_BITS_FLAG)
-
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
CC_OUT_OPTION=-Fo
else
@@ -376,8 +332,6 @@ AC_DEFUN([FLAGS_SETUP_TOOLCHAIN_CONTROL],
GENDEPS_FLAGS="-MMD -MF"
elif test "x$TOOLCHAIN_TYPE" = xclang; then
GENDEPS_FLAGS="-MMD -MF"
- elif test "x$TOOLCHAIN_TYPE" = xxlc; then
- GENDEPS_FLAGS="-qmakedep=gcc -MF"
fi
AC_SUBST(GENDEPS_FLAGS)
])
diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template
index 863a51eeb4a..c0a0c9e1506 100644
--- a/make/autoconf/spec.gmk.template
+++ b/make/autoconf/spec.gmk.template
@@ -477,7 +477,7 @@ MACOSX_VERSION_MAX := @MACOSX_VERSION_MAX@
MACOSX_CODESIGN_MODE := @MACOSX_CODESIGN_MODE@
MACOSX_CODESIGN_IDENTITY := @MACOSX_CODESIGN_IDENTITY@
-# Toolchain type: gcc, clang, xlc, microsoft...
+# Toolchain type: gcc, clang, microsoft...
TOOLCHAIN_TYPE := @TOOLCHAIN_TYPE@
TOOLCHAIN_VERSION := @TOOLCHAIN_VERSION@
CC_VERSION_NUMBER := @CC_VERSION_NUMBER@
@@ -486,17 +486,6 @@ CXX_VERSION_NUMBER := @CXX_VERSION_NUMBER@
# Legacy support
HOTSPOT_TOOLCHAIN_TYPE := @HOTSPOT_TOOLCHAIN_TYPE@
-# Option used to tell the compiler whether to create 32- or 64-bit executables
-COMPILER_TARGET_BITS_FLAG := @COMPILER_TARGET_BITS_FLAG@
-COMPILER_SUPPORTS_TARGET_BITS_FLAG := @COMPILER_SUPPORTS_TARGET_BITS_FLAG@
-
-# Option used to pass a command file to the compiler
-COMPILER_COMMAND_FILE_FLAG := @COMPILER_COMMAND_FILE_FLAG@
-
-# Option for specifying a file which saves the binder commands
-# produced by the link step (for debugging, currently AIX only)
-COMPILER_BINDCMD_FILE_FLAG := @COMPILER_BINDCMD_FILE_FLAG@
-
CC_OUT_OPTION := @CC_OUT_OPTION@
# Flags used for overriding the default opt setting for a C/C++ source file.
diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4
index 15ebc0cbbbc..acccac3e320 100644
--- a/make/autoconf/toolchain.m4
+++ b/make/autoconf/toolchain.m4
@@ -35,25 +35,23 @@
m4_include([toolchain_microsoft.m4])
# All valid toolchains, regardless of platform (used by help.m4)
-VALID_TOOLCHAINS_all="gcc clang xlc microsoft"
+VALID_TOOLCHAINS_all="gcc clang microsoft"
# These toolchains are valid on different platforms
VALID_TOOLCHAINS_linux="gcc clang"
VALID_TOOLCHAINS_macosx="clang"
-VALID_TOOLCHAINS_aix="xlc clang"
+VALID_TOOLCHAINS_aix="clang"
VALID_TOOLCHAINS_windows="microsoft"
# Toolchain descriptions
TOOLCHAIN_DESCRIPTION_clang="clang/LLVM"
TOOLCHAIN_DESCRIPTION_gcc="GNU Compiler Collection"
TOOLCHAIN_DESCRIPTION_microsoft="Microsoft Visual Studio"
-TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++"
# Minimum supported versions, empty means unspecified
TOOLCHAIN_MINIMUM_VERSION_clang="13.0"
TOOLCHAIN_MINIMUM_VERSION_gcc="10.0"
TOOLCHAIN_MINIMUM_VERSION_microsoft="19.28.0.0" # VS2019 16.8, aka MSVC 14.28
-TOOLCHAIN_MINIMUM_VERSION_xlc="17.1.1.4"
# Minimum supported linker versions, empty means unspecified
TOOLCHAIN_MINIMUM_LD_VERSION_gcc="2.18"
@@ -234,25 +232,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETERMINE_TOOLCHAIN_TYPE],
# First toolchain type in the list is the default
DEFAULT_TOOLCHAIN=${VALID_TOOLCHAINS%% *}
- # On AIX the default toolchain depends on the installed (found) compiler
- # xlclang++ -> xlc toolchain
- # ibm-clang++_r -> clang toolchain
- # The compiler is searched on the PATH and TOOLCHAIN_PATH
- # xlclang++ has precedence over ibm-clang++_r if both are installed
- if test "x$OPENJDK_TARGET_OS" = xaix; then
- DEFAULT_TOOLCHAIN="clang"
- if test "x$TOOLCHAIN_PATH" != x; then
- if test -e ${TOOLCHAIN_PATH}/xlclang++; then
- DEFAULT_TOOLCHAIN="xlc"
- fi
- else
- UTIL_LOOKUP_PROGS(XLCLANG_TEST_PATH, xlclang++)
- if test "x$XLCLANG_TEST_PATH" != x; then
- DEFAULT_TOOLCHAIN="xlc"
- fi
- fi
- fi
-
if test "x$with_toolchain_type" = xlist; then
# List all toolchains
AC_MSG_NOTICE([The following toolchains are valid on this platform:])
@@ -277,48 +256,13 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETERMINE_TOOLCHAIN_TYPE],
fi
AC_SUBST(TOOLCHAIN_TYPE)
- # on AIX, check for xlclang++ on the PATH and TOOLCHAIN_PATH and use it if it is available
- if test "x$OPENJDK_TARGET_OS" = xaix; then
- if test "x$TOOLCHAIN_PATH" != x; then
- XLC_TEST_PATH=${TOOLCHAIN_PATH}/
- fi
- if test "x$TOOLCHAIN_TYPE" = xclang; then
- TOOLCHAIN_DESCRIPTION_clang="IBM Open XL C/C++"
- XLCLANG_VERSION_OUTPUT=`${XLC_TEST_PATH}ibm-clang++_r --version 2>&1 | $HEAD -n 1`
- $ECHO "$XLCLANG_VERSION_OUTPUT" | $GREP "IBM Open XL C/C++ for AIX" > /dev/null
- if test $? -eq 0; then
- AC_MSG_NOTICE([ibm-clang++_r output: $XLCLANG_VERSION_OUTPUT])
- else
- AC_MSG_ERROR([ibm-clang++_r version output check failed, output: $XLCLANG_VERSION_OUTPUT])
- fi
- else
- XLCLANG_VERSION_OUTPUT=`${XLC_TEST_PATH}xlclang++ -qversion 2>&1 | $HEAD -n 1`
- $ECHO "$XLCLANG_VERSION_OUTPUT" | $GREP "IBM XL C/C++ for AIX" > /dev/null
- if test $? -eq 0; then
- AC_MSG_NOTICE([xlclang++ output: $XLCLANG_VERSION_OUTPUT])
- else
- AC_MSG_ERROR([xlclang++ version output check failed, output: $XLCLANG_VERSION_OUTPUT])
- fi
- fi
- fi
-
- if test "x$OPENJDK_TARGET_OS" = xaix; then
- TOOLCHAIN_CC_BINARY_clang="ibm-clang_r"
- else
- TOOLCHAIN_CC_BINARY_clang="clang"
- fi
+ TOOLCHAIN_CC_BINARY_clang="ibm-clang_r clang"
TOOLCHAIN_CC_BINARY_gcc="gcc"
TOOLCHAIN_CC_BINARY_microsoft="cl"
- TOOLCHAIN_CC_BINARY_xlc="xlclang"
- if test "x$OPENJDK_TARGET_OS" = xaix; then
- TOOLCHAIN_CXX_BINARY_clang="ibm-clang++_r"
- else
- TOOLCHAIN_CXX_BINARY_clang="clang++"
- fi
+ TOOLCHAIN_CXX_BINARY_clang="ibm-clang++_r clang++"
TOOLCHAIN_CXX_BINARY_gcc="g++"
TOOLCHAIN_CXX_BINARY_microsoft="cl"
- TOOLCHAIN_CXX_BINARY_xlc="xlclang++"
# Use indirect variable referencing
toolchain_var_name=TOOLCHAIN_DESCRIPTION_$TOOLCHAIN_TYPE
@@ -408,25 +352,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION],
COMPILER=[$]$1
COMPILER_NAME=$2
- if test "x$TOOLCHAIN_TYPE" = xxlc; then
- # xlc -qversion output typically looks like
- # IBM XL C/C++ for AIX, V11.1 (5724-X13)
- # Version: 11.01.0000.0015
- COMPILER_VERSION_OUTPUT=`$COMPILER -qversion 2>&1`
- # Check that this is likely to be the IBM XL C compiler.
- $ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "IBM XL C" > /dev/null
- if test $? -ne 0; then
- ALT_VERSION_OUTPUT=`$COMPILER --version 2>&1`
- AC_MSG_NOTICE([The $COMPILER_NAME compiler (located as $COMPILER) does not seem to be the required $TOOLCHAIN_TYPE compiler.])
- AC_MSG_NOTICE([The result from running with -qversion was: "$COMPILER_VERSION_OUTPUT"])
- AC_MSG_NOTICE([The result from running with --version was: "$ALT_VERSION_OUTPUT"])
- AC_MSG_ERROR([A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir.])
- fi
- # Collapse compiler output into a single line
- COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT`
- COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \
- $SED -e 's/^.*Version: \(@<:@1-9@:>@@<:@0-9.@:>@*\).*$/\1/'`
- elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
+ if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
# There is no specific version flag, but all output starts with a version string.
# First line typically looks something like:
# Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
@@ -465,12 +391,22 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION],
$SED -e 's/^.* \(@<:@1-9@:>@<:@0-9@:>@*\.@<:@0-9.@:>@*\)@<:@^0-9.@:>@.*$/\1/'`
elif test "x$TOOLCHAIN_TYPE" = xclang; then
# clang --version output typically looks like
- # Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
- # clang version 3.3 (tags/RELEASE_33/final)
+ # Apple clang version 15.0.0 (clang-1500.3.9.4)
+ # Target: arm64-apple-darwin23.2.0
+ # Thread model: posix
+ # InstalledDir: /Library/Developer/CommandLineTools/usr/bin
# or
- # Debian clang version 3.2-7ubuntu1 (tags/RELEASE_32/final) (based on LLVM 3.2)
+ # clang version 10.0.0-4ubuntu1
# Target: x86_64-pc-linux-gnu
# Thread model: posix
+ # InstalledDir: /usr/bin
+ # Target: x86_64-pc-linux-gnu
+ # Thread model: posix
+ # or
+ # IBM Open XL C/C++ for AIX 17.1.0 (5725-C72, 5765-J18), clang version 13.0.0
+ # Target: powerpc-ibm-aix7.2.0.0
+ # Thread model: posix
+ # InstalledDir: /opt/IBM/openxlC/17.1.0/bin
COMPILER_VERSION_OUTPUT=`$COMPILER --version 2>&1`
# Check that this is likely to be clang
$ECHO "$COMPILER_VERSION_OUTPUT" | $GREP "clang" > /dev/null
@@ -479,10 +415,12 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_COMPILER_VERSION],
AC_MSG_NOTICE([The result from running with --version was: "$COMPILER_VERSION_OUTPUT"])
AC_MSG_ERROR([A $TOOLCHAIN_TYPE compiler is required. Try setting --with-tools-dir.])
fi
- # Collapse compiler output into a single line
- COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT`
+ # Remove "Thread model:" and further details from the version string, and
+ # collapse into a single line
+ COMPILER_VERSION_STRING=`$ECHO $COMPILER_VERSION_OUTPUT | \
+ $SED -e 's/ *Thread model: .*//'`
COMPILER_VERSION_NUMBER=`$ECHO $COMPILER_VERSION_OUTPUT | \
- $SED -e 's/^.* version \(@<:@1-9@:>@@<:@0-9.@:>@*\).*$/\1/'`
+ $SED -e 's/^.*clang version \(@<:@1-9@:>@@<:@0-9.@:>@*\).*$/\1/'`
else
AC_MSG_ERROR([Unknown toolchain type $TOOLCHAIN_TYPE.])
fi
@@ -575,10 +513,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_LD_VERSION],
LINKER=[$]$1
LINKER_NAME="$2"
- if test "x$TOOLCHAIN_TYPE" = xxlc; then
- LINKER_VERSION_STRING="Unknown"
- LINKER_VERSION_NUMBER="0.0"
- elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
+ if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
# There is no specific version flag, but all output starts with a version string.
# First line typically looks something like:
# Microsoft (R) Incremental Linker Version 12.00.31101.0
@@ -1000,6 +935,14 @@ AC_DEFUN_ONCE([TOOLCHAIN_MISC_CHECKS],
fi
fi
fi
+ if test "x$OPENJDK_TARGET_OS" = xaix; then
+ # Make sure we have the Open XL version of clang on AIX
+
+ $ECHO "$CC_VERSION_STRING" | $GREP "IBM Open XL C/C++ for AIX" > /dev/null
+ if test $? -ne 0; then
+ AC_MSG_ERROR([ibm-clang_r version output check failed, output: $CC_VERSION_OUTPUT])
+ fi
+ fi
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
# Check if linker has -z noexecstack.
diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk
index 13b0318b4c7..893f4177990 100644
--- a/make/common/NativeCompilation.gmk
+++ b/make/common/NativeCompilation.gmk
@@ -303,36 +303,36 @@ endef
# Setup the toolchain variables
define SetupToolchain
ifeq ($$($1_TARGET_TYPE), BUILD)
- $$(call SetIfEmpty, $1_CC, $(BUILD_CC))
- $$(call SetIfEmpty, $1_CXX, $(BUILD_CXX))
- $$(call SetIfEmpty, $1_AR, $(BUILD_AR))
- $$(call SetIfEmpty, $1_LIB, $(BUILD_LIB))
- $$(call SetIfEmpty, $1_AS, $(BUILD_AS))
- $$(call SetIfEmpty, $1_OBJCOPY, $(BUILD_OBJCOPY))
- $$(call SetIfEmpty, $1_STRIP, $(BUILD_STRIP))
- $$(call SetIfEmpty, $1_SYSROOT_CFLAGS, $(BUILD_SYSROOT_CFLAGS))
- $$(call SetIfEmpty, $1_SYSROOT_LDFLAGS, $(BUILD_SYSROOT_LDFLAGS))
+ $$(call SetIfEmpty, $1_CC, $$(BUILD_CC))
+ $$(call SetIfEmpty, $1_CXX, $$(BUILD_CXX))
+ $$(call SetIfEmpty, $1_AR, $$(BUILD_AR))
+ $$(call SetIfEmpty, $1_LIB, $$(BUILD_LIB))
+ $$(call SetIfEmpty, $1_AS, $$(BUILD_AS))
+ $$(call SetIfEmpty, $1_OBJCOPY, $$(BUILD_OBJCOPY))
+ $$(call SetIfEmpty, $1_STRIP, $$(BUILD_STRIP))
+ $$(call SetIfEmpty, $1_SYSROOT_CFLAGS, $$(BUILD_SYSROOT_CFLAGS))
+ $$(call SetIfEmpty, $1_SYSROOT_LDFLAGS, $$(BUILD_SYSROOT_LDFLAGS))
ifeq ($$($1_LINK_TYPE), C++)
- $$(call SetIfEmpty, $1_LD, $(BUILD_LDCXX))
+ $$(call SetIfEmpty, $1_LD, $$(BUILD_LDCXX))
else
- $$(call SetIfEmpty, $1_LD, $(BUILD_LD))
+ $$(call SetIfEmpty, $1_LD, $$(BUILD_LD))
endif
else
- $$(call SetIfEmpty, $1_CC, $(CC))
- $$(call SetIfEmpty, $1_CXX, $(CXX))
- $$(call SetIfEmpty, $1_AR, $(AR))
- $$(call SetIfEmpty, $1_LIB, $(LIB))
- $$(call SetIfEmpty, $1_AS, $(AS))
- $$(call SetIfEmpty, $1_MT, $(MT))
- $$(call SetIfEmpty, $1_RC, $(RC))
- $$(call SetIfEmpty, $1_OBJCOPY, $(OBJCOPY))
- $$(call SetIfEmpty, $1_STRIP, $(STRIP))
- $$(call SetIfEmpty, $1_SYSROOT_CFLAGS, $(SYSROOT_CFLAGS))
- $$(call SetIfEmpty, $1_SYSROOT_LDFLAGS, $(SYSROOT_LDFLAGS))
+ $$(call SetIfEmpty, $1_CC, $$(CC))
+ $$(call SetIfEmpty, $1_CXX, $$(CXX))
+ $$(call SetIfEmpty, $1_AR, $$(AR))
+ $$(call SetIfEmpty, $1_LIB, $$(LIB))
+ $$(call SetIfEmpty, $1_AS, $$(AS))
+ $$(call SetIfEmpty, $1_MT, $$(MT))
+ $$(call SetIfEmpty, $1_RC, $$(RC))
+ $$(call SetIfEmpty, $1_OBJCOPY, $$(OBJCOPY))
+ $$(call SetIfEmpty, $1_STRIP, $$(STRIP))
+ $$(call SetIfEmpty, $1_SYSROOT_CFLAGS, $$(SYSROOT_CFLAGS))
+ $$(call SetIfEmpty, $1_SYSROOT_LDFLAGS, $$(SYSROOT_LDFLAGS))
ifeq ($$($1_LINK_TYPE), C++)
- $$(call SetIfEmpty, $1_LD, $(LDCXX))
+ $$(call SetIfEmpty, $1_LD, $$(LDCXX))
else
- $$(call SetIfEmpty, $1_LD, $(LD))
+ $$(call SetIfEmpty, $1_LD, $$(LD))
endif
endif
endef
diff --git a/make/common/TestFilesCompilation.gmk b/make/common/TestFilesCompilation.gmk
index 626eb058f0a..85e01b0a521 100644
--- a/make/common/TestFilesCompilation.gmk
+++ b/make/common/TestFilesCompilation.gmk
@@ -56,22 +56,34 @@ define SetupTestFilesCompilationBody
$$(error There are duplicate test file names for $1: $$($1_DUPLICATED_NAMES))
endif
+ # Always include common test functionality
+ TEST_CFLAGS := -I$(TOPDIR)/test/lib/native
+
+ ifeq ($(TOOLCHAIN_TYPE), gcc)
+ TEST_CFLAGS += -fvisibility=hidden
+ TEST_LDFLAGS += -Wl,--exclude-libs,ALL
+ else ifeq ($(TOOLCHAIN_TYPE), clang)
+ TEST_CFLAGS += -fvisibility=hidden
+ else ifeq ($(TOOLCHAIN_TYPE), xlc)
+ TEST_CFLAGS += -qvisibility=hidden
+ endif
+
# The list to depend on starts out empty
$1 :=
ifeq ($$($1_TYPE), LIBRARY)
$1_PREFIX = lib
$1_OUTPUT_SUBDIR := lib
- $1_BASE_CFLAGS := $(CFLAGS_JDKLIB)
- $1_BASE_CXXFLAGS := $(CXXFLAGS_JDKLIB)
- $1_LDFLAGS := $(LDFLAGS_JDKLIB) $$(call SET_SHARED_LIBRARY_ORIGIN)
+ $1_BASE_CFLAGS := $(CFLAGS_JDKLIB) $$(TEST_CFLAGS)
+ $1_BASE_CXXFLAGS := $(CXXFLAGS_JDKLIB) $$(TEST_CFLAGS)
+ $1_LDFLAGS := $(LDFLAGS_JDKLIB) $$(TEST_LDFLAGS) $$(call SET_SHARED_LIBRARY_ORIGIN)
$1_COMPILATION_TYPE := LIBRARY
$1_LOG_TYPE := library
else ifeq ($$($1_TYPE), PROGRAM)
$1_PREFIX = exe
$1_OUTPUT_SUBDIR := bin
- $1_BASE_CFLAGS := $(CFLAGS_JDKEXE)
- $1_BASE_CXXFLAGS := $(CXXFLAGS_JDKEXE)
- $1_LDFLAGS := $(LDFLAGS_JDKEXE) $(LDFLAGS_TESTEXE)
+ $1_BASE_CFLAGS := $(CFLAGS_JDKEXE) $$(TEST_CFLAGS)
+ $1_BASE_CXXFLAGS := $(CXXFLAGS_JDKEXE) $$(TEST_CFLAGS)
+ $1_LDFLAGS := $(LDFLAGS_JDKEXE) $$(TEST_LDFLAGS) $(LDFLAGS_TESTEXE)
$1_COMPILATION_TYPE := EXECUTABLE
$1_LOG_TYPE := executable
else
diff --git a/make/common/modules/LauncherCommon.gmk b/make/common/modules/LauncherCommon.gmk
index 8041e9fe681..95d8474f045 100644
--- a/make/common/modules/LauncherCommon.gmk
+++ b/make/common/modules/LauncherCommon.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2024, 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,8 +39,6 @@ ifeq ($(TOOLCHAIN_TYPE), gcc)
LDFLAGS_JDKEXE += -Wl,--exclude-libs,ALL
else ifeq ($(TOOLCHAIN_TYPE), clang)
LAUNCHER_CFLAGS += -fvisibility=hidden
-else ifeq ($(TOOLCHAIN_TYPE), xlc)
- LAUNCHER_CFLAGS += -qvisibility=hidden
endif
LAUNCHER_SRC := $(TOPDIR)/src/java.base/share/native/launcher
diff --git a/make/common/modules/LibCommon.gmk b/make/common/modules/LibCommon.gmk
index 2450d2d1e03..67d0ff1435f 100644
--- a/make/common/modules/LibCommon.gmk
+++ b/make/common/modules/LibCommon.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -44,9 +44,6 @@ ifeq ($(TOOLCHAIN_TYPE), gcc)
else ifeq ($(TOOLCHAIN_TYPE), clang)
CFLAGS_JDKLIB += -fvisibility=hidden
CXXFLAGS_JDKLIB += -fvisibility=hidden
-else ifeq ($(TOOLCHAIN_TYPE), xlc)
- CFLAGS_JDKLIB += -qvisibility=hidden
- CXXFLAGS_JDKLIB += -qvisibility=hidden
endif
# Put the libraries here.
diff --git a/make/common/native/Link.gmk b/make/common/native/Link.gmk
index fb23152d4fb..3390eb3c899 100644
--- a/make/common/native/Link.gmk
+++ b/make/common/native/Link.gmk
@@ -133,11 +133,6 @@ define CreateDynamicLibraryOrExecutable
ifeq ($$($1_TYPE), LIBRARY)
# Generating a dynamic library.
$1_EXTRA_LDFLAGS += $$(call SET_SHARED_LIBRARY_NAME,$$($1_BASENAME))
-
- # Create loadmap on AIX. Helps in diagnosing some problems.
- ifneq ($(COMPILER_BINDCMD_FILE_FLAG), )
- $1_EXTRA_LDFLAGS += $(COMPILER_BINDCMD_FILE_FLAG)$$($1_OBJECT_DIR)/$$($1_NOSUFFIX).loadmap
- endif
endif
$1_VARDEPS := $$($1_LD) $$($1_SYSROOT_LDFLAGS) $$($1_LDFLAGS) \
diff --git a/make/common/native/Paths.gmk b/make/common/native/Paths.gmk
index 67aa61d86e9..e021a390289 100644
--- a/make/common/native/Paths.gmk
+++ b/make/common/native/Paths.gmk
@@ -209,12 +209,7 @@ define SetupObjectFileList
# If there are many object files, use an @-file...
ifneq ($$(word 17, $$($1_ALL_OBJS)), )
$1_OBJ_FILE_LIST := $$($1_OBJECT_DIR)/_$1_objectfilenames.txt
- ifneq ($(COMPILER_COMMAND_FILE_FLAG), )
- $1_LD_OBJ_ARG := $(COMPILER_COMMAND_FILE_FLAG)$$($1_OBJ_FILE_LIST)
- else
- # ...except for toolchains which don't support them.
- $1_LD_OBJ_ARG := `cat $$($1_OBJ_FILE_LIST)`
- endif
+ $1_LD_OBJ_ARG := @$$($1_OBJ_FILE_LIST)
# If we are building static library, 'AR' on macosx/aix may not support @-file.
ifeq ($$($1_TYPE), STATIC_LIBRARY)
diff --git a/make/conf/module-loader-map.conf b/make/conf/module-loader-map.conf
index ca09d23b02b..5b72bf78aa0 100644
--- a/make/conf/module-loader-map.conf
+++ b/make/conf/module-loader-map.conf
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2024, 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
@@ -91,3 +91,50 @@ PLATFORM_MODULES= \
PLATFORM_MODULES_windows= \
jdk.crypto.mscapi \
#
+
+NATIVE_ACCESS_MODULES= \
+ java.base \
+ java.datatransfer \
+ java.desktop \
+ java.instrument \
+ java.logging \
+ java.management \
+ java.management.rmi \
+ java.naming \
+ java.net.http \
+ java.prefs \
+ java.rmi \
+ java.scripting \
+ java.se \
+ java.security.jgss \
+ java.security.sasl \
+ java.smartcardio \
+ java.sql \
+ java.sql.rowset \
+ java.transaction.xa \
+ java.xml \
+ java.xml.crypto \
+ jdk.accessibility \
+ jdk.charsets \
+ jdk.crypto.cryptoki \
+ jdk.dynalink \
+ jdk.httpserver \
+ jdk.incubator.vector \
+ jdk.internal.vm.ci \
+ jdk.jfr \
+ jdk.jsobject \
+ jdk.localedata \
+ jdk.management \
+ jdk.management.agent \
+ jdk.management.jfr \
+ jdk.naming.dns \
+ jdk.naming.rmi \
+ jdk.net \
+ jdk.nio.mapmode \
+ jdk.sctp \
+ jdk.security.auth \
+ jdk.security.jgss \
+ jdk.unsupported \
+ jdk.xml.dom \
+ jdk.zipfs \
+ #
diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk
index 69cd80f5171..859e75cfc9f 100644
--- a/make/hotspot/lib/CompileJvm.gmk
+++ b/make/hotspot/lib/CompileJvm.gmk
@@ -73,7 +73,6 @@ CFLAGS_VM_VERSION := \
$(VERSION_CFLAGS) \
-DHOTSPOT_VERSION_STRING='"$(VERSION_STRING)"' \
-DDEBUG_LEVEL='"$(DEBUG_LEVEL)"' \
- -DHOTSPOT_BUILD_USER='"$(USERNAME)"' \
-DHOTSPOT_VM_DISTRO='"$(HOTSPOT_VM_DISTRO)"' \
-DCPU='"$(OPENJDK_TARGET_CPU_VM_VERSION)"' \
-DHOTSPOT_BUILD_TIME='"$(HOTSPOT_BUILD_TIME)"' \
@@ -97,8 +96,6 @@ ifneq ($(DEBUG_LEVEL), release)
DISABLED_WARNINGS_gcc += strict-overflow
endif
-DISABLED_WARNINGS_xlc := tautological-compare shift-negative-value
-
DISABLED_WARNINGS_microsoft := 4624 4244 4291 4146 4127 4722
################################################################################
@@ -203,7 +200,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \
DISABLED_WARNINGS_clang_aix_debug.cpp := format-nonliteral, \
DISABLED_WARNINGS_clang_aix_jvm.cpp := format-nonliteral, \
DISABLED_WARNINGS_clang_aix_osThread_aix.cpp := tautological-undefined-compare, \
- DISABLED_WARNINGS_xlc := $(DISABLED_WARNINGS_xlc), \
DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft), \
ASFLAGS := $(JVM_ASFLAGS), \
LDFLAGS := $(JVM_LDFLAGS), \
diff --git a/make/ide/eclipse/CreateWorkspace.gmk b/make/ide/eclipse/CreateWorkspace.gmk
index a7937a33d9e..2362c0f7e71 100644
--- a/make/ide/eclipse/CreateWorkspace.gmk
+++ b/make/ide/eclipse/CreateWorkspace.gmk
@@ -280,7 +280,6 @@ define SetupEclipseWorkspaceBody
\
\
\
- \
\
\
\
@@ -288,7 +287,6 @@ define SetupEclipseWorkspaceBody
\
\
\
- \
\
\
\
diff --git a/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/BuildConfig.java b/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/BuildConfig.java
index 7d733bde909..4dd3c898b61 100644
--- a/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/BuildConfig.java
+++ b/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/BuildConfig.java
@@ -221,7 +221,6 @@ void initDefaultDefines(Vector defines) {
Vector sysDefines = new Vector();
sysDefines.add("WIN32");
sysDefines.add("_WINDOWS");
- sysDefines.add("HOTSPOT_BUILD_USER=\\\""+System.getProperty("user.name")+"\\\"");
sysDefines.add("HOTSPOT_BUILD_TARGET=\\\""+get("Build")+"\\\"");
sysDefines.add("INCLUDE_JFR=1");
sysDefines.add("_JNI_IMPLEMENTATION_");
diff --git a/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/ProjectCreator.java b/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/ProjectCreator.java
index d5478230a42..a61afa8461a 100644
--- a/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/ProjectCreator.java
+++ b/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/ProjectCreator.java
@@ -78,7 +78,7 @@ public static void usage() {
System.err.println(" are both quoted strings.");
System.err.println(" Default includes: \".\"");
System.err
- .println(" Default defines: WIN32, _WINDOWS, \"HOTSPOT_BUILD_USER=$(USERNAME)\"");
+ .println(" Default defines: WIN32, _WINDOWS");
}
public static void main(String[] args) {
diff --git a/make/jdk/src/classes/build/tools/module/GenModuleLoaderMap.java b/make/jdk/src/classes/build/tools/module/GenModuleLoaderMap.java
index c6c90e0fb59..aea74cc1dc0 100644
--- a/make/jdk/src/classes/build/tools/module/GenModuleLoaderMap.java
+++ b/make/jdk/src/classes/build/tools/module/GenModuleLoaderMap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024, 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
@@ -48,6 +48,7 @@ public static void main(String... args) throws Exception {
// default set of boot modules and ext modules
Stream bootModules = Stream.empty();
Stream platformModules = Stream.empty();
+ Stream nativeAccessModules = Stream.empty();
Path outfile = null;
Path source = null;
for (int i=0; i < args.length; i++) {
@@ -60,6 +61,9 @@ public static void main(String... args) throws Exception {
} else if (option.equals("-platform")) {
String[] mns = arg.split(",");
platformModules = Stream.concat(platformModules, Arrays.stream(mns));
+ } else if (option.equals("-native-access")) {
+ String[] mns = arg.split(",");
+ nativeAccessModules = Stream.concat(nativeAccessModules, Arrays.stream(mns));
} else if (option.equals("-o")) {
outfile = Paths.get(arg);
} else {
@@ -84,6 +88,8 @@ public static void main(String... args) throws Exception {
line = patch(line, "@@BOOT_MODULE_NAMES@@", bootModules);
} else if (line.contains("@@PLATFORM_MODULE_NAMES@@")) {
line = patch(line, "@@PLATFORM_MODULE_NAMES@@", platformModules);
+ } else if (line.contains("@@NATIVE_ACCESS_MODULE_NAMES@@")) {
+ line = patch(line, "@@NATIVE_ACCESS_MODULE_NAMES@@", nativeAccessModules);
}
writer.println(line);
}
diff --git a/make/modules/java.base/Launcher.gmk b/make/modules/java.base/Launcher.gmk
index 11af61b082e..a559322f9d3 100644
--- a/make/modules/java.base/Launcher.gmk
+++ b/make/modules/java.base/Launcher.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2024, 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
@@ -73,7 +73,7 @@ endif
################################################################################
-ifeq ($(call isTargetOs, macosx aix linux), true)
+ifeq ($(call isTargetOsType, unix), true)
$(eval $(call SetupJdkExecutable, BUILD_JSPAWNHELPER, \
NAME := jspawnhelper, \
SRC := $(TOPDIR)/src/$(MODULE)/unix/native/jspawnhelper, \
diff --git a/make/modules/java.base/Lib.gmk b/make/modules/java.base/Lib.gmk
index 54050d07986..53fe95a1b0c 100644
--- a/make/modules/java.base/Lib.gmk
+++ b/make/modules/java.base/Lib.gmk
@@ -72,7 +72,6 @@ TARGETS += $(BUILD_LIBNET)
$(eval $(call SetupJdkLibrary, BUILD_LIBNIO, \
NAME := nio, \
OPTIMIZATION := HIGH, \
- WARNINGS_AS_ERRORS_xlc := false, \
CFLAGS := $(CFLAGS_JDKLIB), \
EXTRA_HEADER_DIRS := \
libnio/ch \
diff --git a/make/modules/java.base/gensrc/GensrcModuleLoaderMap.gmk b/make/modules/java.base/gensrc/GensrcModuleLoaderMap.gmk
index e248e680d46..4ec9ee587cc 100644
--- a/make/modules/java.base/gensrc/GensrcModuleLoaderMap.gmk
+++ b/make/modules/java.base/gensrc/GensrcModuleLoaderMap.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -37,8 +37,9 @@ $(strip \
endef
BOOT_MODULES_LIST := $(call SubstComma, $(BOOT_MODULES))
PLATFORM_MODULES_LIST := $(call SubstComma, $(PLATFORM_MODULES))
+NATIVE_ACCESS_MODULES_LIST := $(call SubstComma, $(NATIVE_ACCESS_MODULES))
-VARDEPS_VALUE := $(BOOT_MODULES_LIST) $(PLATFORM_MODULES_LIST)
+VARDEPS_VALUE := $(BOOT_MODULES_LIST) $(PLATFORM_MODULES_LIST) $(NATIVE_ACCESS_MODULES_LIST)
VARDEPS_FILE := $(call DependOnVariable, VARDEPS_VALUE)
############################################################################
@@ -49,7 +50,9 @@ $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/module/ModuleLoaderMap.java:
$(call MakeTargetDir)
$(RM) $@ $@.tmp
$(TOOL_GENCLASSLOADERMAP) -boot $(BOOT_MODULES_LIST) \
- -platform $(PLATFORM_MODULES_LIST) -o $@.tmp $<
+ -platform $(PLATFORM_MODULES_LIST) \
+ -native-access $(NATIVE_ACCESS_MODULES_LIST) \
+ -o $@.tmp $<
$(MV) $@.tmp $@
TARGETS += $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/module/ModuleLoaderMap.java
diff --git a/make/modules/java.base/lib/CoreLibraries.gmk b/make/modules/java.base/lib/CoreLibraries.gmk
index b27013536f8..48d56895297 100644
--- a/make/modules/java.base/lib/CoreLibraries.gmk
+++ b/make/modules/java.base/lib/CoreLibraries.gmk
@@ -59,7 +59,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJAVA, \
CFLAGS := $(CFLAGS_JDKLIB) \
$(LIBJAVA_CFLAGS), \
jdk_util.c_CFLAGS := $(VERSION_CFLAGS), \
- WARNINGS_AS_ERRORS_xlc := false, \
DISABLED_WARNINGS_gcc_ProcessImpl_md.c := unused-result, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk
index aaf98d088fd..048292e385b 100644
--- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk
+++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk
@@ -238,7 +238,6 @@ ifeq ($(call isTargetOs, windows macosx), false)
OPTIMIZATION := LOW, \
CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_XAWT_CFLAGS) \
$(X_CFLAGS), \
- WARNINGS_AS_ERRORS_xlc := false, \
DISABLED_WARNINGS_gcc := int-to-pointer-cast, \
DISABLED_WARNINGS_gcc_awt_Taskbar.c := parentheses, \
DISABLED_WARNINGS_gcc_GLXSurfaceData.c := unused-function, \
@@ -482,14 +481,6 @@ else
HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES -DHB_NO_VISIBILITY
endif
- # Early re-canonizing has to be disabled to workaround an internal XlC compiler error
- # when building libharfbuzz
- ifeq ($(call isTargetOs, aix), true)
- ifneq ($(TOOLCHAIN_TYPE), clang)
- HARFBUZZ_CFLAGS += -qdebug=necan
- endif
- endif
-
# hb-ft.cc is not presently needed, and requires freetype 2.4.2 or later.
# hb-subset and hb-style APIs are not needed, excluded to cut on compilation time.
LIBFONTMANAGER_EXCLUDE_FILES += hb-ft.cc hb-subset-cff-common.cc \
@@ -571,7 +562,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBFONTMANAGER, \
CFLAGS_windows = -DCC_NOEX, \
EXTRA_HEADER_DIRS := $(LIBFONTMANAGER_EXTRA_HEADER_DIRS), \
EXTRA_SRC := $(LIBFONTMANAGER_EXTRA_SRC), \
- WARNINGS_AS_ERRORS_xlc := false, \
DISABLED_WARNINGS_gcc := $(HARFBUZZ_DISABLED_WARNINGS_gcc), \
DISABLED_WARNINGS_CXX_gcc := $(HARFBUZZ_DISABLED_WARNINGS_CXX_gcc), \
DISABLED_WARNINGS_clang := $(HARFBUZZ_DISABLED_WARNINGS_clang), \
diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk
index 5f945e90dd2..e21280e8a5d 100644
--- a/make/test/JtregNativeJdk.gmk
+++ b/make/test/JtregNativeJdk.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2015, 2024, 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
@@ -53,8 +53,6 @@ BUILD_JDK_JTREG_EXECUTABLES_CFLAGS_exeJliLaunchTest := \
-I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjli \
-I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libjli
-TEST_LIB_NATIVE_SRC := $(TOPDIR)/test/lib/native
-
# Platform specific setup
ifeq ($(call isTargetOs, windows), true)
BUILD_JDK_JTREG_EXCLUDE += libDirectIO.c libInheritedChannel.c \
@@ -69,14 +67,6 @@ ifeq ($(call isTargetOs, windows), true)
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerTest := $(LIBCXX) jvm.lib
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib
BUILD_JDK_JTREG_EXECUTABLES_CFLAGS_exeNullCallerTest := /EHsc
-
- # java.lang.foreign tests
- BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncStackWalk := -I$(TEST_LIB_NATIVE_SRC)
- BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libLinkerInvokerUnnamed := -I$(TEST_LIB_NATIVE_SRC)
- BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libLinkerInvokerModule := -I$(TEST_LIB_NATIVE_SRC)
- BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libLoaderLookupInvoker := -I$(TEST_LIB_NATIVE_SRC)
- BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncInvokers := -I$(TEST_LIB_NATIVE_SRC)
-
BUILD_JDK_JTREG_LIBRARIES_LIBS_libTracePinnedThreads := jvm.lib
BUILD_JDK_JTREG_LIBRARIES_LIBS_libNewDirectByteBuffer := $(WIN_LIB_JAVA)
BUILD_JDK_JTREG_LIBRARIES_LIBS_libGetXSpace := $(WIN_LIB_JAVA)
@@ -88,15 +78,10 @@ else
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libNativeThread := -pthread
# java.lang.foreign tests
- BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncStackWalk := -I$(TEST_LIB_NATIVE_SRC)
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncStackWalk := -pthread
- BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncInvokers := -I$(TEST_LIB_NATIVE_SRC)
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncInvokers := -pthread
- BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libLinkerInvokerUnnamed := -I$(TEST_LIB_NATIVE_SRC)
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLinkerInvokerUnnamed := -pthread
- BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libLinkerInvokerModule := -I$(TEST_LIB_NATIVE_SRC)
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLinkerInvokerModule := -pthread
- BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libLoaderLookupInvoker := -I$(TEST_LIB_NATIVE_SRC)
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLoaderLookupInvoker := -pthread
BUILD_JDK_JTREG_LIBRARIES_LIBS_libExplicitAttach := -ljvm
diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad
index ed38964271f..2f95e80f62c 100644
--- a/src/hotspot/cpu/aarch64/aarch64.ad
+++ b/src/hotspot/cpu/aarch64/aarch64.ad
@@ -16076,33 +16076,33 @@ instruct cmpFastUnlock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRe
ins_pipe(pipe_serial);
%}
-instruct cmpFastLockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRegPNoSp tmp2)
+instruct cmpFastLockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRegPNoSp tmp2, iRegPNoSp tmp3)
%{
predicate(LockingMode == LM_LIGHTWEIGHT);
match(Set cr (FastLock object box));
- effect(TEMP tmp, TEMP tmp2);
+ effect(TEMP tmp, TEMP tmp2, TEMP tmp3);
ins_cost(5 * INSN_COST);
- format %{ "fastlock $object,$box\t! kills $tmp,$tmp2" %}
+ format %{ "fastlock $object,$box\t! kills $tmp,$tmp2,$tmp3" %}
ins_encode %{
- __ fast_lock_lightweight($object$$Register, $box$$Register, $tmp$$Register, $tmp2$$Register);
+ __ fast_lock_lightweight($object$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register);
%}
ins_pipe(pipe_serial);
%}
-instruct cmpFastUnlockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRegPNoSp tmp2)
+instruct cmpFastUnlockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp, iRegPNoSp tmp2, iRegPNoSp tmp3)
%{
predicate(LockingMode == LM_LIGHTWEIGHT);
match(Set cr (FastUnlock object box));
- effect(TEMP tmp, TEMP tmp2);
+ effect(TEMP tmp, TEMP tmp2, TEMP tmp3);
ins_cost(5 * INSN_COST);
- format %{ "fastunlock $object,$box\t! kills $tmp, $tmp2" %}
+ format %{ "fastunlock $object,$box\t! kills $tmp, $tmp2, $tmp3" %}
ins_encode %{
- __ fast_unlock_lightweight($object$$Register, $box$$Register, $tmp$$Register, $tmp2$$Register);
+ __ fast_unlock_lightweight($object$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register);
%}
ins_pipe(pipe_serial);
diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp
index d210c21d12b..3a4c868744c 100644
--- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp
@@ -94,12 +94,12 @@ using MacroAssembler::null_check;
};
// allocation of arrays
- // obj : will contain pointer to allocated object
- // len : array length in number of elements
- // t : scratch register - contents destroyed
- // header_size: size of object header in words
- // f : element scale factor
- // slow_case : exit to slow case implementation if fast allocation fails
+ // obj : will contain pointer to allocated object
+ // len : array length in number of elements
+ // t : scratch register - contents destroyed
+ // base_offset_in_bytes: offset of first array element, in bytes
+ // f : element scale factor
+ // slow_case : exit to slow case implementation if fast allocation fails
void allocate_array(Register obj, Register len, Register t, Register t2, int base_offset_in_bytes, int f, Register klass, Label& slow_case);
int rsp_offset() const { return _rsp_offset; }
diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp
index 38804ff2ed6..bc8c9f1cd7f 100644
--- a/src/hotspot/cpu/riscv/assembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp
@@ -1191,7 +1191,7 @@ static Assembler::SEW elemtype_to_sew(BasicType etype) {
void NAME(Register Rd, uint32_t imm, SEW sew, LMUL lmul = m1, \
VMA vma = mu, VTA vta = tu, bool vill = false) { \
unsigned insn = 0; \
- guarantee(is_uimm5(imm), "imm is invalid"); \
+ guarantee(is_uimm5(imm), "uimm is invalid"); \
patch((address)&insn, 6, 0, op); \
patch((address)&insn, 14, 12, funct3); \
patch((address)&insn, 19, 15, imm); \
@@ -1327,7 +1327,7 @@ enum VectorMask {
// r_vm
#define INSN(NAME, op, funct3, funct6) \
void NAME(VectorRegister Vd, VectorRegister Vs2, uint32_t imm, VectorMask vm = unmasked) { \
- guarantee(is_uimm5(imm), "imm is invalid"); \
+ guarantee(is_uimm5(imm), "uimm is invalid"); \
patch_VArith(op, Vd, funct3, (uint32_t)(imm & 0x1f), Vs2, vm, funct6); \
}
@@ -1340,6 +1340,9 @@ enum VectorMask {
INSN(vslideup_vi, 0b1010111, 0b011, 0b001110);
INSN(vslidedown_vi, 0b1010111, 0b011, 0b001111);
+ // Vector Narrowing Integer Right Shift Instructions
+ INSN(vnsra_wi, 0b1010111, 0b011, 0b101101);
+
#undef INSN
#define INSN(NAME, op, funct3, funct6) \
@@ -1505,6 +1508,9 @@ enum VectorMask {
INSN(vmulh_vx, 0b1010111, 0b110, 0b100111);
INSN(vmul_vx, 0b1010111, 0b110, 0b100101);
+ // Vector Widening Integer Add/Subtract
+ INSN(vwadd_vx, 0b1010111, 0b110, 0b110001);
+
// Vector Integer Min/Max Instructions
INSN(vmax_vx, 0b1010111, 0b100, 0b000111);
INSN(vmaxu_vx, 0b1010111, 0b100, 0b000110);
@@ -1538,6 +1544,8 @@ enum VectorMask {
// Vector Single-Width Integer Add and Subtract
INSN(vsub_vx, 0b1010111, 0b100, 0b000010);
INSN(vadd_vx, 0b1010111, 0b100, 0b000000);
+
+ // Vector Integer reverse subtract
INSN(vrsub_vx, 0b1010111, 0b100, 0b000011);
// Vector Slide Instructions
@@ -1600,16 +1608,23 @@ enum VectorMask {
patch_VArith(op, Vd, funct3, (uint32_t)(imm & 0x1f), Vs2, vm, funct6); \
}
+ // Vector Integer Comparison Instructions
INSN(vmsgt_vi, 0b1010111, 0b011, 0b011111);
INSN(vmsgtu_vi, 0b1010111, 0b011, 0b011110);
INSN(vmsle_vi, 0b1010111, 0b011, 0b011101);
INSN(vmsleu_vi, 0b1010111, 0b011, 0b011100);
INSN(vmsne_vi, 0b1010111, 0b011, 0b011001);
INSN(vmseq_vi, 0b1010111, 0b011, 0b011000);
+
+ // Vector Bitwise Logical Instructions
INSN(vxor_vi, 0b1010111, 0b011, 0b001011);
INSN(vor_vi, 0b1010111, 0b011, 0b001010);
INSN(vand_vi, 0b1010111, 0b011, 0b001001);
+
+ // Vector Single-Width Integer Add and Subtract
INSN(vadd_vi, 0b1010111, 0b011, 0b000000);
+
+ // Vector Integer reverse subtract
INSN(vrsub_vi, 0b1010111, 0b011, 0b000011);
#undef INSN
diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp
index f4c05b9efd6..d523c8a4cda 100644
--- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp
@@ -177,6 +177,12 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register
if (len->is_valid()) {
sw(len, Address(obj, arrayOopDesc::length_offset_in_bytes()));
+ int base_offset = arrayOopDesc::length_offset_in_bytes() + BytesPerInt;
+ if (!is_aligned(base_offset, BytesPerWord)) {
+ assert(is_aligned(base_offset, BytesPerInt), "must be 4-byte aligned");
+ // Clear gap/first 4 bytes following the length field.
+ sw(zr, Address(obj, base_offset));
+ }
} else if (UseCompressedClassPointers) {
store_klass_gap(obj, zr);
}
@@ -296,16 +302,9 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register tmp1
initialize_header(obj, klass, len, tmp1, tmp2);
- // Clear leading 4 bytes, if necessary.
- // TODO: This could perhaps go into initialize_body() and also clear the leading 4 bytes
- // for non-array objects, thereby replacing the klass-gap clearing code in initialize_header().
- int base_offset = base_offset_in_bytes;
- if (!is_aligned(base_offset, BytesPerWord)) {
- assert(is_aligned(base_offset, BytesPerInt), "must be 4-byte aligned");
- sw(zr, Address(obj, base_offset));
- base_offset += BytesPerInt;
- }
- assert(is_aligned(base_offset, BytesPerWord), "must be word-aligned");
+ // Align-up to word boundary, because we clear the 4 bytes potentially
+ // following the length field in initialize_header().
+ int base_offset = align_up(base_offset_in_bytes, BytesPerWord);
// clear rest of allocated space
const Register len_zero = len;
diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp
index 2d7f8d7485d..8fded677430 100644
--- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp
@@ -95,12 +95,12 @@ using MacroAssembler::null_check;
};
// allocation of arrays
- // obj : will contain pointer to allocated object
- // len : array length in number of elements
- // t : temp register - contents destroyed
- // header_size: size of object header in words
- // f : element scale factor
- // slow_case : exit to slow case implementation if fast allocation fails
+ // obj : will contain pointer to allocated object
+ // len : array length in number of elements
+ // t : temp register - contents destroyed
+ // base_offset_in_bytes: offset of first array element, in bytes
+ // f : element scale factor
+ // slow_case : exit to slow case implementation if fast allocation fails
void allocate_array(Register obj, Register len, Register tmp1, Register tmp2, int base_offset_in_bytes, int f, Register klass, Label& slow_case);
int rsp_offset() const { return _rsp_offset; }
diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
index 767d4111e76..18ab55474a6 100644
--- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp
@@ -2064,8 +2064,8 @@ static void float16_to_float_slow_path(C2_MacroAssembler& masm, C2GeneralStub(dst, src, tmp, 20, float16_to_float_slow_path);
- // in riscv, NaN needs a special process as fcvt does not work in that case.
- // in riscv, Inf does not need a special process as fcvt can handle it correctly.
+ // On riscv, NaN needs a special process as fcvt does not work in that case.
+ // On riscv, Inf does not need a special process as fcvt can handle it correctly.
// but we consider to get the slow path to process NaN and Inf at the same time,
// as both of them are rare cases, and if we try to get the slow path to handle
// only NaN case it would sacrifise the performance for normal cases,
@@ -2112,7 +2112,7 @@ static void float_to_float16_slow_path(C2_MacroAssembler& masm, C2GeneralStub(dst, src, xtmp, 130, float_to_float16_slow_path);
- // in riscv, NaN needs a special process as fcvt does not work in that case.
+ // On riscv, NaN needs a special process as fcvt does not work in that case.
// check whether it's a NaN.
// replace fclass with feq as performance optimization.
@@ -2127,6 +2127,117 @@ void C2_MacroAssembler::float_to_float16(Register dst, FloatRegister src, FloatR
bind(stub->continuation());
}
+static void float16_to_float_v_slow_path(C2_MacroAssembler& masm, C2GeneralStub& stub) {
+#define __ masm.
+ VectorRegister dst = stub.data<0>();
+ VectorRegister src = stub.data<1>();
+ uint vector_length = stub.data<2>();
+ __ bind(stub.entry());
+
+ // following instructions mainly focus on NaN, as riscv does not handle
+ // NaN well with vfwcvt_f_f_v, but the code also works for Inf at the same time.
+ //
+ // construct NaN's in 32 bits from the NaN's in 16 bits,
+ // we need the payloads of non-canonical NaNs to be preserved.
+
+ // adjust vector type to 2 * SEW.
+ __ vsetvli_helper(T_FLOAT, vector_length, Assembler::m1);
+ // widen and sign-extend src data.
+ __ vsext_vf2(dst, src, Assembler::v0_t);
+ __ mv(t0, 0x7f800000);
+ // sign-bit was already set via sign-extension if necessary.
+ __ vsll_vi(dst, dst, 13, Assembler::v0_t);
+ __ vor_vx(dst, dst, t0, Assembler::v0_t);
+
+ __ j(stub.continuation());
+#undef __
+}
+
+// j.l.Float.float16ToFloat
+void C2_MacroAssembler::float16_to_float_v(VectorRegister dst, VectorRegister src, uint vector_length) {
+ auto stub = C2CodeStub::make
+ (dst, src, vector_length, 24, float16_to_float_v_slow_path);
+ assert_different_registers(dst, src);
+
+ // On riscv, NaN needs a special process as vfwcvt_f_f_v does not work in that case.
+ // On riscv, Inf does not need a special process as vfwcvt_f_f_v can handle it correctly.
+ // but we consider to get the slow path to process NaN and Inf at the same time,
+ // as both of them are rare cases, and if we try to get the slow path to handle
+ // only NaN case it would sacrifise the performance for normal cases,
+ // i.e. non-NaN and non-Inf cases.
+
+ vsetvli_helper(BasicType::T_SHORT, vector_length, Assembler::mf2);
+
+ // check whether there is a NaN or +/- Inf.
+ mv(t0, 0x7c00);
+ vand_vx(v0, src, t0);
+ // v0 will be used as mask in slow path.
+ vmseq_vx(v0, v0, t0);
+ vcpop_m(t0, v0);
+
+ // For non-NaN or non-Inf cases, just use built-in instructions.
+ vfwcvt_f_f_v(dst, src);
+
+ // jump to stub processing NaN and Inf cases if there is any of them in the vector-wide.
+ bnez(t0, stub->entry());
+
+ bind(stub->continuation());
+}
+
+static void float_to_float16_v_slow_path(C2_MacroAssembler& masm,
+ C2GeneralStub& stub) {
+#define __ masm.
+ VectorRegister dst = stub.data<0>();
+ VectorRegister src = stub.data<1>();
+ VectorRegister tmp = stub.data<2>();
+ __ bind(stub.entry());
+
+ // mul is already set to mf2 in float_to_float16_v.
+
+ // preserve the payloads of non-canonical NaNs.
+ __ vnsra_wi(dst, src, 13, Assembler::v0_t);
+
+ // preserve the sign bit.
+ __ vnsra_wi(tmp, src, 26, Assembler::v0_t);
+ __ vsll_vi(tmp, tmp, 10, Assembler::v0_t);
+ __ mv(t0, 0x3ff);
+ __ vor_vx(tmp, tmp, t0, Assembler::v0_t);
+
+ // get the result by merging sign bit and payloads of preserved non-canonical NaNs.
+ __ vand_vv(dst, dst, tmp, Assembler::v0_t);
+
+ __ j(stub.continuation());
+#undef __
+}
+
+// j.l.Float.float16ToFloat
+void C2_MacroAssembler::float_to_float16_v(VectorRegister dst, VectorRegister src, VectorRegister vtmp,
+ Register tmp, uint vector_length) {
+ assert_different_registers(dst, src, vtmp);
+
+ auto stub = C2CodeStub::make
+ (dst, src, vtmp, 28, float_to_float16_v_slow_path);
+
+ // On riscv, NaN needs a special process as vfncvt_f_f_w does not work in that case.
+
+ vsetvli_helper(BasicType::T_FLOAT, vector_length, Assembler::m1);
+
+ // check whether there is a NaN.
+ // replace v_fclass with vmseq_vv as performance optimization.
+ vmfne_vv(v0, src, src);
+ vcpop_m(t0, v0);
+
+ vsetvli_helper(BasicType::T_SHORT, vector_length, Assembler::mf2, tmp);
+
+ // For non-NaN cases, just use built-in instructions.
+ vfncvt_f_f_w(dst, src);
+
+ // jump to stub processing NaN cases.
+ bnez(t0, stub->entry());
+
+ bind(stub->continuation());
+}
+
void C2_MacroAssembler::signum_fp_v(VectorRegister dst, VectorRegister one, BasicType bt, int vlen) {
vsetvli_helper(bt, vlen);
@@ -2510,7 +2621,7 @@ void C2_MacroAssembler::string_indexof_char_v(Register str1, Register cnt1,
// Set dst to NaN if any NaN input.
void C2_MacroAssembler::minmax_fp_v(VectorRegister dst, VectorRegister src1, VectorRegister src2,
- BasicType bt, bool is_min, int vector_length) {
+ BasicType bt, bool is_min, uint vector_length) {
assert_different_registers(dst, src1, src2);
vsetvli_helper(bt, vector_length);
@@ -2529,7 +2640,7 @@ void C2_MacroAssembler::minmax_fp_v(VectorRegister dst, VectorRegister src1, Vec
// are handled with a mask-undisturbed policy.
void C2_MacroAssembler::minmax_fp_masked_v(VectorRegister dst, VectorRegister src1, VectorRegister src2,
VectorRegister vmask, VectorRegister tmp1, VectorRegister tmp2,
- BasicType bt, bool is_min, int vector_length) {
+ BasicType bt, bool is_min, uint vector_length) {
assert_different_registers(src1, src2, tmp1, tmp2);
vsetvli_helper(bt, vector_length);
@@ -2552,7 +2663,7 @@ void C2_MacroAssembler::minmax_fp_masked_v(VectorRegister dst, VectorRegister sr
void C2_MacroAssembler::reduce_minmax_fp_v(FloatRegister dst,
FloatRegister src1, VectorRegister src2,
VectorRegister tmp1, VectorRegister tmp2,
- bool is_double, bool is_min, int vector_length, VectorMask vm) {
+ bool is_double, bool is_min, uint vector_length, VectorMask vm) {
assert_different_registers(dst, src1);
assert_different_registers(src2, tmp1, tmp2);
@@ -2597,7 +2708,7 @@ bool C2_MacroAssembler::in_scratch_emit_size() {
void C2_MacroAssembler::reduce_integral_v(Register dst, Register src1,
VectorRegister src2, VectorRegister tmp,
- int opc, BasicType bt, int vector_length, VectorMask vm) {
+ int opc, BasicType bt, uint vector_length, VectorMask vm) {
assert(bt == T_BYTE || bt == T_SHORT || bt == T_INT || bt == T_LONG, "unsupported element type");
vsetvli_helper(bt, vector_length);
vmv_s_x(tmp, src1);
@@ -2629,7 +2740,7 @@ void C2_MacroAssembler::reduce_integral_v(Register dst, Register src1,
// Set vl and vtype for full and partial vector operations.
// (vma = mu, vta = tu, vill = false)
-void C2_MacroAssembler::vsetvli_helper(BasicType bt, int vector_length, LMUL vlmul, Register tmp) {
+void C2_MacroAssembler::vsetvli_helper(BasicType bt, uint vector_length, LMUL vlmul, Register tmp) {
Assembler::SEW sew = Assembler::elemtype_to_sew(bt);
if (vector_length <= 31) {
vsetivli(tmp, vector_length, sew, vlmul);
@@ -2642,7 +2753,7 @@ void C2_MacroAssembler::vsetvli_helper(BasicType bt, int vector_length, LMUL vlm
}
void C2_MacroAssembler::compare_integral_v(VectorRegister vd, VectorRegister src1, VectorRegister src2,
- int cond, BasicType bt, int vector_length, VectorMask vm) {
+ int cond, BasicType bt, uint vector_length, VectorMask vm) {
assert(is_integral_type(bt), "unsupported element type");
assert(vm == Assembler::v0_t ? vd != v0 : true, "should be different registers");
vsetvli_helper(bt, vector_length);
@@ -2661,7 +2772,7 @@ void C2_MacroAssembler::compare_integral_v(VectorRegister vd, VectorRegister src
}
void C2_MacroAssembler::compare_fp_v(VectorRegister vd, VectorRegister src1, VectorRegister src2,
- int cond, BasicType bt, int vector_length, VectorMask vm) {
+ int cond, BasicType bt, uint vector_length, VectorMask vm) {
assert(is_floating_point_type(bt), "unsupported element type");
assert(vm == Assembler::v0_t ? vd != v0 : true, "should be different registers");
vsetvli_helper(bt, vector_length);
@@ -2679,7 +2790,7 @@ void C2_MacroAssembler::compare_fp_v(VectorRegister vd, VectorRegister src1, Vec
}
}
-void C2_MacroAssembler::integer_extend_v(VectorRegister dst, BasicType dst_bt, int vector_length,
+void C2_MacroAssembler::integer_extend_v(VectorRegister dst, BasicType dst_bt, uint vector_length,
VectorRegister src, BasicType src_bt) {
assert(type2aelembytes(dst_bt) > type2aelembytes(src_bt) && type2aelembytes(dst_bt) <= 8 && type2aelembytes(src_bt) <= 4, "invalid element size");
assert(dst_bt != T_FLOAT && dst_bt != T_DOUBLE && src_bt != T_FLOAT && src_bt != T_DOUBLE, "unsupported element type");
@@ -2717,7 +2828,7 @@ void C2_MacroAssembler::integer_extend_v(VectorRegister dst, BasicType dst_bt, i
// Vector narrow from src to dst with specified element sizes.
// High part of dst vector will be filled with zero.
-void C2_MacroAssembler::integer_narrow_v(VectorRegister dst, BasicType dst_bt, int vector_length,
+void C2_MacroAssembler::integer_narrow_v(VectorRegister dst, BasicType dst_bt, uint vector_length,
VectorRegister src, BasicType src_bt) {
assert(type2aelembytes(dst_bt) < type2aelembytes(src_bt) && type2aelembytes(dst_bt) <= 4 && type2aelembytes(src_bt) <= 8, "invalid element size");
assert(dst_bt != T_FLOAT && dst_bt != T_DOUBLE && src_bt != T_FLOAT && src_bt != T_DOUBLE, "unsupported element type");
diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
index 25ba66387f1..e1eb23d7c68 100644
--- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp
@@ -156,9 +156,9 @@
vl1r_v(v, t0);
}
- void spill_copy_vector_stack_to_stack(int src_offset, int dst_offset, int vector_length_in_bytes) {
+ void spill_copy_vector_stack_to_stack(int src_offset, int dst_offset, uint vector_length_in_bytes) {
assert(vector_length_in_bytes % 16 == 0, "unexpected vector reg size");
- for (int i = 0; i < vector_length_in_bytes / 8; i++) {
+ for (int i = 0; i < (int)vector_length_in_bytes / 8; i++) {
unspill(t0, true, src_offset + (i * 8));
spill(t0, true, dst_offset + (i * 8));
}
@@ -188,6 +188,9 @@
void expand_bits_i_v(Register dst, Register src, Register mask);
void expand_bits_l_v(Register dst, Register src, Register mask);
+ void float16_to_float_v(VectorRegister dst, VectorRegister src, uint vector_length);
+ void float_to_float16_v(VectorRegister dst, VectorRegister src, VectorRegister vtmp, Register tmp, uint vector_length);
+
void string_equals_v(Register r1, Register r2,
Register result, Register cnt1);
@@ -224,30 +227,30 @@
void minmax_fp_v(VectorRegister dst,
VectorRegister src1, VectorRegister src2,
- BasicType bt, bool is_min, int vector_length);
+ BasicType bt, bool is_min, uint vector_length);
void minmax_fp_masked_v(VectorRegister dst, VectorRegister src1, VectorRegister src2,
VectorRegister vmask, VectorRegister tmp1, VectorRegister tmp2,
- BasicType bt, bool is_min, int vector_length);
+ BasicType bt, bool is_min, uint vector_length);
void reduce_minmax_fp_v(FloatRegister dst,
FloatRegister src1, VectorRegister src2,
VectorRegister tmp1, VectorRegister tmp2,
- bool is_double, bool is_min, int vector_length,
+ bool is_double, bool is_min, uint vector_length,
VectorMask vm = Assembler::unmasked);
void reduce_integral_v(Register dst, Register src1,
VectorRegister src2, VectorRegister tmp,
- int opc, BasicType bt, int vector_length,
+ int opc, BasicType bt, uint vector_length,
VectorMask vm = Assembler::unmasked);
- void vsetvli_helper(BasicType bt, int vector_length, LMUL vlmul = Assembler::m1, Register tmp = t0);
+ void vsetvli_helper(BasicType bt, uint vector_length, LMUL vlmul = Assembler::m1, Register tmp = t0);
void compare_integral_v(VectorRegister dst, VectorRegister src1, VectorRegister src2, int cond,
- BasicType bt, int vector_length, VectorMask vm = Assembler::unmasked);
+ BasicType bt, uint vector_length, VectorMask vm = Assembler::unmasked);
void compare_fp_v(VectorRegister dst, VectorRegister src1, VectorRegister src2, int cond,
- BasicType bt, int vector_length, VectorMask vm = Assembler::unmasked);
+ BasicType bt, uint vector_length, VectorMask vm = Assembler::unmasked);
// In Matcher::scalable_predicate_reg_slots,
// we assume each predicate register is one-eighth of the size of
@@ -264,18 +267,18 @@
vle8_v(v, t0);
}
- void spill_copy_vmask_stack_to_stack(int src_offset, int dst_offset, int vector_length_in_bytes) {
+ void spill_copy_vmask_stack_to_stack(int src_offset, int dst_offset, uint vector_length_in_bytes) {
assert(vector_length_in_bytes % 4 == 0, "unexpected vector mask reg size");
- for (int i = 0; i < vector_length_in_bytes / 4; i++) {
+ for (int i = 0; i < (int)vector_length_in_bytes / 4; i++) {
unspill(t0, false, src_offset + (i * 4));
spill(t0, false, dst_offset + (i * 4));
}
}
- void integer_extend_v(VectorRegister dst, BasicType dst_bt, int vector_length,
+ void integer_extend_v(VectorRegister dst, BasicType dst_bt, uint vector_length,
VectorRegister src, BasicType src_bt);
- void integer_narrow_v(VectorRegister dst, BasicType dst_bt, int vector_length,
+ void integer_narrow_v(VectorRegister dst, BasicType dst_bt, uint vector_length,
VectorRegister src, BasicType src_bt);
void vfcvt_rtz_x_f_v_safe(VectorRegister dst, VectorRegister src);
diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp
index 8461948752b..808bc66b263 100644
--- a/src/hotspot/cpu/riscv/globals_riscv.hpp
+++ b/src/hotspot/cpu/riscv/globals_riscv.hpp
@@ -115,6 +115,7 @@ define_pd_global(intx, InlineSmallCode, 1000);
product(bool, UseZtso, false, EXPERIMENTAL, "Assume Ztso memory model") \
product(bool, UseZihintpause, false, EXPERIMENTAL, \
"Use Zihintpause instructions") \
+ product(bool, UseZvfh, false, EXPERIMENTAL, "Use Zvfh instructions") \
product(bool, UseZvkn, false, EXPERIMENTAL, \
"Use Zvkn group extension, Zvkned, Zvknhb, Zvkb, Zvkt") \
product(bool, UseRVVForBigIntegerShiftIntrinsics, true, \
diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad
index d07f4dc7c9a..a21a42fe4ae 100644
--- a/src/hotspot/cpu/riscv/riscv_v.ad
+++ b/src/hotspot/cpu/riscv/riscv_v.ad
@@ -32,7 +32,7 @@ source %{
static void loadStore(C2_MacroAssembler masm, bool is_store,
VectorRegister reg, BasicType bt, Register base,
- int vector_length, Assembler::VectorMask vm = Assembler::unmasked) {
+ uint vector_length, Assembler::VectorMask vm = Assembler::unmasked) {
Assembler::SEW sew = Assembler::elemtype_to_sew(bt);
masm.vsetvli_helper(bt, vector_length);
@@ -73,6 +73,9 @@ source %{
return false;
}
break;
+ case Op_VectorCastHF2F:
+ case Op_VectorCastF2HF:
+ return UseZvfh;
default:
break;
}
@@ -3660,6 +3663,37 @@ instruct vsignum_reg(vReg dst, vReg zero, vReg one, vRegMask_V0 v0) %{
ins_pipe(pipe_slow);
%}
+// ---------------- Convert Half Floating to Floating Vector Operations ----------------
+
+// half precision -> single
+
+instruct vconvHF2F(vReg dst, vReg src, vRegMask_V0 v0) %{
+ predicate(Matcher::vector_element_basic_type(n) == T_FLOAT);
+ match(Set dst (VectorCastHF2F src));
+ effect(TEMP_DEF dst, TEMP v0);
+ format %{ "vfwcvt.f.f.v $dst, $src\t# convert half to single precision" %}
+ ins_encode %{
+ __ float16_to_float_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg),
+ Matcher::vector_length(this));
+ %}
+ ins_pipe(pipe_slow);
+%}
+
+// single precision -> half
+
+instruct vconvF2HF(vReg dst, vReg src, vReg vtmp, vRegMask_V0 v0, iRegINoSp tmp) %{
+ predicate(Matcher::vector_element_basic_type(n) == T_SHORT);
+ match(Set dst (VectorCastF2HF src));
+ effect(TEMP_DEF dst, TEMP v0, TEMP vtmp, TEMP tmp);
+ format %{ "vfncvt.f.f.w $dst, $src\t# convert single to half precision" %}
+ ins_encode %{
+ __ float_to_float16_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg),
+ as_VectorRegister($vtmp$$reg), $tmp$$Register,
+ Matcher::vector_length(this));
+ %}
+ ins_pipe(pipe_slow);
+%}
+
// ------------------------------ Vector Load Gather ---------------------------
instruct gather_load(vReg dst, indirect mem, vReg idx) %{
diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
index bbdafb922cc..df447abaa06 100644
--- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
+++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp
@@ -3662,8 +3662,153 @@ class StubGenerator: public StubCodeGenerator {
#endif // COMPILER2
+ address generate_cont_thaw(Continuation::thaw_kind kind) {
+ bool return_barrier = Continuation::is_thaw_return_barrier(kind);
+ bool return_barrier_exception = Continuation::is_thaw_return_barrier_exception(kind);
+
+ address start = __ pc();
+
+ if (return_barrier) {
+ __ ld(sp, Address(xthread, JavaThread::cont_entry_offset()));
+ }
+
+#ifndef PRODUCT
+ {
+ Label OK;
+ __ ld(t0, Address(xthread, JavaThread::cont_entry_offset()));
+ __ beq(sp, t0, OK);
+ __ stop("incorrect sp");
+ __ bind(OK);
+ }
+#endif
+
+ if (return_barrier) {
+ // preserve possible return value from a method returning to the return barrier
+ __ sub(sp, sp, 2 * wordSize);
+ __ fsd(f10, Address(sp, 0 * wordSize));
+ __ sd(x10, Address(sp, 1 * wordSize));
+ }
+
+ __ mv(c_rarg1, (return_barrier ? 1 : 0));
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, Continuation::prepare_thaw), xthread, c_rarg1);
+ __ mv(t1, x10); // x10 contains the size of the frames to thaw, 0 if overflow or no more frames
+
+ if (return_barrier) {
+ // restore return value (no safepoint in the call to thaw, so even an oop return value should be OK)
+ __ ld(x10, Address(sp, 1 * wordSize));
+ __ fld(f10, Address(sp, 0 * wordSize));
+ __ add(sp, sp, 2 * wordSize);
+ }
+
+#ifndef PRODUCT
+ {
+ Label OK;
+ __ ld(t0, Address(xthread, JavaThread::cont_entry_offset()));
+ __ beq(sp, t0, OK);
+ __ stop("incorrect sp");
+ __ bind(OK);
+ }
+#endif
+
+ Label thaw_success;
+ // t1 contains the size of the frames to thaw, 0 if overflow or no more frames
+ __ bnez(t1, thaw_success);
+ __ la(t0, ExternalAddress(StubRoutines::throw_StackOverflowError_entry()));
+ __ jr(t0);
+ __ bind(thaw_success);
+
+ // make room for the thawed frames
+ __ sub(t0, sp, t1);
+ __ andi(sp, t0, -16); // align
+
+ if (return_barrier) {
+ // save original return value -- again
+ __ sub(sp, sp, 2 * wordSize);
+ __ fsd(f10, Address(sp, 0 * wordSize));
+ __ sd(x10, Address(sp, 1 * wordSize));
+ }
+
+ // If we want, we can templatize thaw by kind, and have three different entries
+ __ mv(c_rarg1, kind);
+
+ __ call_VM_leaf(Continuation::thaw_entry(), xthread, c_rarg1);
+ __ mv(t1, x10); // x10 is the sp of the yielding frame
+
+ if (return_barrier) {
+ // restore return value (no safepoint in the call to thaw, so even an oop return value should be OK)
+ __ ld(x10, Address(sp, 1 * wordSize));
+ __ fld(f10, Address(sp, 0 * wordSize));
+ __ add(sp, sp, 2 * wordSize);
+ } else {
+ __ mv(x10, zr); // return 0 (success) from doYield
+ }
+
+ // we're now on the yield frame (which is in an address above us b/c sp has been pushed down)
+ __ mv(fp, t1);
+ __ sub(sp, t1, 2 * wordSize); // now pointing to fp spill
+
+ if (return_barrier_exception) {
+ __ ld(c_rarg1, Address(fp, -1 * wordSize)); // return address
+ __ verify_oop(x10);
+ __ mv(x9, x10); // save return value contaning the exception oop in callee-saved x9
+
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), xthread, c_rarg1);
+
+ // see OptoRuntime::generate_exception_blob: x10 -- exception oop, x13 -- exception pc
+
+ __ mv(x11, x10); // the exception handler
+ __ mv(x10, x9); // restore return value contaning the exception oop
+ __ verify_oop(x10);
+
+ __ leave();
+ __ mv(x13, ra);
+ __ jr(x11); // the exception handler
+ } else {
+ // We're "returning" into the topmost thawed frame; see Thaw::push_return_frame
+ __ leave();
+ __ ret();
+ }
+
+ return start;
+ }
+
+ address generate_cont_thaw() {
+ if (!Continuations::enabled()) return nullptr;
+
+ StubCodeMark mark(this, "StubRoutines", "Cont thaw");
+ address start = __ pc();
+ generate_cont_thaw(Continuation::thaw_top);
+ return start;
+ }
+
+ address generate_cont_returnBarrier() {
+ if (!Continuations::enabled()) return nullptr;
+
+ // TODO: will probably need multiple return barriers depending on return type
+ StubCodeMark mark(this, "StubRoutines", "cont return barrier");
+ address start = __ pc();
+
+ generate_cont_thaw(Continuation::thaw_return_barrier);
+
+ return start;
+ }
+
+ address generate_cont_returnBarrier_exception() {
+ if (!Continuations::enabled()) return nullptr;
+
+ StubCodeMark mark(this, "StubRoutines", "cont return barrier exception handler");
+ address start = __ pc();
+
+ generate_cont_thaw(Continuation::thaw_return_barrier_exception);
+
+ return start;
+ }
+
+#if COMPILER2_OR_JVMCI
+
#undef __
#define __ this->
+
class Sha2Generator : public MacroAssembler {
StubCodeGenerator* _cgen;
public:
@@ -4044,262 +4189,10 @@ class StubGenerator: public StubCodeGenerator {
return start;
}
};
-#undef __
-#define __ masm->
-
- // Continuation point for throwing of implicit exceptions that are
- // not handled in the current activation. Fabricates an exception
- // oop and initiates normal exception dispatching in this
- // frame. Since we need to preserve callee-saved values (currently
- // only for C2, but done for C1 as well) we need a callee-saved oop
- // map and therefore have to make these stubs into RuntimeStubs
- // rather than BufferBlobs. If the compiler needs all registers to
- // be preserved between the fault point and the exception handler
- // then it must assume responsibility for that in
- // AbstractCompiler::continuation_for_implicit_null_exception or
- // continuation_for_implicit_division_by_zero_exception. All other
- // implicit exceptions (e.g., NullPointerException or
- // AbstractMethodError on entry) are either at call sites or
- // otherwise assume that stack unwinding will be initiated, so
- // caller saved registers were assumed volatile in the compiler.
-
-#undef __
-#define __ masm->
-
- address generate_throw_exception(const char* name,
- address runtime_entry,
- Register arg1 = noreg,
- Register arg2 = noreg) {
- // Information about frame layout at time of blocking runtime call.
- // Note that we only have to preserve callee-saved registers since
- // the compilers are responsible for supplying a continuation point
- // if they expect all registers to be preserved.
- // n.b. riscv asserts that frame::arg_reg_save_area_bytes == 0
- assert_cond(runtime_entry != nullptr);
- enum layout {
- fp_off = 0,
- fp_off2,
- return_off,
- return_off2,
- framesize // inclusive of return address
- };
-
- const int insts_size = 1024;
- const int locs_size = 64;
-
- CodeBuffer code(name, insts_size, locs_size);
- OopMapSet* oop_maps = new OopMapSet();
- MacroAssembler* masm = new MacroAssembler(&code);
- assert_cond(oop_maps != nullptr && masm != nullptr);
-
- address start = __ pc();
-
- // This is an inlined and slightly modified version of call_VM
- // which has the ability to fetch the return PC out of
- // thread-local storage and also sets up last_Java_sp slightly
- // differently than the real call_VM
-
- __ enter(); // Save FP and RA before call
-
- assert(is_even(framesize / 2), "sp not 16-byte aligned");
-
- // ra and fp are already in place
- __ addi(sp, fp, 0 - ((unsigned)framesize << LogBytesPerInt)); // prolog
-
- int frame_complete = __ pc() - start;
-
- // Set up last_Java_sp and last_Java_fp
- address the_pc = __ pc();
- __ set_last_Java_frame(sp, fp, the_pc, t0);
-
- // Call runtime
- if (arg1 != noreg) {
- assert(arg2 != c_rarg1, "clobbered");
- __ mv(c_rarg1, arg1);
- }
- if (arg2 != noreg) {
- __ mv(c_rarg2, arg2);
- }
- __ mv(c_rarg0, xthread);
- BLOCK_COMMENT("call runtime_entry");
- __ call(runtime_entry);
-
- // Generate oop map
- OopMap* map = new OopMap(framesize, 0);
- assert_cond(map != nullptr);
-
- oop_maps->add_gc_map(the_pc - start, map);
-
- __ reset_last_Java_frame(true);
-
- __ leave();
-
- // check for pending exceptions
-#ifdef ASSERT
- Label L;
- __ ld(t0, Address(xthread, Thread::pending_exception_offset()));
- __ bnez(t0, L);
- __ should_not_reach_here();
- __ bind(L);
-#endif // ASSERT
- __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
-
- // codeBlob framesize is in words (not VMRegImpl::slot_size)
- RuntimeStub* stub =
- RuntimeStub::new_runtime_stub(name,
- &code,
- frame_complete,
- (framesize >> (LogBytesPerWord - LogBytesPerInt)),
- oop_maps, false);
- assert(stub != nullptr, "create runtime stub fail!");
- return stub->entry_point();
- }
#undef __
#define __ _masm->
- address generate_cont_thaw(Continuation::thaw_kind kind) {
- bool return_barrier = Continuation::is_thaw_return_barrier(kind);
- bool return_barrier_exception = Continuation::is_thaw_return_barrier_exception(kind);
-
- address start = __ pc();
-
- if (return_barrier) {
- __ ld(sp, Address(xthread, JavaThread::cont_entry_offset()));
- }
-
-#ifndef PRODUCT
- {
- Label OK;
- __ ld(t0, Address(xthread, JavaThread::cont_entry_offset()));
- __ beq(sp, t0, OK);
- __ stop("incorrect sp");
- __ bind(OK);
- }
-#endif
-
- if (return_barrier) {
- // preserve possible return value from a method returning to the return barrier
- __ sub(sp, sp, 2 * wordSize);
- __ fsd(f10, Address(sp, 0 * wordSize));
- __ sd(x10, Address(sp, 1 * wordSize));
- }
-
- __ mv(c_rarg1, (return_barrier ? 1 : 0));
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, Continuation::prepare_thaw), xthread, c_rarg1);
- __ mv(t1, x10); // x10 contains the size of the frames to thaw, 0 if overflow or no more frames
-
- if (return_barrier) {
- // restore return value (no safepoint in the call to thaw, so even an oop return value should be OK)
- __ ld(x10, Address(sp, 1 * wordSize));
- __ fld(f10, Address(sp, 0 * wordSize));
- __ add(sp, sp, 2 * wordSize);
- }
-
-#ifndef PRODUCT
- {
- Label OK;
- __ ld(t0, Address(xthread, JavaThread::cont_entry_offset()));
- __ beq(sp, t0, OK);
- __ stop("incorrect sp");
- __ bind(OK);
- }
-#endif
-
- Label thaw_success;
- // t1 contains the size of the frames to thaw, 0 if overflow or no more frames
- __ bnez(t1, thaw_success);
- __ la(t0, ExternalAddress(StubRoutines::throw_StackOverflowError_entry()));
- __ jr(t0);
- __ bind(thaw_success);
-
- // make room for the thawed frames
- __ sub(t0, sp, t1);
- __ andi(sp, t0, -16); // align
-
- if (return_barrier) {
- // save original return value -- again
- __ sub(sp, sp, 2 * wordSize);
- __ fsd(f10, Address(sp, 0 * wordSize));
- __ sd(x10, Address(sp, 1 * wordSize));
- }
-
- // If we want, we can templatize thaw by kind, and have three different entries
- __ mv(c_rarg1, kind);
-
- __ call_VM_leaf(Continuation::thaw_entry(), xthread, c_rarg1);
- __ mv(t1, x10); // x10 is the sp of the yielding frame
-
- if (return_barrier) {
- // restore return value (no safepoint in the call to thaw, so even an oop return value should be OK)
- __ ld(x10, Address(sp, 1 * wordSize));
- __ fld(f10, Address(sp, 0 * wordSize));
- __ add(sp, sp, 2 * wordSize);
- } else {
- __ mv(x10, zr); // return 0 (success) from doYield
- }
-
- // we're now on the yield frame (which is in an address above us b/c sp has been pushed down)
- __ mv(fp, t1);
- __ sub(sp, t1, 2 * wordSize); // now pointing to fp spill
-
- if (return_barrier_exception) {
- __ ld(c_rarg1, Address(fp, -1 * wordSize)); // return address
- __ verify_oop(x10);
- __ mv(x9, x10); // save return value contaning the exception oop in callee-saved x9
-
- __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), xthread, c_rarg1);
-
- // see OptoRuntime::generate_exception_blob: x10 -- exception oop, x13 -- exception pc
-
- __ mv(x11, x10); // the exception handler
- __ mv(x10, x9); // restore return value contaning the exception oop
- __ verify_oop(x10);
-
- __ leave();
- __ mv(x13, ra);
- __ jr(x11); // the exception handler
- } else {
- // We're "returning" into the topmost thawed frame; see Thaw::push_return_frame
- __ leave();
- __ ret();
- }
-
- return start;
- }
-
- address generate_cont_thaw() {
- if (!Continuations::enabled()) return nullptr;
-
- StubCodeMark mark(this, "StubRoutines", "Cont thaw");
- address start = __ pc();
- generate_cont_thaw(Continuation::thaw_top);
- return start;
- }
-
- address generate_cont_returnBarrier() {
- if (!Continuations::enabled()) return nullptr;
-
- // TODO: will probably need multiple return barriers depending on return type
- StubCodeMark mark(this, "StubRoutines", "cont return barrier");
- address start = __ pc();
-
- generate_cont_thaw(Continuation::thaw_return_barrier);
-
- return start;
- }
-
- address generate_cont_returnBarrier_exception() {
- if (!Continuations::enabled()) return nullptr;
-
- StubCodeMark mark(this, "StubRoutines", "cont return barrier exception handler");
- address start = __ pc();
-
- generate_cont_thaw(Continuation::thaw_return_barrier_exception);
-
- return start;
- }
-
// Set of L registers that correspond to a contiguous memory area.
// Each 64-bit register typically corresponds to 2 32-bit integers.
template
@@ -5149,7 +5042,7 @@ class StubGenerator: public StubCodeGenerator {
return (address) start;
}
-
+#endif // COMPILER2_OR_JVMCI
#ifdef COMPILER2
@@ -5464,6 +5357,114 @@ static const int64_t right_3_bits = right_n_bits(3);
return start;
}
+ // Continuation point for throwing of implicit exceptions that are
+ // not handled in the current activation. Fabricates an exception
+ // oop and initiates normal exception dispatching in this
+ // frame. Since we need to preserve callee-saved values (currently
+ // only for C2, but done for C1 as well) we need a callee-saved oop
+ // map and therefore have to make these stubs into RuntimeStubs
+ // rather than BufferBlobs. If the compiler needs all registers to
+ // be preserved between the fault point and the exception handler
+ // then it must assume responsibility for that in
+ // AbstractCompiler::continuation_for_implicit_null_exception or
+ // continuation_for_implicit_division_by_zero_exception. All other
+ // implicit exceptions (e.g., NullPointerException or
+ // AbstractMethodError on entry) are either at call sites or
+ // otherwise assume that stack unwinding will be initiated, so
+ // caller saved registers were assumed volatile in the compiler.
+
+#undef __
+#define __ masm->
+
+ address generate_throw_exception(const char* name,
+ address runtime_entry,
+ Register arg1 = noreg,
+ Register arg2 = noreg) {
+ // Information about frame layout at time of blocking runtime call.
+ // Note that we only have to preserve callee-saved registers since
+ // the compilers are responsible for supplying a continuation point
+ // if they expect all registers to be preserved.
+ // n.b. riscv asserts that frame::arg_reg_save_area_bytes == 0
+ assert_cond(runtime_entry != nullptr);
+ enum layout {
+ fp_off = 0,
+ fp_off2,
+ return_off,
+ return_off2,
+ framesize // inclusive of return address
+ };
+
+ const int insts_size = 1024;
+ const int locs_size = 64;
+
+ CodeBuffer code(name, insts_size, locs_size);
+ OopMapSet* oop_maps = new OopMapSet();
+ MacroAssembler* masm = new MacroAssembler(&code);
+ assert_cond(oop_maps != nullptr && masm != nullptr);
+
+ address start = __ pc();
+
+ // This is an inlined and slightly modified version of call_VM
+ // which has the ability to fetch the return PC out of
+ // thread-local storage and also sets up last_Java_sp slightly
+ // differently than the real call_VM
+
+ __ enter(); // Save FP and RA before call
+
+ assert(is_even(framesize / 2), "sp not 16-byte aligned");
+
+ // ra and fp are already in place
+ __ addi(sp, fp, 0 - ((unsigned)framesize << LogBytesPerInt)); // prolog
+
+ int frame_complete = __ pc() - start;
+
+ // Set up last_Java_sp and last_Java_fp
+ address the_pc = __ pc();
+ __ set_last_Java_frame(sp, fp, the_pc, t0);
+
+ // Call runtime
+ if (arg1 != noreg) {
+ assert(arg2 != c_rarg1, "clobbered");
+ __ mv(c_rarg1, arg1);
+ }
+ if (arg2 != noreg) {
+ __ mv(c_rarg2, arg2);
+ }
+ __ mv(c_rarg0, xthread);
+ BLOCK_COMMENT("call runtime_entry");
+ __ call(runtime_entry);
+
+ // Generate oop map
+ OopMap* map = new OopMap(framesize, 0);
+ assert_cond(map != nullptr);
+
+ oop_maps->add_gc_map(the_pc - start, map);
+
+ __ reset_last_Java_frame(true);
+
+ __ leave();
+
+ // check for pending exceptions
+#ifdef ASSERT
+ Label L;
+ __ ld(t0, Address(xthread, Thread::pending_exception_offset()));
+ __ bnez(t0, L);
+ __ should_not_reach_here();
+ __ bind(L);
+#endif // ASSERT
+ __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
+
+ // codeBlob framesize is in words (not VMRegImpl::slot_size)
+ RuntimeStub* stub =
+ RuntimeStub::new_runtime_stub(name,
+ &code,
+ frame_complete,
+ (framesize >> (LogBytesPerWord - LogBytesPerInt)),
+ oop_maps, false);
+ assert(stub != nullptr, "create runtime stub fail!");
+ return stub->entry_point();
+ }
+
#undef __
// Initialization
diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp
index e6f79cd6379..3619ac3e527 100644
--- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp
+++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp
@@ -152,6 +152,7 @@ class VM_Version : public Abstract_VM_Version {
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_Zvfh , "Zvfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZvfh)) \
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) \
diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp
index 9482537d84f..a5b2e6e5972 100644
--- a/src/hotspot/cpu/x86/assembler_x86.cpp
+++ b/src/hotspot/cpu/x86/assembler_x86.cpp
@@ -3657,7 +3657,7 @@ void Assembler::movups(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit);
simd_prefix(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x10);
emit_operand(dst, src, 0);
@@ -3667,7 +3667,7 @@ void Assembler::vmovups(XMMRegister dst, Address src, int vector_len) {
assert(vector_len == AVX_512bit ? VM_Version::supports_evex() : VM_Version::supports_avx(), "");
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_FVM, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit);
simd_prefix(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x10);
emit_operand(dst, src, 0);
@@ -3677,7 +3677,7 @@ void Assembler::movups(Address dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit);
simd_prefix(src, xnoreg, dst, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x11);
emit_operand(src, dst, 0);
@@ -3687,7 +3687,7 @@ void Assembler::vmovups(Address dst, XMMRegister src, int vector_len) {
assert(vector_len == AVX_512bit ? VM_Version::supports_evex() : VM_Version::supports_avx(), "");
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_FVM, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit);
simd_prefix(src, xnoreg, dst, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x11);
emit_operand(src, dst, 0);
@@ -4198,7 +4198,7 @@ void Assembler::packuswb(XMMRegister dst, Address src) {
assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x67);
emit_operand(dst, src, 0);
@@ -4582,7 +4582,7 @@ void Assembler::evpcmpeqd(KRegister kdst, KRegister mask, XMMRegister nds, Addre
assert(VM_Version::supports_evex(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.reset_is_clear_context();
attributes.set_embedded_opmask_register_specifier(mask);
@@ -4642,7 +4642,7 @@ void Assembler::evpcmpeqq(KRegister kdst, XMMRegister nds, Address src, int vect
InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.reset_is_clear_context();
attributes.set_is_evex_instruction();
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
int dst_enc = kdst->encoding();
vex_prefix(src, nds->encoding(), dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int8(0x29);
@@ -5142,6 +5142,33 @@ assert(vector_len == AVX_128bit? VM_Version::supports_avx() :
emit_int16(0x04, (0xC0 | encode));
}
+void Assembler::vpmadd52luq(XMMRegister dst, XMMRegister src1, Address src2, int vector_len) {
+ assert ((VM_Version::supports_avxifma() && vector_len <= AVX_256bit) || (VM_Version::supports_avx512ifma() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl())), "");
+
+ InstructionMark im(this);
+ InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
+
+ if (VM_Version::supports_avx512ifma()) {
+ attributes.set_is_evex_instruction();
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
+ }
+ vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int8((unsigned char)0xB4);
+ emit_operand(dst, src2, 0);
+}
+
+void Assembler::vpmadd52luq(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len) {
+ assert ((VM_Version::supports_avxifma() && vector_len <= AVX_256bit) || (VM_Version::supports_avx512ifma() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl())), "");
+
+ InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
+
+ if (VM_Version::supports_avx512ifma()) {
+ attributes.set_is_evex_instruction();
+ }
+ int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int16((unsigned char)0xB4, (0xC0 | encode));
+}
+
void Assembler::evpmadd52luq(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len) {
evpmadd52luq(dst, k0, src1, src2, false, vector_len);
}
@@ -5159,6 +5186,33 @@ void Assembler::evpmadd52luq(XMMRegister dst, KRegister mask, XMMRegister src1,
emit_int16((unsigned char)0xB4, (0xC0 | encode));
}
+void Assembler::vpmadd52huq(XMMRegister dst, XMMRegister src1, Address src2, int vector_len) {
+ assert ((VM_Version::supports_avxifma() && vector_len <= AVX_256bit) || (VM_Version::supports_avx512ifma() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl())), "");
+
+ InstructionMark im(this);
+ InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
+
+ if (VM_Version::supports_avx512ifma()) {
+ attributes.set_is_evex_instruction();
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
+ }
+ vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int8((unsigned char)0xB5);
+ emit_operand(dst, src2, 0);
+}
+
+void Assembler::vpmadd52huq(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len) {
+ assert ((VM_Version::supports_avxifma() && vector_len <= AVX_256bit) || (VM_Version::supports_avx512ifma() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl())), "");
+
+ InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
+
+ if (VM_Version::supports_avx512ifma()) {
+ attributes.set_is_evex_instruction();
+ }
+ int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
+ emit_int16((unsigned char)0xB5, (0xC0 | encode));
+}
+
void Assembler::evpmadd52huq(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len) {
evpmadd52huq(dst, k0, src1, src2, false, vector_len);
}
@@ -5400,7 +5454,7 @@ void Assembler::pshufd(XMMRegister dst, Address src, int mode) {
assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* 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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x70);
emit_operand(dst, src, 1);
@@ -5629,7 +5683,7 @@ void Assembler::punpckldq(XMMRegister dst, Address src) {
assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes");
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* 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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x62);
emit_operand(dst, src, 0);
@@ -6135,7 +6189,7 @@ void Assembler::smovl() {
void Assembler::roundsd(XMMRegister dst, XMMRegister src, int32_t rmode) {
assert(VM_Version::supports_sse4_1(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false);
- int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
+ int encode = simd_prefix_and_encode(dst, src, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
emit_int24(0x0B, (0xC0 | encode), (unsigned char)rmode);
}
@@ -6734,7 +6788,7 @@ void Assembler::addpd(XMMRegister dst, Address src) {
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_rex_vex_w_reverted();
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x58);
emit_operand(dst, src, 0);
@@ -6767,7 +6821,7 @@ void Assembler::vaddpd(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* 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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_rex_vex_w_reverted();
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x58);
@@ -6778,7 +6832,7 @@ void Assembler::vaddps(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x58);
emit_operand(dst, src, 0);
@@ -6818,7 +6872,7 @@ void Assembler::vsubpd(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* 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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_rex_vex_w_reverted();
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x5C);
@@ -6829,7 +6883,7 @@ void Assembler::vsubps(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x5C);
emit_operand(dst, src, 0);
@@ -6847,7 +6901,7 @@ void Assembler::mulpd(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* 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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_rex_vex_w_reverted();
simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x59);
@@ -6880,7 +6934,7 @@ void Assembler::vmulpd(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* 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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_rex_vex_w_reverted();
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x59);
@@ -6891,7 +6945,7 @@ void Assembler::vmulps(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x59);
emit_operand(dst, src, 0);
@@ -6915,7 +6969,7 @@ void Assembler::vfmadd231pd(XMMRegister dst, XMMRegister src1, Address src2, int
assert(VM_Version::supports_fma(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xB8);
emit_operand(dst, src2, 0);
@@ -6925,7 +6979,7 @@ void Assembler::vfmadd231ps(XMMRegister dst, XMMRegister src1, Address src2, int
assert(VM_Version::supports_fma(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xB8);
emit_operand(dst, src2, 0);
@@ -6965,7 +7019,7 @@ void Assembler::vdivpd(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* 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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_rex_vex_w_reverted();
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x5E);
@@ -6976,7 +7030,7 @@ void Assembler::vdivps(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x5E);
emit_operand(dst, src, 0);
@@ -7029,7 +7083,7 @@ void Assembler::vrndscalepd(XMMRegister dst, Address src, int32_t rmode, int vec
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
emit_int8(0x09);
emit_operand(dst, src, 1);
@@ -7048,7 +7102,7 @@ void Assembler::vsqrtpd(XMMRegister dst, Address src, int vector_len) {
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* 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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_rex_vex_w_reverted();
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x51);
@@ -7066,7 +7120,7 @@ void Assembler::vsqrtps(XMMRegister dst, Address src, int vector_len) {
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x51);
emit_operand(dst, src, 0);
@@ -7091,7 +7145,7 @@ void Assembler::andps(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
simd_prefix(dst, dst, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x54);
emit_operand(dst, src, 0);
@@ -7101,7 +7155,7 @@ void Assembler::andpd(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_rex_vex_w_reverted();
simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x54);
@@ -7127,7 +7181,7 @@ void Assembler::vandpd(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_rex_vex_w_reverted();
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x54);
@@ -7138,7 +7192,7 @@ void Assembler::vandps(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x54);
emit_operand(dst, src, 0);
@@ -7180,7 +7234,7 @@ void Assembler::xorpd(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_rex_vex_w_reverted();
simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x57);
@@ -7191,7 +7245,7 @@ void Assembler::xorps(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionMark im(this);
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
simd_prefix(dst, dst, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x57);
emit_operand(dst, src, 0);
@@ -7216,7 +7270,7 @@ void Assembler::vxorpd(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_rex_vex_w_reverted();
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8(0x57);
@@ -7227,7 +7281,7 @@ void Assembler::vxorps(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes);
emit_int8(0x57);
emit_operand(dst, src, 0);
@@ -7355,7 +7409,7 @@ void Assembler::vpaddd(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(UseAVX > 0, "requires some form of AVX");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8((unsigned char)0xFE);
emit_operand(dst, src, 0);
@@ -7365,7 +7419,7 @@ void Assembler::vpaddq(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(UseAVX > 0, "requires some form of AVX");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* 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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_rex_vex_w_reverted();
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8((unsigned char)0xD4);
@@ -7461,7 +7515,7 @@ void Assembler::vpsubd(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(UseAVX > 0, "requires some form of AVX");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8((unsigned char)0xFA);
emit_operand(dst, src, 0);
@@ -7471,7 +7525,7 @@ void Assembler::vpsubq(XMMRegister dst, XMMRegister nds, Address src, int vector
assert(UseAVX > 0, "requires some form of AVX");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* 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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_rex_vex_w_reverted();
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8((unsigned char)0xFB);
@@ -7551,7 +7605,7 @@ void Assembler::vpmulld(XMMRegister dst, XMMRegister nds, Address src, int vecto
assert(UseAVX > 0, "requires some form of AVX");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int8(0x40);
emit_operand(dst, src, 0);
@@ -7561,7 +7615,7 @@ void Assembler::evpmullq(XMMRegister dst, XMMRegister nds, Address src, int vect
assert(UseAVX > 2, "requires some form of EVEX");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes);
emit_int8(0x40);
@@ -8037,7 +8091,7 @@ void Assembler::vpand(XMMRegister dst, XMMRegister nds, Address src, int vector_
assert(UseAVX > 0, "requires some form of AVX");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8((unsigned char)0xDB);
emit_operand(dst, src, 0);
@@ -8155,7 +8209,7 @@ void Assembler::vpor(XMMRegister dst, XMMRegister nds, Address src, int vector_l
assert(UseAVX > 0, "requires some form of AVX");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8((unsigned char)0xEB);
emit_operand(dst, src, 0);
@@ -8222,7 +8276,7 @@ void Assembler::vpxor(XMMRegister dst, XMMRegister nds, Address src, int vector_
vector_len == AVX_512bit ? VM_Version::supports_evex() : 0, "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_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_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8((unsigned char)0xEF);
emit_operand(dst, src, 0);
@@ -8253,7 +8307,7 @@ void Assembler::evpxord(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -8281,7 +8335,7 @@ void Assembler::evpxorq(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -8296,7 +8350,7 @@ void Assembler::evpandd(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -8325,7 +8379,7 @@ void Assembler::evpandq(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), "requires AVX512VL");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -8354,7 +8408,7 @@ void Assembler::evporq(XMMRegister dst, KRegister mask, XMMRegister nds, Address
assert(vector_len == Assembler::AVX_512bit || VM_Version::supports_avx512vl(), "requires AVX512VL");
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -8379,7 +8433,7 @@ void Assembler::evpxorq(XMMRegister dst, XMMRegister nds, Address src, int vecto
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
emit_int8((unsigned char)0xEF);
emit_operand(dst, src, 0);
@@ -8501,7 +8555,7 @@ void Assembler::vpternlogd(XMMRegister dst, int imm8, XMMRegister src2, Address
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src3, src2->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
emit_int8(0x25);
emit_operand(dst, src3, 1);
@@ -8526,7 +8580,7 @@ void Assembler::vpternlogq(XMMRegister dst, int imm8, XMMRegister src2, Address
InstructionMark im(this);
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
attributes.set_is_evex_instruction();
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
vex_prefix(src3, src2->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes);
emit_int8(0x25);
emit_operand(dst, src3, 1);
@@ -9061,6 +9115,13 @@ void Assembler::vpunpckhdq(XMMRegister dst, XMMRegister nds, XMMRegister src, in
emit_int16(0x6A, (0xC0 | encode));
}
+void Assembler::vpunpckhqdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
+ assert(UseAVX > 0, "requires some form of AVX");
+ InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
+ emit_int16(0x6D, (0xC0 | encode));
+}
+
void Assembler::vpunpckldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
assert(UseAVX > 0, "requires some form of AVX");
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
@@ -9068,6 +9129,13 @@ void Assembler::vpunpckldq(XMMRegister dst, XMMRegister nds, XMMRegister src, in
emit_int16(0x62, (0xC0 | encode));
}
+void Assembler::vpunpcklqdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) {
+ assert(UseAVX > 0, "requires some form of AVX");
+ InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true);
+ int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes);
+ emit_int16(0x6C, (0xC0 | encode));
+}
+
// xmm/mem sourced byte/word/dword/qword replicate
void Assembler::evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) {
assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), "");
@@ -9085,7 +9153,7 @@ void Assembler::evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
InstructionMark im(this);
assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9112,7 +9180,7 @@ void Assembler::evpaddw(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
InstructionMark im(this);
assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9141,7 +9209,7 @@ void Assembler::evpaddd(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9170,7 +9238,7 @@ void Assembler::evpaddq(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9199,7 +9267,7 @@ void Assembler::evaddps(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9228,7 +9296,7 @@ void Assembler::evaddpd(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9255,7 +9323,7 @@ void Assembler::evpsubb(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
InstructionMark im(this);
assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9282,7 +9350,7 @@ void Assembler::evpsubw(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
InstructionMark im(this);
assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9311,7 +9379,7 @@ void Assembler::evpsubd(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9340,7 +9408,7 @@ void Assembler::evpsubq(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9369,7 +9437,7 @@ void Assembler::evsubps(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9398,7 +9466,7 @@ void Assembler::evsubpd(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9425,7 +9493,7 @@ void Assembler::evpmullw(XMMRegister dst, KRegister mask, XMMRegister nds, Addre
InstructionMark im(this);
assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9454,7 +9522,7 @@ void Assembler::evpmulld(XMMRegister dst, KRegister mask, XMMRegister nds, Addre
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9481,7 +9549,7 @@ void Assembler::evpmullq(XMMRegister dst, KRegister mask, XMMRegister nds, Addre
InstructionMark im(this);
assert(VM_Version::supports_avx512dq() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), "");
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9510,7 +9578,7 @@ void Assembler::evmulps(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9539,7 +9607,7 @@ void Assembler::evmulpd(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9568,7 +9636,7 @@ void Assembler::evsqrtps(XMMRegister dst, KRegister mask, XMMRegister nds, Addre
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9597,7 +9665,7 @@ void Assembler::evsqrtpd(XMMRegister dst, KRegister mask, XMMRegister nds, Addre
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9627,7 +9695,7 @@ void Assembler::evdivps(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9656,7 +9724,7 @@ void Assembler::evdivpd(XMMRegister dst, KRegister mask, XMMRegister nds, Addres
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9679,7 +9747,7 @@ void Assembler::evdivsd(XMMRegister dst, XMMRegister nds, XMMRegister src, EvexR
void Assembler::evpabsb(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) {
assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9694,7 +9762,7 @@ void Assembler::evpabsb(XMMRegister dst, KRegister mask, Address src, bool merge
InstructionMark im(this);
assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9708,7 +9776,7 @@ void Assembler::evpabsb(XMMRegister dst, KRegister mask, Address src, bool merge
void Assembler::evpabsw(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) {
assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9723,7 +9791,7 @@ void Assembler::evpabsw(XMMRegister dst, KRegister mask, Address src, bool merge
InstructionMark im(this);
assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9738,7 +9806,7 @@ void Assembler::evpabsd(XMMRegister dst, KRegister mask, XMMRegister src, bool m
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9754,7 +9822,7 @@ void Assembler::evpabsd(XMMRegister dst, KRegister mask, Address src, bool merge
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9769,7 +9837,7 @@ void Assembler::evpabsq(XMMRegister dst, KRegister mask, XMMRegister src, bool m
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9785,7 +9853,7 @@ void Assembler::evpabsq(XMMRegister dst, KRegister mask, Address src, bool merge
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -9814,7 +9882,7 @@ void Assembler::evpfma213ps(XMMRegister dst, KRegister mask, XMMRegister nds, Ad
assert(VM_Version::supports_evex(), "");
assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), "");
InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
if (merge) {
@@ -10538,7 +10606,7 @@ void Assembler::evpternlogd(XMMRegister dst, int imm8, KRegister mask, XMMRegist
InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
if (merge) {
attributes.reset_is_clear_context();
}
@@ -10569,7 +10637,7 @@ void Assembler::evpternlogq(XMMRegister dst, int imm8, KRegister mask, XMMRegist
InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true);
attributes.set_is_evex_instruction();
attributes.set_embedded_opmask_register_specifier(mask);
- attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit);
+ attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit);
if (merge) {
attributes.reset_is_clear_context();
}
diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp
index e82b77dd343..9b2f03ec7eb 100644
--- a/src/hotspot/cpu/x86/assembler_x86.hpp
+++ b/src/hotspot/cpu/x86/assembler_x86.hpp
@@ -1913,8 +1913,12 @@ class Assembler : public AbstractAssembler {
void pmaddwd(XMMRegister dst, XMMRegister src);
void vpmaddwd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
void vpmaddubsw(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len);
+ void vpmadd52luq(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len);
+ void vpmadd52luq(XMMRegister dst, XMMRegister src1, Address src2, int vector_len);
void evpmadd52luq(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len);
void evpmadd52luq(XMMRegister dst, KRegister mask, XMMRegister src1, XMMRegister src2, bool merge, int vector_len);
+ void vpmadd52huq(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len);
+ void vpmadd52huq(XMMRegister dst, XMMRegister src1, Address src2, int vector_len);
void evpmadd52huq(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len);
void evpmadd52huq(XMMRegister dst, KRegister mask, XMMRegister src1, XMMRegister src2, bool merge, int vector_len);
@@ -2009,6 +2013,8 @@ class Assembler : public AbstractAssembler {
void punpckldq(XMMRegister dst, XMMRegister src);
void punpckldq(XMMRegister dst, Address src);
void vpunpckldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
+ void vpunpcklqdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
+
// Interleave High Word
void vpunpckhwd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
@@ -2018,6 +2024,7 @@ class Assembler : public AbstractAssembler {
// Interleave High Doublewords
void vpunpckhdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
+ void vpunpckhqdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len);
// Interleave Low Quadwords
void punpcklqdq(XMMRegister dst, XMMRegister src);
diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp
index ae340e64fb7..a705dd70efd 100644
--- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp
@@ -83,12 +83,12 @@
};
// allocation of arrays
- // obj : must be rax, will contain pointer to allocated object
- // len : array length in number of elements
- // t : scratch register - contents destroyed
- // header_size: size of object header in words
- // f : element scale factor
- // slow_case : exit to slow case implementation if fast allocation fails
+ // obj : must be rax, will contain pointer to allocated object
+ // len : array length in number of elements
+ // t : scratch register - contents destroyed
+ // base_offset_in_bytes: offset of the first array element, in bytes
+ // f : element scale factor
+ // slow_case : exit to slow case implementation if fast allocation fails
void allocate_array(Register obj, Register len, Register t, Register t2, int base_offset_in_bytes, Address::ScaleFactor f, Register klass, Label& slow_case);
int rsp_offset() const { return _rsp_offset; }
diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
index 38cad579967..1d98e6115a1 100644
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp
@@ -10160,6 +10160,17 @@ void MacroAssembler::vpshufb(XMMRegister dst, XMMRegister nds, AddressLiteral sr
}
}
+void MacroAssembler::vpor(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len, Register rscratch) {
+ assert(rscratch != noreg || always_reachable(src), "missing");
+
+ if (reachable(src)) {
+ Assembler::vpor(dst, nds, as_Address(src), vector_len);
+ } else {
+ lea(rscratch, src);
+ Assembler::vpor(dst, nds, Address(rscratch, 0), vector_len);
+ }
+}
+
void MacroAssembler::vpternlogq(XMMRegister dst, int imm8, XMMRegister src2, AddressLiteral src3, int vector_len, Register rscratch) {
assert(rscratch != noreg || always_reachable(src3), "missing");
diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp
index d0023324c47..261a905fcb3 100644
--- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp
@@ -1863,6 +1863,9 @@ class MacroAssembler: public Assembler {
using Assembler::vpshufb;
void vpshufb(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len, Register rscratch = noreg);
+ using Assembler::vpor;
+ void vpor(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len, Register rscratch = noreg);
+
using Assembler::vpternlogq;
void vpternlogq(XMMRegister dst, int imm8, XMMRegister src2, AddressLiteral src3, int vector_len, Register rscratch = noreg);
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp
index e399d858d3d..11a99907364 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp
@@ -453,6 +453,27 @@ class StubGenerator: public StubCodeGenerator {
void poly1305_limbs_avx512(const XMMRegister D0, const XMMRegister D1,
const XMMRegister L0, const XMMRegister L1, const XMMRegister L2, bool padMSG,
const XMMRegister TMP, const Register rscratch);
+ //Poly305 AVX2 implementation
+ void poly1305_process_blocks_avx2(const Register input, const Register length,
+ const Register a0, const Register a1, const Register a2,
+ const Register r0, const Register r1, const Register c1);
+ void poly1305_msg_mul_reduce_vec4_avx2(const XMMRegister A0, const XMMRegister A1, const XMMRegister A2,
+ const Address R0, const Address R1, const Address R2,
+ const Address R1P, const Address R2P,
+ const XMMRegister P0L, const XMMRegister P0H,
+ const XMMRegister P1L, const XMMRegister P1H,
+ const XMMRegister P2L, const XMMRegister P2H,
+ const XMMRegister YTMP1, const XMMRegister YTMP2,
+ const XMMRegister YTMP3, const XMMRegister YTMP4,
+ const XMMRegister YTMP5, const XMMRegister YTMP6,
+ const Register input, const Register length, const Register rscratch);
+ void poly1305_mul_reduce_vec4_avx2(const XMMRegister A0, const XMMRegister A1, const XMMRegister A2,
+ const XMMRegister R0, const XMMRegister R1, const XMMRegister R2,
+ const XMMRegister R1P, const XMMRegister R2P,
+ const XMMRegister P0L, const XMMRegister P0H,
+ const XMMRegister P1L, const XMMRegister P1H,
+ const XMMRegister P2L, const XMMRegister P2H,
+ const XMMRegister YTMP1, const Register rscratch);
// BASE64 stubs
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly.cpp
index 97070344a57..6d3da2e6c75 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2022, 2024, Intel Corporation. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -927,8 +927,8 @@ address StubGenerator::generate_poly1305_processBlocks() {
__ push(r15);
// Register Map
- const Register input = rdi;
- const Register length = rbx;
+ const Register input = rdi; // msg
+ const Register length = rbx; // msg length in bytes
const Register accumulator = rcx;
const Register R = r8;
@@ -985,9 +985,16 @@ address StubGenerator::generate_poly1305_processBlocks() {
__ cmpl(length, 16*16);
__ jcc(Assembler::less, L_process16Loop);
- poly1305_process_blocks_avx512(input, length,
+ if (UseAVX > 2) {
+ poly1305_process_blocks_avx512(input, length,
a0, a1, a2,
r0, r1, c1);
+ } else {
+ poly1305_process_blocks_avx2(input, length,
+ a0, a1, a2,
+ r0, r1, c1);
+ }
+
// SCALAR LOOP: process one 16-byte message block at a time
__ bind(L_process16Loop);
@@ -1023,3 +1030,668 @@ address StubGenerator::generate_poly1305_processBlocks() {
__ ret(0);
return start;
}
+
+/*
+ The AVX2 implementation below is directly based on the AVX2 Poly1305 hash computation as
+ implemented in Intel(R) Multi-Buffer Crypto for IPsec Library.
+ (url: https://github.com/intel/intel-ipsec-mb/blob/main/lib/avx2_t3/poly_fma_avx2.asm)
+
+ Additional references:
+ [1] Goll M, Gueron S., "Vectorization of Poly1305 message authentication code",
+ 12th International Conference on Information Technology-New Generations,
+ 2015 Apr 13 (pp. 145-150). IEEE.
+ [2] Bhattacharyya S, Sarkar P., "Improved SIMD implementation of Poly1305",
+ IET Information Security. 2020 Sep;14(5):521-30.
+ Note: a compact summary of the Goll-Gueron AVX2 algorithm developed in [1] is presented in [2].
+ [3] Wikipedia, "Parallel evaluation of Horner's method",
+ (url: https://en.wikipedia.org/wiki/Horner%27s_method)
+ ----------------------------------------------------------
+
+ Poly1305 AVX2 algorithm:
+ Let the 32-byte one-time key be partitioned into two equal parts R and K.
+ Let R be the 16-byte secret key used for polynomial evaluation.
+ Let K be the 16-byte secret key.
+ Let Z_P be prime field over which the polynomial is evaluated. Let P = 2^130 - 5 be the prime.
+ Let M be the message which can be represented as a concatenation (||) of 'l' 16-byte blocks M[i].
+ i.e., M = M[0] || M[1] || ... || M[i] || ... || M[l-2] || M[l-1]
+ To create the coefficients C[i] for polynomial evaluation over Z_P, each 16-byte (i.e., 128-bit)
+ message block M[i] is concatenated with bits '10' to make a 130-bit block.
+ The last block (<= 16-byte length) is concatenated with 1 followed by 0s to make a 130-bit block.
+ Therefore, we define
+ C[i] = M[i] || '10' for 0 <= i <= l-2 ;
+ C[l-1] = M[i] || '10...0'
+ such that, length(C[i]) = 130 bits, for i ∈ [0, l).
+
+ Let * indicate scalar multiplication (i.e., w = u * v);
+ Let × indicate scalar multiplication followed by reduction modulo P (i.e., z = u × v = {(u * v) mod P})
+
+ POLY1305_MAC = (POLY1305_EVAL_POLYNOMIAL(C, R, P) + K) mod 2^128; where,
+
+ POLY1305_EVAL_POLYNOMIAL(C, R, P) = {C[0] * R^l + C[1] * R^(l-1) + ... + C[l-2] * R^2 + C[l-1] * R} mod P
+ = R × {C[0] × R^(l-1) + C[1] × R^(l-2) + ... + C[l-2] × R + C[l-1]}
+ = R × Polynomial(R; C[0], C[1], ... ,C[l-2], C[l-1])
+ Where,
+ Polynomial(R; C[0], C[1], ... ,C[l-2], C[l-1]) = Σ{C[i] × R^(l-i-1)} for i ∈ [0, l)
+ ----------------------------------------------------------
+
+ Parallel evaluation of POLY1305_EVAL_POLYNOMIAL(C, R, P):
+ Let the number of message blocks l = 4*l' + ρ where ρ = l mod 4.
+ Using k-way parallel Horner's evaluation [3], for k = 4, we define SUM below:
+
+ SUM = R^4 × Polynomial(R^4; C[0], C[4], C[8] ... , C[4l'-4]) +
+ R^3 × Polynomial(R^4; C[1], C[5], C[9] ... , C[4l'-3]) +
+ R^2 × Polynomial(R^4; C[2], C[6], C[10] ... , C[4l'-2]) +
+ R^1 × Polynomial(R^4; C[3], C[7], C[11] ... , C[4l'-1]) +
+
+ Then,
+ POLY1305_EVAL_POLYNOMIAL(C, R, P) = SUM if ρ = 0 (i.e., l is multiple of 4)
+ = R × Polynomial(R; SUM + C[l-ρ], C[l-ρ+1], ... , C[l-1]) if ρ > 0
+ ----------------------------------------------------------
+
+ Gall-Gueron[1] 4-way SIMD Algorithm[2] for POLY1305_EVAL_POLYNOMIAL(C, R, P):
+
+ Define mathematical vectors (not same as SIMD vector lanes) as below:
+ R4321 = [R^4, R^3, R^2, R^1];
+ R4444 = [R^4, R^4, R^4, R^4];
+ COEF[i] = [C[4i], C[4i+1], C[4i+2], C[4i+3]] for i ∈ [0, l'). For example, COEF[0] and COEF[1] shown below.
+ COEF[0] = [C0, C1, C2, C3]
+ COEF[1] = [C4, C5, C6, C7]
+ T = [T0, T1, T2, T3] be a temporary vector
+ ACC = [acc, 0, 0, 0]; acc has hash from previous computations (if any), otherwise 0.
+ ⊗ indicates component-wise vector multiplication followed by modulo reduction
+ ⊕ indicates component-wise vector addition, + indicates scalar addition
+
+ POLY1305_EVAL_POLYNOMIAL(C, R, P) {
+ T ← ACC; # load accumulator
+ T ← T ⊕ COEF[0]; # add accumulator to the first 4 blocks
+ Compute R4321, R4444;
+ # SIMD loop
+ l' = floor(l/4); # operate on 4 blocks at a time
+ for (i = 1 to l'-1):
+ T ← (R4444 ⊗ T) ⊕ COEF[i];
+ T ← R4321 ⊗ T;
+ SUM ← T0 + T1 + T2 + T3;
+
+ # Scalar tail processing
+ if (ρ > 0):
+ SUM ← R × Polynomial(R; SUM + C[l-ρ], C[l-ρ+1], ... , C[l-1]);
+ return SUM;
+ }
+
+ Notes:
+ (1) Each 130-bit block is represented using three 44-bit limbs (most significant limb is only 42-bit).
+ (The Goll-Gueron implementation[1] uses five 26-bit limbs instead).
+ (2) Each component of the mathematical vectors is a 130-bit value. The above mathemetical vectors are not to be confused with SIMD vector lanes.
+ (3) Each AVX2 YMM register can store four 44-bit limbs in quadwords. Since each 130-bit message block is represented using 3 limbs,
+ to store all the limbs of 4 different 130-bit message blocks, we need 3 YMM registers in total.
+ (4) In the AVX2 implementation, multiplication followed by modulo reduction and addition are performed for 4 blocks at a time.
+
+*/
+
+void StubGenerator::poly1305_process_blocks_avx2(
+ const Register input, const Register length,
+ const Register a0, const Register a1, const Register a2,
+ const Register r0, const Register r1, const Register c1)
+{
+ Label L_process256Loop, L_process256LoopDone;
+ const Register t0 = r13;
+ const Register t1 = r14;
+ const Register t2 = r15;
+ const Register mulql = rax;
+ const Register mulqh = rdx;
+
+ const XMMRegister YMM_ACC0 = xmm0;
+ const XMMRegister YMM_ACC1 = xmm1;
+ const XMMRegister YMM_ACC2 = xmm2;
+
+ const XMMRegister YTMP1 = xmm3;
+ const XMMRegister YTMP2 = xmm4;
+ const XMMRegister YTMP3 = xmm5;
+ const XMMRegister YTMP4 = xmm6;
+ const XMMRegister YTMP5 = xmm7;
+ const XMMRegister YTMP6 = xmm8;
+ const XMMRegister YTMP7 = xmm9;
+ const XMMRegister YTMP8 = xmm10;
+ const XMMRegister YTMP9 = xmm11;
+ const XMMRegister YTMP10 = xmm12;
+ const XMMRegister YTMP11 = xmm13;
+ const XMMRegister YTMP12 = xmm14;
+ const XMMRegister YTMP13 = xmm15;
+
+ const XMMRegister YMM_R0 = YTMP11;
+ const XMMRegister YMM_R1 = YTMP12;
+ const XMMRegister YMM_R2 = YTMP13;
+
+ // XWORD aliases of YMM registers (for convenience)
+ const XMMRegister XTMP1 = YTMP1;
+ const XMMRegister XTMP2 = YTMP2;
+ const XMMRegister XTMP3 = YTMP3;
+
+ // Setup stack frame
+ // Save rbp and rsp
+ __ push(rbp);
+ __ movq(rbp, rsp);
+ // Align stack and reserve space
+ __ andq(rsp, -32);
+ __ subptr(rsp, 32*8);
+
+ /* Compute the following steps of POLY1305_EVAL_POLYNOMIAL algorithm
+ T ← ACC
+ T ← T ⊕ COEF[0];
+ */
+
+ // Spread accumulator into 44-bit limbs in quadwords
+ // Accumulator limbs to be stored in YTMP1,YTMP2,YTMP3
+ // First limb (Acc[43:0])
+ __ movq(t0, a0);
+ __ andq(t0, ExternalAddress(poly1305_mask44()), t1 /*rscratch*/);
+ __ movq(XTMP1, t0);
+ // Second limb (Acc[87:44])
+ __ movq(t0, a1);
+ __ shrdq(a0, t0, 44);
+ __ andq(a0, ExternalAddress(poly1305_mask44()), t1 /*rscratch*/);
+ __ movq(XTMP2, a0);
+ // Third limb (Acc[129:88])
+ __ shrdq(a1, a2, 24);
+ __ andq(a1, ExternalAddress(poly1305_mask42()), t1 /*rscratch*/);
+ __ movq(XTMP3, a1);
+ // --- end of spread accumulator
+
+ // To add accumulator, we must unroll first loop iteration
+ // Load first four 16-byte message blocks of data (64 bytes)
+ __ vmovdqu(YTMP4, Address(input, 0));
+ __ vmovdqu(YTMP5, Address(input, 32));
+
+ // Interleave the input message data to form 44-bit limbs
+ // YMM_ACC0 to have bits 0-43 of all 4 blocks in 4 qwords
+ // YMM_ACC1 to have bits 87-44 of all 4 blocks in 4 qwords
+ // YMM_ACC2 to have bits 127-88 of all 4 blocks in 4 qwords
+ // Interleave blocks of data
+ __ vpunpckhqdq(YMM_ACC2, YTMP4, YTMP5, Assembler::AVX_256bit);
+ __ vpunpcklqdq(YMM_ACC0, YTMP4, YTMP5, Assembler::AVX_256bit);
+
+ // Middle 44-bit limbs of new blocks
+ __ vpsrlq(YMM_ACC1, YMM_ACC0, 44, Assembler::AVX_256bit);
+ __ vpsllq(YTMP4, YMM_ACC2, 20, Assembler::AVX_256bit);
+ __ vpor(YMM_ACC1, YMM_ACC1, YTMP4, Assembler::AVX_256bit);
+ __ vpand(YMM_ACC1, YMM_ACC1, ExternalAddress(poly1305_mask44()), Assembler::AVX_256bit, t1);
+
+ // Lowest 44-bit limbs of new blocks
+ __ vpand(YMM_ACC0, YMM_ACC0, ExternalAddress(poly1305_mask44()), Assembler::AVX_256bit, t1);
+
+ // Highest 42-bit limbs of new blocks; pad the msg with 2^128
+ __ vpsrlq(YMM_ACC2, YMM_ACC2, 24, Assembler::AVX_256bit);
+
+ // Add 2^128 to all 4 final qwords for the message
+ __ vpor(YMM_ACC2, YMM_ACC2, ExternalAddress(poly1305_pad_msg()), Assembler::AVX_256bit, t1);
+ // --- end of input interleaving and message padding
+
+ // Add accumulator to the fist message block
+ // Accumulator limbs in YTMP1,YTMP2,YTMP3
+ __ vpaddq(YMM_ACC0, YMM_ACC0, YTMP1, Assembler::AVX_256bit);
+ __ vpaddq(YMM_ACC1, YMM_ACC1, YTMP2, Assembler::AVX_256bit);
+ __ vpaddq(YMM_ACC2, YMM_ACC2, YTMP3, Assembler::AVX_256bit);
+
+ /* Compute the following steps of POLY1305_EVAL_POLYNOMIAL algorithm
+ Compute R4321, R4444;
+ R4321 = [R^4, R^3, R^2, R^1];
+ R4444 = [R^4, R^4, R^4, R^4];
+ */
+
+ // Compute the powers of R^1..R^4 and form 44-bit limbs of each
+ // YTMP5 to have bits 0-127 for R^1 and R^2
+ // YTMP6 to have bits 128-129 for R^1 and R^2
+ __ movq(XTMP1, r0);
+ __ vpinsrq(XTMP1, XTMP1, r1, 1);
+ __ vinserti128(YTMP5, YTMP5, XTMP1, 1);
+ // clear registers
+ __ vpxor(YTMP10, YTMP10, YTMP10, Assembler::AVX_256bit);
+ __ vpxor(YTMP6, YTMP6, YTMP6, Assembler::AVX_256bit);
+
+ // Calculate R^2
+ // a ← R
+ __ movq(a0, r0);
+ __ movq(a1, r1);
+ // a ← a * R = R^2
+ poly1305_multiply_scalar(a0, a1, a2,
+ r0, r1, c1, true,
+ t0, t1, t2, mulql, mulqh);
+ // Store R^2 in YTMP5, YTM6
+ __ movq(XTMP1, a0);
+ __ vpinsrq(XTMP1, XTMP1, a1, 1);
+ __ vinserti128(YTMP5, YTMP5, XTMP1, 0);
+ __ movq(XTMP1, a2);
+ __ vinserti128(YTMP6, YTMP6, XTMP1, 0);
+
+ // Calculate R^3
+ // a ← a * R = R^3
+ poly1305_multiply_scalar(a0, a1, a2,
+ r0, r1, c1, false,
+ t0, t1, t2, mulql, mulqh);
+ // Store R^3 in YTMP7, YTM2
+ __ movq(XTMP1, a0);
+ __ vpinsrq(XTMP1, XTMP1, a1, 1);
+ __ vinserti128(YTMP7, YTMP7, XTMP1, 1);
+ __ movq(XTMP1, a2);
+ __ vinserti128(YTMP2, YTMP2, XTMP1, 1);
+
+ // Calculate R^4
+ // a ← a * R = R^4
+ poly1305_multiply_scalar(a0, a1, a2,
+ r0, r1, c1, false,
+ t0, t1, t2, mulql, mulqh);
+ // Store R^4 in YTMP7, YTM2
+ __ movq(XTMP1, a0);
+ __ vpinsrq(XTMP1, XTMP1, a1, 1);
+ __ vinserti128(YTMP7, YTMP7, XTMP1, 0);
+ __ movq(XTMP1, a2);
+ __ vinserti128(YTMP2, YTMP2, XTMP1, 0);
+
+ // Interleave the powers of R^1..R^4 to form 44-bit limbs (half-empty)
+ __ vpunpckhqdq(YMM_R2, YTMP5, YTMP10, Assembler::AVX_256bit);
+ __ vpunpcklqdq(YMM_R0, YTMP5, YTMP10, Assembler::AVX_256bit);
+ __ vpunpckhqdq(YTMP3, YTMP7, YTMP10, Assembler::AVX_256bit);
+ __ vpunpcklqdq(YTMP4, YTMP7, YTMP10, Assembler::AVX_256bit);
+
+ __ vpslldq(YMM_R2, YMM_R2, 8, Assembler::AVX_256bit);
+ __ vpslldq(YTMP6, YTMP6, 8, Assembler::AVX_256bit);
+ __ vpslldq(YMM_R0, YMM_R0, 8, Assembler::AVX_256bit);
+ __ vpor(YMM_R2, YMM_R2, YTMP3, Assembler::AVX_256bit);
+ __ vpor(YMM_R0, YMM_R0, YTMP4, Assembler::AVX_256bit);
+ __ vpor(YTMP6, YTMP6, YTMP2, Assembler::AVX_256bit);
+ // Move 2 MSbits to top 24 bits, to be OR'ed later
+ __ vpsllq(YTMP6, YTMP6, 40, Assembler::AVX_256bit);
+
+ __ vpsrlq(YMM_R1, YMM_R0, 44, Assembler::AVX_256bit);
+ __ vpsllq(YTMP5, YMM_R2, 20, Assembler::AVX_256bit);
+ __ vpor(YMM_R1, YMM_R1, YTMP5, Assembler::AVX_256bit);
+ __ vpand(YMM_R1, YMM_R1, ExternalAddress(poly1305_mask44()), Assembler::AVX_256bit, t1);
+
+ __ vpand(YMM_R0, YMM_R0, ExternalAddress(poly1305_mask44()), Assembler::AVX_256bit, t1);
+ __ vpsrlq(YMM_R2, YMM_R2, 24, Assembler::AVX_256bit);
+
+ __ vpor(YMM_R2, YMM_R2, YTMP6, Assembler::AVX_256bit);
+ // YMM_R0, YMM_R1, YMM_R2 have the limbs of R^1, R^2, R^3, R^4
+
+ // Store R^4-R on stack for later use
+ int _r4_r1_save = 0;
+ __ vmovdqu(Address(rsp, _r4_r1_save + 0), YMM_R0);
+ __ vmovdqu(Address(rsp, _r4_r1_save + 32), YMM_R1);
+ __ vmovdqu(Address(rsp, _r4_r1_save + 32*2), YMM_R2);
+
+ // Broadcast 44-bit limbs of R^4
+ __ mov(t0, a0);
+ __ andq(t0, ExternalAddress(poly1305_mask44()), t1 /*rscratch*/); // First limb (R^4[43:0])
+ __ movq(YMM_R0, t0);
+ __ vpermq(YMM_R0, YMM_R0, 0x0, Assembler::AVX_256bit);
+
+ __ movq(t0, a1);
+ __ shrdq(a0, t0, 44);
+ __ andq(a0, ExternalAddress(poly1305_mask44()), t1 /*rscratch*/); // Second limb (R^4[87:44])
+ __ movq(YMM_R1, a0);
+ __ vpermq(YMM_R1, YMM_R1, 0x0, Assembler::AVX_256bit);
+
+ __ shrdq(a1, a2, 24);
+ __ andq(a1, ExternalAddress(poly1305_mask42()), t1 /*rscratch*/); // Third limb (R^4[129:88])
+ __ movq(YMM_R2, a1);
+ __ vpermq(YMM_R2, YMM_R2, 0x0, Assembler::AVX_256bit);
+ // YMM_R0, YMM_R1, YMM_R2 have the limbs of R^4, R^4, R^4, R^4
+
+ // Generate 4*5*R^4
+ // 4*R^4
+ __ vpsllq(YTMP1, YMM_R1, 2, Assembler::AVX_256bit);
+ __ vpsllq(YTMP2, YMM_R2, 2, Assembler::AVX_256bit);
+ // 5*R^4
+ __ vpaddq(YTMP1, YTMP1, YMM_R1, Assembler::AVX_256bit);
+ __ vpaddq(YTMP2, YTMP2, YMM_R2, Assembler::AVX_256bit);
+ // 4*5*R^4
+ __ vpsllq(YTMP1, YTMP1, 2, Assembler::AVX_256bit);
+ __ vpsllq(YTMP2, YTMP2, 2, Assembler::AVX_256bit);
+
+ //Store broadcasted R^4 and 4*5*R^4 on stack for later use
+ int _r4_save = 32*3;
+ int _r4p_save = 32*6;
+ __ vmovdqu(Address(rsp, _r4_save + 0), YMM_R0);
+ __ vmovdqu(Address(rsp, _r4_save + 32), YMM_R1);
+ __ vmovdqu(Address(rsp, _r4_save + 32*2), YMM_R2);
+ __ vmovdqu(Address(rsp, _r4p_save), YTMP1);
+ __ vmovdqu(Address(rsp, _r4p_save + 32), YTMP2);
+
+ // Get the number of multiples of 4 message blocks (64 bytes) for vectorization
+ __ movq(t0, length);
+ __ andq(t0, 0xffffffc0); // 0xffffffffffffffc0 after sign extension
+
+ // VECTOR LOOP: process 4 * 16-byte message blocks at a time
+ __ bind(L_process256Loop);
+ __ cmpl(t0, 16*4); //64 bytes (4 blocks at a time)
+ __ jcc(Assembler::belowEqual, L_process256LoopDone);
+
+ /*
+ Compute the following steps of POLY1305_EVAL_POLYNOMIAL algorithm
+ l' = floor(l/4)
+ for (i = 1 to l'-1):
+ T ← (R4444 ⊗ T) ⊕ COEF[i];
+ */
+
+ // Perform multiply and reduce while loading the next block and adding it in interleaved manner
+ // The logic to advance the SIMD loop counter (i.e. length -= 64) is inside the function below.
+ // The function below also includes the logic to load the next 4 blocks of data for efficient port utilization.
+ poly1305_msg_mul_reduce_vec4_avx2(YMM_ACC0, YMM_ACC1, YMM_ACC2,
+ Address(rsp, _r4_save + 0), Address(rsp, _r4_save + 32), Address(rsp, _r4_save + 32*2),
+ Address(rsp, _r4p_save), Address(rsp, _r4p_save + 32),
+ YTMP1, YTMP2, YTMP3, YTMP4, YTMP5, YTMP6,
+ YTMP7, YTMP8, YTMP9, YTMP10, YTMP11, YTMP12,
+ input, t0, t1 /*rscratch*/);
+ __ jmp(L_process256Loop);
+ // end of vector loop
+ __ bind(L_process256LoopDone);
+
+ /*
+ Compute the following steps of POLY1305_EVAL_POLYNOMIAL algorithm
+ T ← R4321 ⊗ T;
+ */
+
+ // Need to multiply by R^4, R^3, R^2, R
+ //Read R^4-R;
+ __ vmovdqu(YMM_R0, Address(rsp, _r4_r1_save + 0));
+ __ vmovdqu(YMM_R1, Address(rsp, _r4_r1_save + 32));
+ __ vmovdqu(YMM_R2, Address(rsp, _r4_r1_save + 32*2));
+
+ // Generate 4*5*[R^4..R^1] (ignore lowest limb)
+ // YTMP1 to have bits 87-44 of all 1-4th powers of R' in 4 qwords
+ // YTMP2 to have bits 129-88 of all 1-4th powers of R' in 4 qwords
+ __ vpsllq(YTMP10, YMM_R1, 2, Assembler::AVX_256bit);
+ __ vpaddq(YTMP1, YMM_R1, YTMP10, Assembler::AVX_256bit); //R1' (R1*5)
+ __ vpsllq(YTMP10, YMM_R2, 2, Assembler::AVX_256bit);
+ __ vpaddq(YTMP2, YMM_R2, YTMP10, Assembler::AVX_256bit); //R2' (R2*5)
+
+ // 4*5*R
+ __ vpsllq(YTMP1, YTMP1, 2, Assembler::AVX_256bit);
+ __ vpsllq(YTMP2, YTMP2, 2, Assembler::AVX_256bit);
+
+ poly1305_mul_reduce_vec4_avx2(YMM_ACC0, YMM_ACC1, YMM_ACC2,
+ YMM_R0, YMM_R1, YMM_R2, YTMP1, YTMP2,
+ YTMP3, YTMP4, YTMP5, YTMP6,
+ YTMP7, YTMP8, YTMP9, t1);
+ /*
+ Compute the following steps of POLY1305_EVAL_POLYNOMIAL algorithm
+ SUM ← T0 + T1 + T2 + T3;
+ */
+
+ // 4 -> 2 blocks
+ __ vextracti128(YTMP1, YMM_ACC0, 1);
+ __ vextracti128(YTMP2, YMM_ACC1, 1);
+ __ vextracti128(YTMP3, YMM_ACC2, 1);
+
+ __ vpaddq(YMM_ACC0, YMM_ACC0, YTMP1, Assembler::AVX_128bit);
+ __ vpaddq(YMM_ACC1, YMM_ACC1, YTMP2, Assembler::AVX_128bit);
+ __ vpaddq(YMM_ACC2, YMM_ACC2, YTMP3, Assembler::AVX_128bit);
+ // 2 -> 1 blocks
+ __ vpsrldq(YTMP1, YMM_ACC0, 8, Assembler::AVX_128bit);
+ __ vpsrldq(YTMP2, YMM_ACC1, 8, Assembler::AVX_128bit);
+ __ vpsrldq(YTMP3, YMM_ACC2, 8, Assembler::AVX_128bit);
+
+ // Finish folding
+ __ vpaddq(YMM_ACC0, YMM_ACC0, YTMP1, Assembler::AVX_128bit);
+ __ vpaddq(YMM_ACC1, YMM_ACC1, YTMP2, Assembler::AVX_128bit);
+ __ vpaddq(YMM_ACC2, YMM_ACC2, YTMP3, Assembler::AVX_128bit);
+
+ __ movq(YMM_ACC0, YMM_ACC0);
+ __ movq(YMM_ACC1, YMM_ACC1);
+ __ movq(YMM_ACC2, YMM_ACC2);
+
+ __ lea(input, Address(input,16*4));
+ __ andq(length, 63); // remaining bytes < length 64
+ // carry propagation
+ __ vpsrlq(YTMP1, YMM_ACC0, 44, Assembler::AVX_128bit);
+ __ vpand(YMM_ACC0, YMM_ACC0, ExternalAddress(poly1305_mask44()), Assembler::AVX_128bit, t1); // Clear top 20 bits
+ __ vpaddq(YMM_ACC1, YMM_ACC1, YTMP1, Assembler::AVX_128bit);
+ __ vpsrlq(YTMP1, YMM_ACC1, 44, Assembler::AVX_128bit);
+ __ vpand(YMM_ACC1, YMM_ACC1, ExternalAddress(poly1305_mask44()), Assembler::AVX_128bit, t1); // Clear top 20 bits
+ __ vpaddq(YMM_ACC2, YMM_ACC2, YTMP1, Assembler::AVX_128bit);
+ __ vpsrlq(YTMP1, YMM_ACC2, 42, Assembler::AVX_128bit);
+ __ vpand(YMM_ACC2, YMM_ACC2, ExternalAddress(poly1305_mask42()), Assembler::AVX_128bit, t1); // Clear top 20 bits
+ __ vpsllq(YTMP2, YTMP1, 2, Assembler::AVX_128bit);
+ __ vpaddq(YTMP1, YTMP1, YTMP2, Assembler::AVX_128bit);
+ __ vpaddq(YMM_ACC0, YMM_ACC0, YTMP1, Assembler::AVX_128bit);
+
+ // Put together A
+ __ movq(a0, YMM_ACC0);
+ __ movq(t0, YMM_ACC1);
+ __ movq(t1, t0);
+ __ shlq(t1, 44);
+ __ orq(a0, t1);
+ __ shrq(t0, 20);
+ __ movq(a2, YMM_ACC2);
+ __ movq(a1, a2);
+ __ shlq(a1, 24);
+ __ orq(a1, t0);
+ __ shrq(a2, 40);
+
+ // cleanup
+ __ vzeroall(); // clears all ymm registers (ymm0 through ymm15)
+
+ // SAFE DATA (clear powers of R)
+ __ vmovdqu(Address(rsp, _r4_r1_save + 0), YTMP1);
+ __ vmovdqu(Address(rsp, _r4_r1_save + 32), YTMP1);
+ __ vmovdqu(Address(rsp, _r4_r1_save + 32*2), YTMP1);
+ __ vmovdqu(Address(rsp, _r4_save + 0), YTMP1);
+ __ vmovdqu(Address(rsp, _r4_save + 32), YTMP1);
+ __ vmovdqu(Address(rsp, _r4_save + 32*2), YTMP1);
+ __ vmovdqu(Address(rsp, _r4p_save), YTMP1);
+ __ vmovdqu(Address(rsp, _r4p_save + 32), YTMP1);
+
+ // Save rbp and rsp; clear stack frame
+ __ movq(rsp, rbp);
+ __ pop(rbp);
+
+}
+
+// Compute component-wise product for 4 16-byte message blocks,
+// i.e. For each block, compute [a2 a1 a0] = [a2 a1 a0] x [r2 r1 r0]
+//
+// Each block/number is represented by 3 44-bit limb digits, start with multiplication
+//
+// a2 a1 a0
+// x r2 r1 r0
+// ----------------------------------
+// a2xr0 a1xr0 a0xr0
+// + a1xr1 a0xr1 5xa2xr1' (r1' = r1<<2)
+// + a0xr2 5xa2xr2' 5xa1xr2' (r2' = r2<<2)
+// ----------------------------------
+// p2 p1 p0
+//
+void StubGenerator::poly1305_mul_reduce_vec4_avx2(
+ const XMMRegister A0, const XMMRegister A1, const XMMRegister A2,
+ const XMMRegister R0, const XMMRegister R1, const XMMRegister R2,
+ const XMMRegister R1P, const XMMRegister R2P,
+ const XMMRegister P0L, const XMMRegister P0H,
+ const XMMRegister P1L, const XMMRegister P1H,
+ const XMMRegister P2L, const XMMRegister P2H,
+ const XMMRegister YTMP1, const Register rscratch)
+{
+ // Reset accumulator
+ __ vpxor(P0L, P0L, P0L, Assembler::AVX_256bit);
+ __ vpxor(P0H, P0H, P0H, Assembler::AVX_256bit);
+ __ vpxor(P1L, P1L, P1L, Assembler::AVX_256bit);
+ __ vpxor(P1H, P1H, P1H, Assembler::AVX_256bit);
+ __ vpxor(P2L, P2L, P2L, Assembler::AVX_256bit);
+ __ vpxor(P2H, P2H, P2H, Assembler::AVX_256bit);
+
+ // Calculate partial products
+ // p0 = a2xr1'
+ // p1 = a2xr2'
+ // p0 += a0xr0
+ __ vpmadd52luq(P0L, A2, R1P, Assembler::AVX_256bit);
+ __ vpmadd52huq(P0H, A2, R1P, Assembler::AVX_256bit);
+
+ __ vpmadd52luq(P1L, A2, R2P, Assembler::AVX_256bit);
+ __ vpmadd52huq(P1H, A2, R2P, Assembler::AVX_256bit);
+
+ __ vpmadd52luq(P0L, A0, R0, Assembler::AVX_256bit);
+ __ vpmadd52huq(P0H, A0, R0, Assembler::AVX_256bit);
+
+ // p2 = a2xr0
+ // p1 += a0xr1
+ // p0 += a1xr2'
+ // p2 += a0Xr2
+ __ vpmadd52luq(P2L, A2, R0, Assembler::AVX_256bit);
+ __ vpmadd52huq(P2H, A2, R0, Assembler::AVX_256bit);
+
+ __ vpmadd52luq(P1L, A0, R1, Assembler::AVX_256bit);
+ __ vpmadd52huq(P1H, A0, R1, Assembler::AVX_256bit);
+
+ __ vpmadd52luq(P0L, A1, R2P, Assembler::AVX_256bit);
+ __ vpmadd52huq(P0H, A1, R2P, Assembler::AVX_256bit);
+
+ __ vpmadd52luq(P2L, A0, R2, Assembler::AVX_256bit);
+ __ vpmadd52huq(P2H, A0, R2, Assembler::AVX_256bit);
+
+ // Carry propgation (first pass)
+ __ vpsrlq(YTMP1, P0L, 44, Assembler::AVX_256bit);
+ __ vpsllq(P0H, P0H, 8, Assembler::AVX_256bit);
+ __ vpmadd52luq(P1L, A1, R0, Assembler::AVX_256bit);
+ __ vpmadd52huq(P1H, A1, R0, Assembler::AVX_256bit);
+ // Carry propagation (first pass) - continue
+ __ vpand(A0, P0L, ExternalAddress(poly1305_mask44()), Assembler::AVX_256bit, rscratch); // Clear top 20 bits
+ __ vpaddq(P0H, P0H, YTMP1, Assembler::AVX_256bit);
+ __ vpmadd52luq(P2L, A1, R1, Assembler::AVX_256bit);
+ __ vpmadd52huq(P2H, A1, R1, Assembler::AVX_256bit);
+
+ // Carry propagation (first pass) - continue 2
+ __ vpaddq(P1L, P1L, P0H, Assembler::AVX_256bit);
+ __ vpsllq(P1H, P1H, 8, Assembler::AVX_256bit);
+ __ vpsrlq(YTMP1, P1L, 44, Assembler::AVX_256bit);
+ __ vpand(A1, P1L, ExternalAddress(poly1305_mask44()), Assembler::AVX_256bit, rscratch); // Clear top 20 bits
+
+ __ vpaddq(P2L, P2L, P1H, Assembler::AVX_256bit);
+ __ vpaddq(P2L, P2L, YTMP1, Assembler::AVX_256bit);
+ __ vpand(A2, P2L, ExternalAddress(poly1305_mask42()), Assembler::AVX_256bit, rscratch); // Clear top 22 bits
+ __ vpsrlq(YTMP1, P2L, 42, Assembler::AVX_256bit);
+ __ vpsllq(P2H, P2H, 10, Assembler::AVX_256bit);
+ __ vpaddq(P2H, P2H, YTMP1, Assembler::AVX_256bit);
+
+ // Carry propagation (second pass)
+ // Multiply by 5 the highest bits (above 130 bits)
+ __ vpaddq(A0, A0, P2H, Assembler::AVX_256bit);
+ __ vpsllq(P2H, P2H, 2, Assembler::AVX_256bit);
+ __ vpaddq(A0, A0, P2H, Assembler::AVX_256bit);
+
+ __ vpsrlq(YTMP1, A0, 44, Assembler::AVX_256bit);
+ __ vpand(A0, A0, ExternalAddress(poly1305_mask44()), Assembler::AVX_256bit, rscratch); // Clear top 20 bits
+ __ vpaddq(A1, A1, YTMP1, Assembler::AVX_256bit);
+}
+
+// Compute component-wise product for 4 16-byte message blocks and adds the next 4 blocks
+// i.e. For each block, compute [a2 a1 a0] = [a2 a1 a0] x [r2 r1 r0],
+// followed by [a2 a1 a0] += [n2 n1 n0], where n contains the next 4 blocks of the message.
+//
+// Each block/number is represented by 3 44-bit limb digits, start with multiplication
+//
+// a2 a1 a0
+// x r2 r1 r0
+// ----------------------------------
+// a2xr0 a1xr0 a0xr0
+// + a1xr1 a0xr1 5xa2xr1' (r1' = r1<<2)
+// + a0xr2 5xa2xr2' 5xa1xr2' (r2' = r2<<2)
+// ----------------------------------
+// p2 p1 p0
+//
+void StubGenerator::poly1305_msg_mul_reduce_vec4_avx2(
+ const XMMRegister A0, const XMMRegister A1, const XMMRegister A2,
+ const Address R0, const Address R1, const Address R2,
+ const Address R1P, const Address R2P,
+ const XMMRegister P0L, const XMMRegister P0H,
+ const XMMRegister P1L, const XMMRegister P1H,
+ const XMMRegister P2L, const XMMRegister P2H,
+ const XMMRegister YTMP1, const XMMRegister YTMP2,
+ const XMMRegister YTMP3, const XMMRegister YTMP4,
+ const XMMRegister YTMP5, const XMMRegister YTMP6,
+ const Register input, const Register length, const Register rscratch)
+{
+ // Reset accumulator
+ __ vpxor(P0L, P0L, P0L, Assembler::AVX_256bit);
+ __ vpxor(P0H, P0H, P0H, Assembler::AVX_256bit);
+ __ vpxor(P1L, P1L, P1L, Assembler::AVX_256bit);
+ __ vpxor(P1H, P1H, P1H, Assembler::AVX_256bit);
+ __ vpxor(P2L, P2L, P2L, Assembler::AVX_256bit);
+ __ vpxor(P2H, P2H, P2H, Assembler::AVX_256bit);
+
+ // Calculate partial products
+ // p0 = a2xr1'
+ // p1 = a2xr2'
+ // p2 = a2xr0
+ __ vpmadd52luq(P0L, A2, R1P, Assembler::AVX_256bit);
+ __ vpmadd52huq(P0H, A2, R1P, Assembler::AVX_256bit);
+ // Interleave input loading with hash computation
+ __ lea(input, Address(input,16*4));
+ __ subl(length, 16*4);
+ __ vpmadd52luq(P1L, A2, R2P, Assembler::AVX_256bit);
+ __ vpmadd52huq(P1H, A2, R2P, Assembler::AVX_256bit);
+ // Load next block of data (64 bytes)
+ __ vmovdqu(YTMP1, Address(input, 0));
+ __ vmovdqu(YTMP2, Address(input, 32));
+ // interleave new blocks of data
+ __ vpunpckhqdq(YTMP3, YTMP1, YTMP2, Assembler::AVX_256bit);
+ __ vpunpcklqdq(YTMP1, YTMP1, YTMP2, Assembler::AVX_256bit);
+ __ vpmadd52luq(P0L, A0, R0, Assembler::AVX_256bit);
+ __ vpmadd52huq(P0H, A0, R0, Assembler::AVX_256bit);
+ // Highest 42-bit limbs of new blocks
+ __ vpsrlq(YTMP6, YTMP3, 24, Assembler::AVX_256bit);
+ __ vpor(YTMP6, YTMP6, ExternalAddress(poly1305_pad_msg()), Assembler::AVX_256bit, rscratch);
+
+ //Middle 44-bit limbs of new blocks
+ __ vpsrlq(YTMP2, YTMP1, 44, Assembler::AVX_256bit);
+ __ vpsllq(YTMP4, YTMP3, 20, Assembler::AVX_256bit);
+ // p2 = a2xr0
+ __ vpmadd52luq(P2L, A2, R0, Assembler::AVX_256bit);
+ __ vpmadd52huq(P2H, A2, R0, Assembler::AVX_256bit);
+ __ vpor(YTMP2, YTMP2, YTMP4, Assembler::AVX_256bit);
+ __ vpand(YTMP2, YTMP2, ExternalAddress(poly1305_mask44()), Assembler::AVX_256bit, rscratch);
+ // Lowest 44-bit limbs of new blocks
+ __ vpand(YTMP1, YTMP1, ExternalAddress(poly1305_mask44()), Assembler::AVX_256bit, rscratch);
+
+ __ vpmadd52luq(P1L, A0, R1, Assembler::AVX_256bit);
+ __ vpmadd52huq(P1H, A0, R1, Assembler::AVX_256bit);
+ __ vpmadd52luq(P0L, A1, R2P, Assembler::AVX_256bit);
+ __ vpmadd52huq(P0H, A1, R2P, Assembler::AVX_256bit);
+ __ vpmadd52luq(P2L, A0, R2, Assembler::AVX_256bit);
+ __ vpmadd52huq(P2H, A0, R2, Assembler::AVX_256bit);
+
+ // Carry propgation (first pass)
+ __ vpsrlq(YTMP5, P0L, 44, Assembler::AVX_256bit);
+ __ vpsllq(P0H, P0H, 8, Assembler::AVX_256bit);
+ __ vpmadd52luq(P1L, A1, R0, Assembler::AVX_256bit);
+ __ vpmadd52huq(P1H, A1, R0, Assembler::AVX_256bit);
+ // Carry propagation (first pass) - continue
+ __ vpand(A0, P0L, ExternalAddress(poly1305_mask44()), Assembler::AVX_256bit, rscratch); // Clear top 20 bits
+ __ vpaddq(P0H, P0H, YTMP5, Assembler::AVX_256bit);
+ __ vpmadd52luq(P2L, A1, R1, Assembler::AVX_256bit);
+ __ vpmadd52huq(P2H, A1, R1, Assembler::AVX_256bit);
+
+ // Carry propagation (first pass) - continue 2
+ __ vpaddq(P1L, P1L, P0H, Assembler::AVX_256bit);
+ __ vpsllq(P1H, P1H, 8, Assembler::AVX_256bit);
+ __ vpsrlq(YTMP5, P1L, 44, Assembler::AVX_256bit);
+ __ vpand(A1, P1L, ExternalAddress(poly1305_mask44()), Assembler::AVX_256bit, rscratch); // Clear top 20 bits
+
+ __ vpaddq(P2L, P2L, P1H, Assembler::AVX_256bit);
+ __ vpaddq(P2L, P2L, YTMP5, Assembler::AVX_256bit);
+ __ vpand(A2, P2L, ExternalAddress(poly1305_mask42()), Assembler::AVX_256bit, rscratch); // Clear top 22 bits
+ __ vpaddq(A2, A2, YTMP6, Assembler::AVX_256bit); // Add highest bits from new blocks to accumulator
+ __ vpsrlq(YTMP5, P2L, 42, Assembler::AVX_256bit);
+ __ vpsllq(P2H, P2H, 10, Assembler::AVX_256bit);
+ __ vpaddq(P2H, P2H, YTMP5, Assembler::AVX_256bit);
+
+ // Carry propagation (second pass)
+ // Multiply by 5 the highest bits (above 130 bits)
+ __ vpaddq(A0, A0, P2H, Assembler::AVX_256bit);
+ __ vpsllq(P2H, P2H, 2, Assembler::AVX_256bit);
+ __ vpaddq(A0, A0, P2H, Assembler::AVX_256bit);
+
+ __ vpsrlq(YTMP5, A0, 44, Assembler::AVX_256bit);
+ __ vpand(A0, A0, ExternalAddress(poly1305_mask44()), Assembler::AVX_256bit, rscratch); // Clear top 20 bits
+ __ vpaddq(A0, A0, YTMP1, Assembler::AVX_256bit); //Add low 42-bit bits from new blocks to accumulator
+ __ vpaddq(A1, A1, YTMP2, Assembler::AVX_256bit); //Add medium 42-bit bits from new blocks to accumulator
+ __ vpaddq(A1, A1, YTMP5, Assembler::AVX_256bit);
+}
diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp
index cfe613de5b5..3b8ead6254e 100644
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp
@@ -294,7 +294,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ movl(rax, 7);
__ cmpl(rax, Address(rbp, in_bytes(VM_Version::std_cpuid0_offset()))); // Is cpuid(0x7) supported?
__ jccb(Assembler::greater, ext_cpuid);
-
+ // ECX = 0
__ xorl(rcx, rcx);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset())));
@@ -303,6 +303,13 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi, 12), rdx);
+ // ECX = 1
+ __ movl(rax, 7);
+ __ movl(rcx, 1);
+ __ cpuid();
+ __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_ecx1_offset())));
+ __ movl(Address(rsi, 0), rax);
+
//
// Extended cpuid(0x80000000)
//
@@ -958,8 +965,10 @@ void VM_Version::get_processor_features() {
_features &= ~CPU_AVX512_IFMA;
}
- if (UseAVX < 2)
+ if (UseAVX < 2) {
_features &= ~CPU_AVX2;
+ _features &= ~CPU_AVX_IFMA;
+ }
if (UseAVX < 1) {
_features &= ~CPU_AVX;
@@ -989,6 +998,7 @@ void VM_Version::get_processor_features() {
_features &= ~CPU_GFNI;
_features &= ~CPU_AVX512_BITALG;
_features &= ~CPU_AVX512_IFMA;
+ _features &= ~CPU_AVX_IFMA;
}
}
@@ -1345,7 +1355,7 @@ void VM_Version::get_processor_features() {
#endif // COMPILER2 && ASSERT
#ifdef _LP64
- if (supports_avx512ifma() && supports_avx512vlbw() && MaxVectorSize >= 64) {
+ if ((supports_avx512ifma() && supports_avx512vlbw()) || supports_avxifma()) {
if (FLAG_IS_DEFAULT(UsePoly1305Intrinsics)) {
FLAG_SET_DEFAULT(UsePoly1305Intrinsics, true);
}
@@ -2936,8 +2946,11 @@ uint64_t VM_Version::CpuidInfo::feature_flags() const {
result |= CPU_VZEROUPPER;
if (std_cpuid1_ecx.bits.f16c != 0)
result |= CPU_F16C;
- if (sef_cpuid7_ebx.bits.avx2 != 0)
+ if (sef_cpuid7_ebx.bits.avx2 != 0) {
result |= CPU_AVX2;
+ if (sef_cpuid7_ecx1_eax.bits.avx_ifma != 0)
+ result |= CPU_AVX_IFMA;
+ }
if (sef_cpuid7_ebx.bits.avx512f != 0 &&
xem_xcr0_eax.bits.opmask != 0 &&
xem_xcr0_eax.bits.zmm512 != 0 &&
diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp
index 03596a6e446..845b8a7e24d 100644
--- a/src/hotspot/cpu/x86/vm_version_x86.hpp
+++ b/src/hotspot/cpu/x86/vm_version_x86.hpp
@@ -279,6 +279,15 @@ class VM_Version : public Abstract_VM_Version {
} bits;
};
+ union SefCpuid7Ecx1Eax {
+ uint32_t value;
+ struct {
+ uint32_t : 23,
+ avx_ifma : 1,
+ : 8;
+ } bits;
+ };
+
union ExtCpuid1EEbx {
uint32_t value;
struct {
@@ -390,7 +399,8 @@ class VM_Version : public Abstract_VM_Version {
decl(OSPKE, "ospke", 55) /* OS enables protection keys */ \
decl(CET_IBT, "cet_ibt", 56) /* Control Flow Enforcement - Indirect Branch Tracking */ \
decl(CET_SS, "cet_ss", 57) /* Control Flow Enforcement - Shadow Stack */ \
- decl(AVX512_IFMA, "avx512_ifma", 58) /* Integer Vector FMA instructions*/
+ decl(AVX512_IFMA, "avx512_ifma", 58) /* Integer Vector FMA instructions*/ \
+ decl(AVX_IFMA, "avx_ifma", 59) /* 256-bit VEX-coded variant of AVX512-IFMA*/
#define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (1ULL << bit),
CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG)
@@ -449,10 +459,13 @@ class VM_Version : public Abstract_VM_Version {
uint32_t dcp_cpuid4_edx; // unused currently
// cpuid function 7 (structured extended features)
+ // ECX = 0 before calling cpuid()
SefCpuid7Eax sef_cpuid7_eax;
SefCpuid7Ebx sef_cpuid7_ebx;
SefCpuid7Ecx sef_cpuid7_ecx;
SefCpuid7Edx sef_cpuid7_edx;
+ // ECX = 1 before calling cpuid()
+ SefCpuid7Ecx1Eax sef_cpuid7_ecx1_eax;
// cpuid function 0xB (processor topology)
// ecx = 0
@@ -571,6 +584,7 @@ class VM_Version : public Abstract_VM_Version {
static ByteSize std_cpuid1_offset() { return byte_offset_of(CpuidInfo, std_cpuid1_eax); }
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 sef_cpuid7_ecx1_offset() { return byte_offset_of(CpuidInfo, sef_cpuid7_ecx1_eax); }
static ByteSize ext_cpuid1_offset() { return byte_offset_of(CpuidInfo, ext_cpuid1_eax); }
static ByteSize ext_cpuid5_offset() { return byte_offset_of(CpuidInfo, ext_cpuid5_eax); }
static ByteSize ext_cpuid7_offset() { return byte_offset_of(CpuidInfo, ext_cpuid7_eax); }
@@ -677,6 +691,7 @@ class VM_Version : public Abstract_VM_Version {
static bool supports_evex() { return (_features & CPU_AVX512F) != 0; }
static bool supports_avx512dq() { return (_features & CPU_AVX512DQ) != 0; }
static bool supports_avx512ifma() { return (_features & CPU_AVX512_IFMA) != 0; }
+ static bool supports_avxifma() { return (_features & CPU_AVX_IFMA) != 0; }
static bool supports_avx512pf() { return (_features & CPU_AVX512PF) != 0; }
static bool supports_avx512er() { return (_features & CPU_AVX512ER) != 0; }
static bool supports_avx512cd() { return (_features & CPU_AVX512CD) != 0; }
diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad
index 8e5ee96172a..9c21d1abff5 100644
--- a/src/hotspot/cpu/x86/x86.ad
+++ b/src/hotspot/cpu/x86/x86.ad
@@ -3908,22 +3908,14 @@ instruct roundD_reg(legRegD dst, legRegD src, immU8 rmode) %{
ins_cost(150);
ins_encode %{
assert(UseSSE >= 4, "required");
+ if ((UseAVX == 0) && ($dst$$XMMRegister != $src$$XMMRegister)) {
+ __ pxor($dst$$XMMRegister, $dst$$XMMRegister);
+ }
__ roundsd($dst$$XMMRegister, $src$$XMMRegister, $rmode$$constant);
%}
ins_pipe(pipe_slow);
%}
-instruct roundD_mem(legRegD dst, memory src, immU8 rmode) %{
- match(Set dst (RoundDoubleMode (LoadD src) rmode));
- format %{ "roundsd $dst,$src" %}
- ins_cost(150);
- ins_encode %{
- assert(UseSSE >= 4, "required");
- __ roundsd($dst$$XMMRegister, $src$$Address, $rmode$$constant);
- %}
- ins_pipe(pipe_slow);
-%}
-
instruct roundD_imm(legRegD dst, immD con, immU8 rmode) %{
match(Set dst (RoundDoubleMode con rmode));
format %{ "roundsd $dst,[$constantaddress]\t# load from constant table: double=$con" %}
diff --git a/src/hotspot/os/aix/globals_aix.hpp b/src/hotspot/os/aix/globals_aix.hpp
index fb353348a53..6904bf9dc45 100644
--- a/src/hotspot/os/aix/globals_aix.hpp
+++ b/src/hotspot/os/aix/globals_aix.hpp
@@ -66,12 +66,6 @@
product(bool, Use64KPages, true, \
"Use 64K pages if available.") \
\
- /* If VM uses 64K paged memory (shmat) for virtual memory: threshold below */ \
- /* which virtual memory allocations are done with 4K memory (mmap). This is */ \
- /* mainly for test purposes. */ \
- develop(uintx, Use64KPagesThreshold, 0, \
- "4K/64K page allocation threshold.") \
- \
/* Normally AIX commits memory on touch, but sometimes it is helpful to have */ \
/* explicit commit behaviour. This flag, if true, causes the VM to touch */ \
/* memory on os::commit_memory() (which normally is a noop). */ \
diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp
index f6312f2f882..4885675a6a1 100644
--- a/src/hotspot/os/aix/os_aix.cpp
+++ b/src/hotspot/os/aix/os_aix.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2023 SAP SE. All rights reserved.
+ * Copyright (c) 2012, 2024 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
@@ -84,9 +84,7 @@
#endif
// put OS-includes here (sorted alphabetically)
-#ifdef AIX_XLC_GE_17
#include
-#endif
#include
#include
#include
@@ -1972,11 +1970,7 @@ char* os::pd_reserve_memory(size_t bytes, bool exec) {
if (os::vm_page_size() == 4*K) {
return reserve_mmaped_memory(bytes, nullptr /* requested_addr */);
} else {
- if (bytes >= Use64KPagesThreshold) {
- return reserve_shmated_memory(bytes, nullptr /* requested_addr */);
- } else {
- return reserve_mmaped_memory(bytes, nullptr /* requested_addr */);
- }
+ return reserve_shmated_memory(bytes, nullptr /* requested_addr */);
}
}
@@ -2185,11 +2179,7 @@ char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, bool
if (os::vm_page_size() == 4*K) {
return reserve_mmaped_memory(bytes, requested_addr);
} else {
- if (bytes >= Use64KPagesThreshold) {
- return reserve_shmated_memory(bytes, requested_addr);
- } else {
- return reserve_mmaped_memory(bytes, requested_addr);
- }
+ return reserve_shmated_memory(bytes, requested_addr);
}
return addr;
diff --git a/src/hotspot/os/bsd/os_perf_bsd.cpp b/src/hotspot/os/bsd/os_perf_bsd.cpp
index f91dfa87f07..631d2135b64 100644
--- a/src/hotspot/os/bsd/os_perf_bsd.cpp
+++ b/src/hotspot/os/bsd/os_perf_bsd.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024, 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,6 +39,7 @@
#include
#include
#include
+ #include
#endif
static const double NANOS_PER_SEC = 1000000000.0;
@@ -47,10 +48,10 @@ class CPUPerformanceInterface::CPUPerformance : public CHeapObj {
friend class CPUPerformanceInterface;
private:
#ifdef __APPLE__
- uint64_t _total_cpu_nanos;
+ uint64_t _jvm_real;
uint64_t _total_csr_nanos;
- uint64_t _jvm_user_nanos;
- uint64_t _jvm_system_nanos;
+ uint64_t _jvm_user;
+ uint64_t _jvm_system;
long _jvm_context_switches;
long _used_ticks;
long _total_ticks;
@@ -86,11 +87,11 @@ class CPUPerformanceInterface::CPUPerformance : public CHeapObj {
CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
#ifdef __APPLE__
- _total_cpu_nanos= 0;
+ _jvm_real = 0;
_total_csr_nanos= 0;
_jvm_context_switches = 0;
- _jvm_user_nanos = 0;
- _jvm_system_nanos = 0;
+ _jvm_user = 0;
+ _jvm_system = 0;
_used_ticks = 0;
_total_ticks = 0;
_active_processor_count = 0;
@@ -152,42 +153,35 @@ int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_
int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
#ifdef __APPLE__
int result = cpu_load_total_process(psystemTotalLoad);
- mach_port_t task = mach_task_self();
- mach_msg_type_number_t task_info_count = TASK_INFO_MAX;
- task_info_data_t task_info_data;
- kern_return_t kr = task_info(task, TASK_ABSOLUTETIME_INFO, (task_info_t)task_info_data, &task_info_count);
- if (kr != KERN_SUCCESS) {
+
+ struct tms buf;
+ clock_t jvm_real = times(&buf);
+ if (jvm_real == (clock_t) (-1)) {
return OS_ERR;
}
- task_absolutetime_info_t absolutetime_info = (task_absolutetime_info_t)task_info_data;
int active_processor_count = os::active_processor_count();
- uint64_t jvm_user_nanos = absolutetime_info->total_user;
- uint64_t jvm_system_nanos = absolutetime_info->total_system;
-
- uint64_t total_cpu_nanos;
- if(!now_in_nanos(&total_cpu_nanos)) {
- return OS_ERR;
- }
+ uint64_t jvm_user = buf.tms_utime;
+ uint64_t jvm_system = buf.tms_stime;
- if (_total_cpu_nanos == 0 || active_processor_count != _active_processor_count) {
- // First call or change in active processor count
+ if (active_processor_count != _active_processor_count) {
+ // Change in active processor count
result = OS_ERR;
} else {
- uint64_t delta_nanos = active_processor_count * (total_cpu_nanos - _total_cpu_nanos);
- if (delta_nanos == 0) {
+ uint64_t delta = active_processor_count * (jvm_real - _jvm_real);
+ if (delta == 0) {
// Avoid division by zero
return OS_ERR;
}
- *pjvmUserLoad = normalize((double)(jvm_user_nanos - _jvm_user_nanos)/delta_nanos);
- *pjvmKernelLoad = normalize((double)(jvm_system_nanos - _jvm_system_nanos)/delta_nanos);
+ *pjvmUserLoad = normalize((double)(jvm_user - _jvm_user) / delta);
+ *pjvmKernelLoad = normalize((double)(jvm_system - _jvm_system) / delta);
}
_active_processor_count = active_processor_count;
- _total_cpu_nanos = total_cpu_nanos;
- _jvm_user_nanos = jvm_user_nanos;
- _jvm_system_nanos = jvm_system_nanos;
+ _jvm_real = jvm_real;
+ _jvm_user = jvm_user;
+ _jvm_system = jvm_system;
return result;
#else
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 c7d61b33829..5c72b64b629 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
@@ -244,17 +244,21 @@ void VM_Version::rivos_features() {
ext_Zfh.enable_feature();
- ext_Zacas.enable_feature();
ext_Zicboz.enable_feature();
ext_Zicsr.enable_feature();
ext_Zifencei.enable_feature();
ext_Zic64b.enable_feature();
ext_Ztso.enable_feature();
- ext_Zihintpause.enable_feature();
+
+ ext_Zvfh.enable_feature();
unaligned_access.enable_feature(MISALIGNED_FAST);
satp_mode.enable_feature(VM_SV48);
// Features dependent on march/mimpid.
// I.e. march.value() and mimplid.value()
+ if (mimpid.value() > 0x100) {
+ ext_Zacas.enable_feature();
+ ext_Zihintpause.enable_feature();
+ }
}
diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp
index 31ee0103331..8261197a969 100644
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2024, 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
@@ -207,9 +207,11 @@ void LIRItem::set_result(LIR_Opr opr) {
assert(value()->operand()->is_illegal() || value()->operand()->is_constant(), "operand should never change");
value()->set_operand(opr);
+#ifdef ASSERT
if (opr->is_virtual()) {
_gen->_instruction_for_operand.at_put_grow(opr->vreg_number(), value(), nullptr);
}
+#endif
_result = opr;
}
@@ -1529,28 +1531,22 @@ LIR_Opr LIRGenerator::operand_for_instruction(Instruction* x) {
assert(x->as_Phi() || x->as_Local() != nullptr, "only for Phi and Local");
// allocate a virtual register for this local or phi
x->set_operand(rlock(x));
+#ifdef ASSERT
_instruction_for_operand.at_put_grow(x->operand()->vreg_number(), x, nullptr);
+#endif
}
}
return x->operand();
}
-
-Instruction* LIRGenerator::instruction_for_opr(LIR_Opr opr) {
- if (opr->is_virtual()) {
- return instruction_for_vreg(opr->vreg_number());
- }
- return nullptr;
-}
-
-
+#ifdef ASSERT
Instruction* LIRGenerator::instruction_for_vreg(int reg_num) {
if (reg_num < _instruction_for_operand.length()) {
return _instruction_for_operand.at(reg_num);
}
return nullptr;
}
-
+#endif
void LIRGenerator::set_vreg_flag(int vreg_num, VregFlag f) {
if (_vreg_flags.size_in_bits() == 0) {
@@ -3072,7 +3068,9 @@ void LIRGenerator::do_Base(Base* x) {
assert(as_ValueType(t)->tag() == local->type()->tag(), "check");
#endif // __SOFTFP__
local->set_operand(dest);
+#ifdef ASSERT
_instruction_for_operand.at_put_grow(dest->vreg_number(), local, nullptr);
+#endif
java_index += type2size[t];
}
diff --git a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp
index 99fd4d7c995..16c1cd33a25 100644
--- a/src/hotspot/share/c1/c1_LIRGenerator.hpp
+++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2024, 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
@@ -166,7 +166,9 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
PhiResolverState _resolver_state;
BlockBegin* _block;
int _virtual_register_number;
+#ifdef ASSERT
Values _instruction_for_operand;
+#endif
BitMap2D _vreg_flags; // flags which can be set on a per-vreg basis
LIR_List* _lir;
bool _in_conditional_code;
@@ -226,9 +228,11 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
assert(!opr->is_register() || opr->is_virtual(), "should never set result to a physical register");
x->set_operand(opr);
assert(opr == x->operand(), "must be");
+#ifdef ASSERT
if (opr->is_virtual()) {
_instruction_for_operand.at_put_grow(opr->vreg_number(), x, nullptr);
}
+#endif
}
void set_no_result(Value x) { assert(!x->has_uses(), "can't have use"); x->clear_operand(); }
@@ -529,9 +533,10 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
, _barrier_set(BarrierSet::barrier_set()->barrier_set_c1()) {
}
+#ifdef ASSERT
// for virtual registers, maps them back to Phi's or Local's
- Instruction* instruction_for_opr(LIR_Opr opr);
Instruction* instruction_for_vreg(int reg_num);
+#endif
void set_vreg_flag (int vreg_num, VregFlag f);
bool is_vreg_flag_set(int vreg_num, VregFlag f);
diff --git a/src/hotspot/share/cds/archiveHeapLoader.cpp b/src/hotspot/share/cds/archiveHeapLoader.cpp
index b5af9fec573..fe30be16427 100644
--- a/src/hotspot/share/cds/archiveHeapLoader.cpp
+++ b/src/hotspot/share/cds/archiveHeapLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, 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
@@ -88,7 +88,7 @@ void ArchiveHeapLoader::fixup_region() {
fill_failed_loaded_heap();
}
if (is_in_use()) {
- if (!CDSConfig::is_loading_full_module_graph()) {
+ if (!CDSConfig::is_using_full_module_graph()) {
// Need to remove all the archived java.lang.Module objects from HeapShared::roots().
ClassLoaderDataShared::clear_archived_oops();
}
@@ -164,18 +164,19 @@ void ArchiveHeapLoader::patch_compressed_embedded_pointers(BitMapView bm,
// Optimization: if dumptime shift is the same as runtime shift, we can perform a
// quick conversion from "dumptime narrowOop" -> "runtime narrowOop".
+ narrowOop* patching_start = (narrowOop*)region.start() + FileMapInfo::current_info()->heap_oopmap_start_pos();
if (_narrow_oop_shift == CompressedOops::shift()) {
uint32_t quick_delta = (uint32_t)rt_encoded_bottom - (uint32_t)dt_encoded_bottom;
log_info(cds)("CDS heap data relocation quick delta = 0x%x", quick_delta);
if (quick_delta == 0) {
log_info(cds)("CDS heap data relocation unnecessary, quick_delta = 0");
} else {
- PatchCompressedEmbeddedPointersQuick patcher((narrowOop*)region.start(), quick_delta);
+ PatchCompressedEmbeddedPointersQuick patcher(patching_start, quick_delta);
bm.iterate(&patcher);
}
} else {
log_info(cds)("CDS heap data quick relocation not possible");
- PatchCompressedEmbeddedPointers patcher((narrowOop*)region.start());
+ PatchCompressedEmbeddedPointers patcher(patching_start);
bm.iterate(&patcher);
}
}
@@ -186,17 +187,10 @@ void ArchiveHeapLoader::patch_embedded_pointers(FileMapInfo* info,
MemRegion region, address oopmap,
size_t oopmap_size_in_bits) {
BitMapView bm((BitMap::bm_word_t*)oopmap, oopmap_size_in_bits);
-
-#ifndef PRODUCT
- ResourceMark rm;
- ResourceBitMap checkBm = HeapShared::calculate_oopmap(region);
- assert(bm.is_same(checkBm), "sanity");
-#endif
-
if (UseCompressedOops) {
patch_compressed_embedded_pointers(bm, info, region);
} else {
- PatchUncompressedEmbeddedPointers patcher((oop*)region.start());
+ PatchUncompressedEmbeddedPointers patcher((oop*)region.start() + FileMapInfo::current_info()->heap_oopmap_start_pos());
bm.iterate(&patcher);
}
}
@@ -316,7 +310,7 @@ bool ArchiveHeapLoader::load_heap_region_impl(FileMapInfo* mapinfo, LoadedArchiv
uintptr_t oopmap = bitmap_base + r->oopmap_offset();
BitMapView bm((BitMap::bm_word_t*)oopmap, r->oopmap_size_in_bits());
- PatchLoadedRegionPointers patcher((narrowOop*)load_address, loaded_region);
+ PatchLoadedRegionPointers patcher((narrowOop*)load_address + FileMapInfo::current_info()->heap_oopmap_start_pos(), loaded_region);
bm.iterate(&patcher);
return true;
}
@@ -449,7 +443,7 @@ void ArchiveHeapLoader::patch_native_pointers() {
if (r->mapped_base() != nullptr && r->has_ptrmap()) {
log_info(cds, heap)("Patching native pointers in heap region");
BitMapView bm = r->ptrmap_view();
- PatchNativePointers patcher((Metadata**)r->mapped_base());
+ PatchNativePointers patcher((Metadata**)r->mapped_base() + FileMapInfo::current_info()->heap_ptrmap_start_pos());
bm.iterate(&patcher);
}
}
diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp
index 2f18838bb9b..098019b1788 100644
--- a/src/hotspot/share/cds/archiveHeapWriter.cpp
+++ b/src/hotspot/share/cds/archiveHeapWriter.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 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,6 +62,7 @@ address ArchiveHeapWriter::_requested_top;
GrowableArrayCHeap* ArchiveHeapWriter::_native_pointers;
GrowableArrayCHeap* ArchiveHeapWriter::_source_objs;
+GrowableArrayCHeap* ArchiveHeapWriter::_source_objs_order;
ArchiveHeapWriter::BufferOffsetToSourceObjectTable*
ArchiveHeapWriter::_buffer_offset_to_source_obj_table = nullptr;
@@ -72,6 +73,7 @@ typedef ResourceHashtable FillersTable;
static FillersTable* _fillers;
+static int _num_native_ptrs = 0;
void ArchiveHeapWriter::init() {
if (HeapShared::can_write()) {
@@ -84,6 +86,7 @@ void ArchiveHeapWriter::init() {
_native_pointers = new GrowableArrayCHeap(2048);
_source_objs = new GrowableArrayCHeap(10000);
+ _source_objs_order = new GrowableArrayCHeap(10000);
guarantee(UseG1GC, "implementation limitation");
guarantee(MIN_GC_REGION_ALIGNMENT <= /*G1*/HeapRegion::min_region_size_in_words() * HeapWordSize, "must be");
@@ -91,6 +94,7 @@ void ArchiveHeapWriter::init() {
}
void ArchiveHeapWriter::add_source_obj(oop src_obj) {
+ _source_objs_order->append(_source_objs->length());
_source_objs->append(src_obj);
}
@@ -226,9 +230,54 @@ void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeapat(*a);
+ oop ob = _source_objs->at(*b);
+
+ int rank_a = oop_sorting_rank(oa);
+ int rank_b = oop_sorting_rank(ob);
+
+ if (rank_a != rank_b) {
+ return rank_a - rank_b;
+ } else {
+ // If they are the same rank, sort them by their position in the _source_objs array
+ return *a - *b;
+ }
+}
+
+void ArchiveHeapWriter::sort_source_objs() {
+ _source_objs_order->sort(compare_objs_by_oop_fields);
+}
+
void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeap* roots) {
- for (int i = 0; i < _source_objs->length(); i++) {
- oop src_obj = _source_objs->at(i);
+ sort_source_objs();
+ for (int i = 0; i < _source_objs_order->length(); i++) {
+ int src_obj_index = _source_objs_order->at(i);
+ oop src_obj = _source_objs->at(src_obj_index);
HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(src_obj);
assert(info != nullptr, "must be");
size_t buffer_offset = copy_one_source_obj_to_buffer(src_obj);
@@ -239,8 +288,8 @@ void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeaplength() + 1, roots->length());
+ log_info(cds)("Size of heap region = " SIZE_FORMAT " bytes, %d objects, %d roots, %d native ptrs",
+ _buffer_used, _source_objs->length() + 1, roots->length(), _num_native_ptrs);
}
size_t ArchiveHeapWriter::filler_array_byte_size(int length) {
@@ -512,6 +561,17 @@ class ArchiveHeapWriter::EmbeddedOopRelocator: public BasicOopIterateClosure {
}
};
+static void log_bitmap_usage(const char* which, BitMap* bitmap, size_t total_bits) {
+ // The whole heap is covered by total_bits, but there are only non-zero bits within [start ... end).
+ size_t start = bitmap->find_first_set_bit(0);
+ size_t end = bitmap->size();
+ log_info(cds)("%s = " SIZE_FORMAT_W(7) " ... " SIZE_FORMAT_W(7) " (%3zu%% ... %3zu%% = %3zu%%)", which,
+ start, end,
+ start * 100 / total_bits,
+ end * 100 / total_bits,
+ (end - start) * 100 / total_bits);
+}
+
// Update all oop fields embedded in the buffered objects
void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeap* roots,
ArchiveHeapInfo* heap_info) {
@@ -519,14 +579,17 @@ void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeapoopmap()->resize(heap_region_byte_size / oopmap_unit);
- auto iterator = [&] (oop src_obj, HeapShared::CachedOopInfo& info) {
- oop requested_obj = requested_obj_from_buffer_offset(info.buffer_offset());
+ for (int i = 0; i < _source_objs_order->length(); i++) {
+ int src_obj_index = _source_objs_order->at(i);
+ oop src_obj = _source_objs->at(src_obj_index);
+ HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(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());
- address buffered_obj = offset_to_buffered_address(info.buffer_offset());
+ address buffered_obj = offset_to_buffered_address(info->buffer_offset());
EmbeddedOopRelocator relocator(src_obj, buffered_obj, heap_info->oopmap());
src_obj->oop_iterate(&relocator);
};
- HeapShared::archived_object_cache()->iterate_all(iterator);
// Relocate HeapShared::roots(), which is created in copy_roots_to_buffer() and
// doesn't have a corresponding src_obj, so we can't use EmbeddedOopRelocator on it.
@@ -542,6 +605,10 @@ void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeaplength();
+ log_bitmap_usage("oopmap", heap_info->oopmap(), total_bytes / (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop)));
+ log_bitmap_usage("ptrmap", heap_info->ptrmap(), total_bytes / sizeof(address));
}
void ArchiveHeapWriter::mark_native_pointer(oop src_obj, int field_offset) {
@@ -551,6 +618,8 @@ void ArchiveHeapWriter::mark_native_pointer(oop src_obj, int field_offset) {
info._src_obj = src_obj;
info._field_offset = field_offset;
_native_pointers->append(info);
+ HeapShared::set_has_native_pointers(src_obj);
+ _num_native_ptrs ++;
}
}
@@ -565,6 +634,13 @@ bool ArchiveHeapWriter::is_marked_as_native_pointer(ArchiveHeapInfo* heap_info,
assert((Metadata**)_requested_bottom <= requested_field_addr && requested_field_addr < (Metadata**) _requested_top, "range check");
BitMap::idx_t idx = requested_field_addr - (Metadata**) _requested_bottom;
+ // Leading zeros have been removed so some addresses may not be in the ptrmap
+ size_t start_pos = FileMapInfo::current_info()->heap_ptrmap_start_pos();
+ if (idx < start_pos) {
+ return false;
+ } else {
+ idx -= start_pos;
+ }
return (idx < heap_info->ptrmap()->size()) && (heap_info->ptrmap()->at(idx) == true);
}
diff --git a/src/hotspot/share/cds/archiveHeapWriter.hpp b/src/hotspot/share/cds/archiveHeapWriter.hpp
index 889646b78c8..3acb8753877 100644
--- a/src/hotspot/share/cds/archiveHeapWriter.hpp
+++ b/src/hotspot/share/cds/archiveHeapWriter.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 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
@@ -140,6 +140,7 @@ class ArchiveHeapWriter : AllStatic {
static GrowableArrayCHeap* _native_pointers;
static GrowableArrayCHeap* _source_objs;
+ static GrowableArrayCHeap* _source_objs_order;
typedef ResourceHashtable static void relocate_root_at(oop requested_roots, int index, CHeapBitMap* oopmap);
static void update_header_for_requested_obj(oop requested_obj, oop src_obj, Klass* src_klass);
+
+ static int compare_objs_by_oop_fields(int* a, int* b);
+ static void sort_source_objs();
+
public:
static void init() NOT_CDS_JAVA_HEAP_RETURN;
static void add_source_obj(oop src_obj);
diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp
index 349f993babe..838b854fc3f 100644
--- a/src/hotspot/share/cds/cdsConfig.cpp
+++ b/src/hotspot/share/cds/cdsConfig.cpp
@@ -25,11 +25,13 @@
#include "precompiled.hpp"
#include "cds/archiveHeapLoader.hpp"
#include "cds/cdsConfig.hpp"
+#include "cds/classListWriter.hpp"
#include "cds/heapShared.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/moduleEntry.hpp"
#include "include/jvm_io.h"
#include "logging/log.hpp"
+#include "memory/universe.hpp"
#include "runtime/arguments.hpp"
#include "runtime/globals.hpp"
#include "runtime/java.hpp"
@@ -37,12 +39,9 @@
bool CDSConfig::_is_dumping_static_archive = false;
bool CDSConfig::_is_dumping_dynamic_archive = false;
-
-// The ability to dump the FMG depends on many factors checked by
-// is_dumping_full_module_graph(), but can be unconditionally disabled by
-// _dumping_full_module_graph_disabled. (Ditto for loading the FMG).
-bool CDSConfig::_dumping_full_module_graph_disabled = false;
-bool CDSConfig::_loading_full_module_graph_disabled = false;
+bool CDSConfig::_is_using_optimized_module_handling = true;
+bool CDSConfig::_is_dumping_full_module_graph = true;
+bool CDSConfig::_is_using_full_module_graph = true;
bool CDSConfig::_module_patching_disables_cds = false;
bool CDSConfig::_java_base_module_patching_disables_cds = false;
@@ -56,6 +55,15 @@ char* CDSConfig::_default_archive_path = nullptr;
char* CDSConfig::_static_archive_path = nullptr;
char* CDSConfig::_dynamic_archive_path = 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) |
+ (is_dumping_static_archive() ? IS_DUMPING_STATIC_ARCHIVE : 0) |
+ (is_logging_lambda_form_invokers() ? IS_LOGGING_LAMBDA_FORM_INVOKERS : 0) |
+ (is_using_archive() ? IS_USING_ARCHIVE : 0);
+}
+
+
void CDSConfig::initialize() {
if (is_dumping_static_archive()) {
if (RequireSharedSpaces) {
@@ -71,6 +79,10 @@ void CDSConfig::initialize() {
if (is_dumping_static_archive() || UseSharedSpaces) {
init_shared_archive_paths();
}
+
+ if (!is_dumping_heap()) {
+ _is_dumping_full_module_graph = false;
+ }
}
char* CDSConfig::default_archive_path() {
@@ -238,14 +250,14 @@ void CDSConfig::init_shared_archive_paths() {
void CDSConfig::check_system_property(const char* key, const char* value) {
if (Arguments::is_internal_module_property(key)) {
- MetaspaceShared::disable_optimized_module_handling();
+ stop_using_optimized_module_handling();
log_info(cds)("optimized module handling: disabled due to incompatible property: %s=%s", key, value);
}
if (strcmp(key, "jdk.module.showModuleResolution") == 0 ||
strcmp(key, "jdk.module.validation") == 0 ||
strcmp(key, "java.system.class.loader") == 0) {
- disable_loading_full_module_graph();
- disable_dumping_full_module_graph();
+ stop_dumping_full_module_graph();
+ stop_using_full_module_graph();
log_info(cds)("full module graph: disabled due to incompatible property: %s=%s", key, value);
}
}
@@ -382,6 +394,20 @@ bool CDSConfig::check_vm_args_consistency(bool mode_flag_cmd_line) {
return true;
}
+bool CDSConfig::is_using_archive() {
+ return UseSharedSpaces; // TODO: UseSharedSpaces will be eventually replaced by CDSConfig::is_using_archive()
+}
+
+bool CDSConfig::is_logging_lambda_form_invokers() {
+ return ClassListWriter::is_enabled() || is_dumping_dynamic_archive();
+}
+
+void CDSConfig::stop_using_optimized_module_handling() {
+ _is_using_optimized_module_handling = false;
+ _is_dumping_full_module_graph = false; // This requires is_using_optimized_module_handling()
+ _is_using_full_module_graph = false; // This requires is_using_optimized_module_handling()
+}
+
#if INCLUDE_CDS_JAVA_HEAP
bool CDSConfig::is_dumping_heap() {
if (is_valhalla_preview()) {
@@ -392,47 +418,39 @@ bool CDSConfig::is_dumping_heap() {
return is_dumping_static_archive() && HeapShared::can_write();
}
-bool CDSConfig::is_dumping_full_module_graph() {
- if (!_dumping_full_module_graph_disabled &&
- is_dumping_heap() &&
- MetaspaceShared::use_optimized_module_handling()) {
+bool CDSConfig::is_using_full_module_graph() {
+ if (ClassLoaderDataShared::is_full_module_graph_loaded()) {
return true;
- } else {
- return false;
}
-}
-bool CDSConfig::is_loading_full_module_graph() {
- if (ClassLoaderDataShared::is_full_module_graph_loaded()) {
- return true;
+ if (!_is_using_full_module_graph) {
+ return false;
}
- if (!_loading_full_module_graph_disabled &&
- UseSharedSpaces &&
- ArchiveHeapLoader::can_use() &&
- MetaspaceShared::use_optimized_module_handling()) {
+ if (UseSharedSpaces && ArchiveHeapLoader::can_use()) {
// Classes used by the archived full module graph are loaded in JVMTI early phase.
assert(!(JvmtiExport::should_post_class_file_load_hook() && JvmtiExport::has_early_class_hook_env()),
"CDS should be disabled if early class hooks are enabled");
return true;
} else {
+ _is_using_full_module_graph = false;
return false;
}
}
-void CDSConfig::disable_dumping_full_module_graph(const char* reason) {
- if (!_dumping_full_module_graph_disabled) {
- _dumping_full_module_graph_disabled = true;
+void CDSConfig::stop_dumping_full_module_graph(const char* reason) {
+ if (_is_dumping_full_module_graph) {
+ _is_dumping_full_module_graph = false;
if (reason != nullptr) {
log_info(cds)("full module graph cannot be dumped: %s", reason);
}
}
}
-void CDSConfig::disable_loading_full_module_graph(const char* reason) {
+void CDSConfig::stop_using_full_module_graph(const char* reason) {
assert(!ClassLoaderDataShared::is_full_module_graph_loaded(), "you call this function too late!");
- if (!_loading_full_module_graph_disabled) {
- _loading_full_module_graph_disabled = true;
+ if (_is_using_full_module_graph) {
+ _is_using_full_module_graph = false;
if (reason != nullptr) {
log_info(cds)("full module graph cannot be loaded: %s", reason);
}
diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp
index ba3883f3db5..bf9b7b56b6f 100644
--- a/src/hotspot/share/cds/cdsConfig.hpp
+++ b/src/hotspot/share/cds/cdsConfig.hpp
@@ -33,15 +33,16 @@ class CDSConfig : public AllStatic {
#if INCLUDE_CDS
static bool _is_dumping_static_archive;
static bool _is_dumping_dynamic_archive;
- static bool _dumping_full_module_graph_disabled;
- static bool _loading_full_module_graph_disabled;
+ static bool _is_using_optimized_module_handling;
+ static bool _is_dumping_full_module_graph;
+ static bool _is_using_full_module_graph;
static bool _module_patching_disables_cds;
static bool _java_base_module_patching_disables_cds;
- static char* _default_archive_path;
- static char* _static_archive_path;
- static char* _dynamic_archive_path;
+ static char* _default_archive_path;
+ static char* _static_archive_path;
+ static char* _dynamic_archive_path;
#endif
static void extract_shared_archive_paths(const char* archive_path,
@@ -51,6 +52,13 @@ class CDSConfig : public AllStatic {
static bool check_unsupported_cds_runtime_properties();
public:
+ // Used by jdk.internal.misc.CDS.getCDSConfigStatus();
+ static const int IS_DUMPING_ARCHIVE = 1 << 0;
+ static const int IS_DUMPING_STATIC_ARCHIVE = 1 << 1;
+ static const int IS_LOGGING_LAMBDA_FORM_INVOKERS = 1 << 2;
+ static const int IS_USING_ARCHIVE = 1 << 3;
+ static int get_status() NOT_CDS_RETURN_(0);
+
// Initialization and command-line checking
static void initialize() NOT_CDS_RETURN;
static void check_system_property(const char* key, const char* value) NOT_CDS_RETURN;
@@ -62,33 +70,49 @@ class CDSConfig : public AllStatic {
static bool java_base_module_patching_disables_cds() { return _java_base_module_patching_disables_cds; }
static void set_java_base_module_patching_disables_cds() { _java_base_module_patching_disables_cds = true; }
- // Basic CDS features
- static bool is_dumping_archive() { return is_dumping_static_archive() || is_dumping_dynamic_archive(); }
- static bool is_dumping_static_archive() { return CDS_ONLY(_is_dumping_static_archive) NOT_CDS(false); }
- static void enable_dumping_static_archive() { CDS_ONLY(_is_dumping_static_archive = true); }
- static bool is_dumping_dynamic_archive() { return CDS_ONLY(_is_dumping_dynamic_archive) NOT_CDS(false); }
- static void enable_dumping_dynamic_archive() { CDS_ONLY(_is_dumping_dynamic_archive = true); }
+ // --- Basic CDS features
+
+ // archive(s) in general
+ static bool is_dumping_archive() { return is_dumping_static_archive() || is_dumping_dynamic_archive(); }
+ static bool is_using_archive() NOT_CDS_RETURN_(false);
+ static int num_archives(const char* archive_path) NOT_CDS_RETURN_(0);
+
+ // static_archive
+ static bool is_dumping_static_archive() { return CDS_ONLY(_is_dumping_static_archive) NOT_CDS(false); }
+ static void enable_dumping_static_archive() { CDS_ONLY(_is_dumping_static_archive = true); }
+
+ // dynamic_archive
+ static bool is_dumping_dynamic_archive() { return CDS_ONLY(_is_dumping_dynamic_archive) NOT_CDS(false); }
+ static void enable_dumping_dynamic_archive() { CDS_ONLY(_is_dumping_dynamic_archive = true); }
static void disable_dumping_dynamic_archive() { CDS_ONLY(_is_dumping_dynamic_archive = false); }
- // Archive paths
+ // optimized_module_handling -- can we skip some expensive operations related to modules?
+ static bool is_using_optimized_module_handling() { return CDS_ONLY(_is_using_optimized_module_handling) NOT_CDS(false); }
+ static void stop_using_optimized_module_handling() NOT_CDS_RETURN;
+
+ static bool is_logging_lambda_form_invokers() NOT_CDS_RETURN_(false);
+
+ // archive_path
+
// Points to the classes.jsa in $JAVA_HOME
- static char* default_archive_path() NOT_CDS_RETURN_(nullptr);
+ static char* default_archive_path() NOT_CDS_RETURN_(nullptr);
// The actual static archive (if any) selected at runtime
static const char* static_archive_path() { return CDS_ONLY(_static_archive_path) NOT_CDS(nullptr); }
// The actual dynamic archive (if any) selected at runtime
static const char* dynamic_archive_path() { return CDS_ONLY(_dynamic_archive_path) NOT_CDS(nullptr); }
- static int num_archives(const char* archive_path) NOT_CDS_RETURN_(0);
+ // --- Archived java objects
+
+ static bool is_dumping_heap() NOT_CDS_JAVA_HEAP_RETURN_(false);
+ // full_module_graph (requires optimized_module_handling)
+ static bool is_dumping_full_module_graph() { return CDS_ONLY(_is_dumping_full_module_graph) NOT_CDS(false); }
+ static bool is_using_full_module_graph() NOT_CDS_JAVA_HEAP_RETURN_(false);
+ static void stop_dumping_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN;
+ static void stop_using_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN;
- // CDS archived heap
- static bool is_dumping_heap() NOT_CDS_JAVA_HEAP_RETURN_(false);
- static void disable_dumping_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN;
- static bool is_dumping_full_module_graph() NOT_CDS_JAVA_HEAP_RETURN_(false);
- static void disable_loading_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN;
- static bool is_loading_full_module_graph() NOT_CDS_JAVA_HEAP_RETURN_(false);
+ static bool is_valhalla_preview();
- static bool is_valhalla_preview();
};
#endif // SHARE_CDS_CDSCONFIG_HPP
diff --git a/src/hotspot/share/cds/cdsProtectionDomain.cpp b/src/hotspot/share/cds/cdsProtectionDomain.cpp
index 70ce4fb3b96..a4ffeea26dc 100644
--- a/src/hotspot/share/cds/cdsProtectionDomain.cpp
+++ b/src/hotspot/share/cds/cdsProtectionDomain.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2024, 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
@@ -119,7 +119,7 @@ Handle CDSProtectionDomain::get_package_name(Symbol* class_name, TRAPS) {
PackageEntry* CDSProtectionDomain::get_package_entry_from_class(InstanceKlass* ik, Handle class_loader) {
PackageEntry* pkg_entry = ik->package();
- if (CDSConfig::is_loading_full_module_graph() && ik->is_shared() && pkg_entry != nullptr) {
+ if (CDSConfig::is_using_full_module_graph() && ik->is_shared() && pkg_entry != nullptr) {
assert(MetaspaceShared::is_in_shared_metaspace(pkg_entry), "must be");
assert(!ik->is_shared_unregistered_class(), "unexpected archived package entry for an unregistered class");
assert(ik->module()->is_named(), "unexpected archived package entry for a class in an unnamed module");
diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp
index 65ea6d24ced..b41fa6a6fc2 100644
--- a/src/hotspot/share/cds/filemap.cpp
+++ b/src/hotspot/share/cds/filemap.cpp
@@ -277,7 +277,7 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment,
_compressed_oops = UseCompressedOops;
_compressed_class_ptrs = UseCompressedClassPointers;
_max_heap_size = MaxHeapSize;
- _use_optimized_module_handling = MetaspaceShared::use_optimized_module_handling();
+ _use_optimized_module_handling = CDSConfig::is_using_optimized_module_handling();
_has_full_module_graph = CDSConfig::is_dumping_full_module_graph();
_has_valhalla_patched_classes = CDSConfig::is_valhalla_preview();
// The following fields are for sanity checks for whether this archive
@@ -355,6 +355,8 @@ void FileMapHeader::print(outputStream* st) {
st->print_cr("- requested_base_address: " INTPTR_FORMAT, p2i(_requested_base_address));
st->print_cr("- mapped_base_address: " INTPTR_FORMAT, p2i(_mapped_base_address));
st->print_cr("- heap_roots_offset: " SIZE_FORMAT, _heap_roots_offset);
+ st->print_cr("- _heap_oopmap_start_pos: " SIZE_FORMAT, _heap_oopmap_start_pos);
+ st->print_cr("- _heap_ptrmap_start_pos: " SIZE_FORMAT, _heap_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);
@@ -1637,11 +1639,37 @@ static size_t write_bitmap(const CHeapBitMap* map, char* output, size_t offset)
return offset + size_in_bytes;
}
+// The start of the archived heap has many primitive arrays (String
+// bodies) that are not marked by the oop/ptr maps. So we must have
+// lots of leading zeros.
+size_t FileMapInfo::remove_bitmap_leading_zeros(CHeapBitMap* map) {
+ size_t old_zeros = map->find_first_set_bit(0);
+ size_t old_size = map->size_in_bytes();
+
+ // Slice and resize bitmap
+ map->truncate(old_zeros, map->size());
+
+ DEBUG_ONLY(
+ size_t new_zeros = map->find_first_set_bit(0);
+ assert(new_zeros == 0, "Should have removed leading zeros");
+ )
+
+ assert(map->size_in_bytes() < old_size, "Map size should have decreased");
+ return old_zeros;
+}
+
char* FileMapInfo::write_bitmap_region(const CHeapBitMap* ptrmap, ArchiveHeapInfo* heap_info,
size_t &size_in_bytes) {
size_in_bytes = ptrmap->size_in_bytes();
if (heap_info->is_used()) {
+ // Remove leading zeros
+ size_t removed_oop_zeros = remove_bitmap_leading_zeros(heap_info->oopmap());
+ size_t removed_ptr_zeros = remove_bitmap_leading_zeros(heap_info->ptrmap());
+
+ header()->set_heap_oopmap_start_pos(removed_oop_zeros);
+ header()->set_heap_ptrmap_start_pos(removed_ptr_zeros);
+
size_in_bytes += heap_info->oopmap()->size_in_bytes();
size_in_bytes += heap_info->ptrmap()->size_in_bytes();
}
@@ -2049,7 +2077,7 @@ void FileMapInfo::map_or_load_heap_region() {
}
if (!success) {
- CDSConfig::disable_loading_full_module_graph();
+ CDSConfig::stop_using_full_module_graph();
}
}
@@ -2483,13 +2511,13 @@ bool FileMapHeader::validate() {
}
if (!_use_optimized_module_handling) {
- MetaspaceShared::disable_optimized_module_handling();
+ CDSConfig::stop_using_optimized_module_handling();
log_info(cds)("optimized module handling: disabled because archive was created without optimized module handling");
}
if (is_static() && !_has_full_module_graph) {
// Only the static archive can contain the full module graph.
- CDSConfig::disable_loading_full_module_graph("archive was created without full module graph");
+ CDSConfig::stop_using_full_module_graph("archive was created without full module graph");
}
return true;
diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp
index 150c4badc38..510892897a9 100644
--- a/src/hotspot/share/cds/filemap.hpp
+++ b/src/hotspot/share/cds/filemap.hpp
@@ -259,6 +259,8 @@ class FileMapHeader: private CDSFileMapHeaderBase {
CDSMustMatchFlags _must_match; // These flags must be the same between dumptime and runtime
size_t _heap_roots_offset; // Offset of the HeapShared::roots() object, from the bottom
// of the archived heap objects, in bytes.
+ size_t _heap_oopmap_start_pos; // The first bit in the oopmap corresponds to this position in the heap.
+ size_t _heap_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the heap.
char* from_mapped_offset(size_t offset) const {
return mapped_base_address() + offset;
}
@@ -300,6 +302,8 @@ class FileMapHeader: private CDSFileMapHeaderBase {
bool compressed_oops() const { return _compressed_oops; }
bool compressed_class_pointers() const { return _compressed_class_ptrs; }
size_t heap_roots_offset() const { return _heap_roots_offset; }
+ size_t heap_oopmap_start_pos() const { return _heap_oopmap_start_pos;}
+ size_t heap_ptrmap_start_pos() const { return _heap_ptrmap_start_pos;}
// FIXME: These should really return int
jshort max_used_path_index() const { return _max_used_path_index; }
jshort app_module_paths_start_index() const { return _app_module_paths_start_index; }
@@ -312,6 +316,8 @@ class FileMapHeader: private CDSFileMapHeaderBase {
void set_ptrmap_size_in_bits(size_t s) { _ptrmap_size_in_bits = s; }
void set_mapped_base_address(char* p) { _mapped_base_address = p; }
void set_heap_roots_offset(size_t n) { _heap_roots_offset = n; }
+ void set_heap_oopmap_start_pos(size_t n) { _heap_oopmap_start_pos = n; }
+ void set_heap_ptrmap_start_pos(size_t n) { _heap_ptrmap_start_pos = n; }
void copy_base_archive_name(const char* name);
void set_shared_path_table(SharedPathTable table) {
@@ -413,6 +419,8 @@ class FileMapInfo : public CHeapObj {
uintx max_heap_size() const { return header()->max_heap_size(); }
size_t heap_roots_offset() const { return header()->heap_roots_offset(); }
size_t core_region_alignment() const { return header()->core_region_alignment(); }
+ size_t heap_oopmap_start_pos() const { return header()->heap_oopmap_start_pos(); }
+ size_t heap_ptrmap_start_pos() const { return header()->heap_ptrmap_start_pos(); }
CompressedOops::Mode narrow_oop_mode() const { return header()->narrow_oop_mode(); }
jshort app_module_paths_start_index() const { return header()->app_module_paths_start_index(); }
@@ -469,6 +477,7 @@ class FileMapInfo : public CHeapObj {
void write_header();
void write_region(int region, char* base, size_t size,
bool read_only, bool allow_exec);
+ size_t remove_bitmap_leading_zeros(CHeapBitMap* map);
char* write_bitmap_region(const CHeapBitMap* ptrmap, ArchiveHeapInfo* heap_info,
size_t &size_in_bytes);
size_t write_heap_region(ArchiveHeapInfo* heap_info);
diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp
index 412a1b86737..c559f3c6f8d 100644
--- a/src/hotspot/share/cds/heapShared.cpp
+++ b/src/hotspot/share/cds/heapShared.cpp
@@ -286,7 +286,7 @@ bool HeapShared::archive_object(oop obj) {
if (!obj->klass()->is_inline_klass()) {
obj->identity_hash();
}
- CachedOopInfo info = make_cached_oop_info();
+ CachedOopInfo info = make_cached_oop_info(obj);
archived_object_cache()->put(obj, info);
mark_native_pointers(obj);
@@ -439,6 +439,24 @@ void HeapShared::mark_native_pointers(oop orig_obj) {
}
}
+bool HeapShared::has_oop_pointers(oop src_obj) {
+ CachedOopInfo* info = archived_object_cache()->get(src_obj);
+ assert(info != nullptr, "must be");
+ return info->has_oop_pointers();
+}
+
+bool HeapShared::has_native_pointers(oop src_obj) {
+ CachedOopInfo* info = archived_object_cache()->get(src_obj);
+ assert(info != nullptr, "must be");
+ return info->has_native_pointers();
+}
+
+void HeapShared::set_has_native_pointers(oop src_obj) {
+ CachedOopInfo* info = archived_object_cache()->get(src_obj);
+ assert(info != nullptr, "must be");
+ info->set_has_native_pointers();
+}
+
// -- Handling of Enum objects
// Java Enum classes have synthetic methods that look like this
// enum MyEnum {FOO, BAR}
@@ -974,7 +992,7 @@ HeapShared::resolve_or_init_classes_for_subgraph_of(Klass* k, bool do_init, TRAP
}
return nullptr;
} else {
- if (record->is_full_module_graph() && !CDSConfig::is_loading_full_module_graph()) {
+ if (record->is_full_module_graph() && !CDSConfig::is_using_full_module_graph()) {
if (log_is_enabled(Info, cds, heap)) {
ResourceMark rm(THREAD);
log_info(cds, heap)("subgraph %s cannot be used because full module graph is disabled",
@@ -1140,10 +1158,27 @@ class WalkOopAndArchiveClosure: public BasicOopIterateClosure {
WalkOopAndArchiveClosure* WalkOopAndArchiveClosure::_current = nullptr;
-HeapShared::CachedOopInfo HeapShared::make_cached_oop_info() {
+// Checks if an oop has any non-null oop fields
+class PointsToOopsChecker : public BasicOopIterateClosure {
+ bool _result;
+
+ template void check(T *p) {
+ _result |= (HeapAccess<>::oop_load(p) != nullptr);
+ }
+
+public:
+ PointsToOopsChecker() : _result(false) {}
+ void do_oop(narrowOop *p) { check(p); }
+ void do_oop( oop *p) { check(p); }
+ bool result() { return _result; }
+};
+
+HeapShared::CachedOopInfo HeapShared::make_cached_oop_info(oop obj) {
WalkOopAndArchiveClosure* walker = WalkOopAndArchiveClosure::current();
oop referrer = (walker == nullptr) ? nullptr : walker->referencing_obj();
- return CachedOopInfo(referrer);
+ PointsToOopsChecker points_to_oops_checker;
+ obj->oop_iterate(&points_to_oops_checker);
+ return CachedOopInfo(referrer, points_to_oops_checker.result());
}
// (1) If orig_obj has not been archived yet, archive it.
@@ -1441,12 +1476,14 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
#ifndef PRODUCT
bool is_test_class = (ArchiveHeapTestClass != nullptr) && (strcmp(info->klass_name, ArchiveHeapTestClass) == 0);
+ const char* test_class_name = ArchiveHeapTestClass;
#else
bool is_test_class = false;
+ const char* test_class_name = ""; // avoid C++ printf checks warnings.
#endif
if (is_test_class) {
- log_warning(cds)("Loading ArchiveHeapTestClass %s ...", ArchiveHeapTestClass);
+ log_warning(cds)("Loading ArchiveHeapTestClass %s ...", test_class_name);
}
Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, THREAD);
@@ -1472,14 +1509,14 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
// We don't want ArchiveHeapTestClass to be abused to easily load/initialize arbitrary
// core-lib classes. You need to at least append to the bootclasspath.
stringStream st;
- st.print("ArchiveHeapTestClass %s is not in unnamed module", ArchiveHeapTestClass);
+ st.print("ArchiveHeapTestClass %s is not in unnamed module", test_class_name);
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
}
if (ik->package() != nullptr) {
// This restriction makes HeapShared::is_a_test_class_in_unnamed_module() easy.
stringStream st;
- st.print("ArchiveHeapTestClass %s is not in unnamed package", ArchiveHeapTestClass);
+ st.print("ArchiveHeapTestClass %s is not in unnamed package", test_class_name);
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), st.as_string());
}
} else {
@@ -1494,7 +1531,7 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
}
if (is_test_class) {
- log_warning(cds)("Initializing ArchiveHeapTestClass %s ...", ArchiveHeapTestClass);
+ log_warning(cds)("Initializing ArchiveHeapTestClass %s ...", test_class_name);
}
ik->initialize(CHECK);
diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp
index c41339173cd..e1b73eeced7 100644
--- a/src/hotspot/share/cds/heapShared.hpp
+++ b/src/hotspot/share/cds/heapShared.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, 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
@@ -186,18 +186,29 @@ class HeapShared: AllStatic {
}
class CachedOopInfo {
- // See "TEMP notes: What are these?" in archiveHeapWriter.hpp
+ // Used by CDSHeapVerifier.
oop _orig_referrer;
// The location of this object inside ArchiveHeapWriter::_buffer
size_t _buffer_offset;
+
+ // One or more fields in this object are pointing to non-null oops.
+ bool _has_oop_pointers;
+
+ // One or more fields in this object are pointing to MetaspaceObj
+ bool _has_native_pointers;
public:
- CachedOopInfo(oop orig_referrer)
+ CachedOopInfo(oop orig_referrer, bool has_oop_pointers)
: _orig_referrer(orig_referrer),
- _buffer_offset(0) {}
+ _buffer_offset(0),
+ _has_oop_pointers(has_oop_pointers),
+ _has_native_pointers(false) {}
oop orig_referrer() const { return _orig_referrer; }
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; }
+ bool has_native_pointers() const { return _has_native_pointers; }
+ void set_has_native_pointers() { _has_native_pointers = true; }
};
private:
@@ -237,7 +248,7 @@ class HeapShared: AllStatic {
static DumpTimeKlassSubGraphInfoTable* _dump_time_subgraph_info_table;
static RunTimeKlassSubGraphInfoTable _run_time_subgraph_info_table;
- static CachedOopInfo make_cached_oop_info();
+ static CachedOopInfo make_cached_oop_info(oop obj);
static void archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
bool is_full_module_graph);
@@ -368,6 +379,9 @@ class HeapShared: AllStatic {
// Scratch objects for archiving Klass::java_mirror()
static void set_scratch_java_mirror(Klass* k, oop mirror);
static void remove_scratch_objects(Klass* k);
+ static bool has_oop_pointers(oop obj);
+ static bool has_native_pointers(oop obj);
+ static void set_has_native_pointers(oop obj);
// We use the HeapShared::roots() array to make sure that objects stored in the
// archived heap region are not prematurely collected. These roots include:
diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp
index df49d99c453..0312dcf4a9e 100644
--- a/src/hotspot/share/cds/metaspaceShared.cpp
+++ b/src/hotspot/share/cds/metaspaceShared.cpp
@@ -786,7 +786,7 @@ void MetaspaceShared::preload_and_dump_impl(TRAPS) {
if (CDSConfig::is_dumping_heap()) {
if (!HeapShared::is_archived_boot_layer_available(THREAD)) {
log_info(cds)("archivedBootLayer not available, disabling full module graph");
- CDSConfig::disable_dumping_full_module_graph();
+ CDSConfig::stop_dumping_full_module_graph();
}
HeapShared::init_for_dumping(CHECK);
ArchiveHeapWriter::init();
@@ -1182,8 +1182,8 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
static_mapinfo->map_or_load_heap_region();
}
#endif // _LP64
- log_info(cds)("initial optimized module handling: %s", MetaspaceShared::use_optimized_module_handling() ? "enabled" : "disabled");
- log_info(cds)("initial full module graph: %s", CDSConfig::is_loading_full_module_graph() ? "enabled" : "disabled");
+ log_info(cds)("initial optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled");
+ log_info(cds)("initial full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled");
} else {
unmap_archive(static_mapinfo);
unmap_archive(dynamic_mapinfo);
diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp
index d8e41c23c11..f8346851faa 100644
--- a/src/hotspot/share/cds/metaspaceShared.hpp
+++ b/src/hotspot/share/cds/metaspaceShared.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024, 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
@@ -53,6 +53,7 @@ class MetaspaceShared : AllStatic {
static intx _relocation_delta;
static char* _requested_base_address;
static bool _use_optimized_module_handling;
+
public:
enum {
// core archive spaces
diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp
index 406a543e566..cb15ada9f84 100644
--- a/src/hotspot/share/classfile/classLoaderData.cpp
+++ b/src/hotspot/share/classfile/classLoaderData.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024, 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
@@ -408,9 +408,6 @@ void ClassLoaderData::methods_do(void f(Method*)) {
}
void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) {
- // To call this, one must have the MultiArray_lock held, but the _klasses list still has lock free reads.
- assert_locked_or_safepoint(MultiArray_lock);
-
// Lock-free access requires load_acquire
for (Klass* k = Atomic::load_acquire(&_klasses); k != nullptr; k = k->next_link()) {
// Filter out InstanceKlasses (or their ObjArrayKlasses) that have not entered the
diff --git a/src/hotspot/share/classfile/classLoaderDataShared.cpp b/src/hotspot/share/classfile/classLoaderDataShared.cpp
index e6f34b2b8b9..b6d93eace4e 100644
--- a/src/hotspot/share/classfile/classLoaderDataShared.cpp
+++ b/src/hotspot/share/classfile/classLoaderDataShared.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2024, 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
@@ -172,7 +172,7 @@ void ClassLoaderDataShared::serialize(SerializeClosure* f) {
_archived_system_loader_data.serialize(f);
f->do_ptr(&_archived_javabase_moduleEntry);
- if (f->reading() && CDSConfig::is_loading_full_module_graph()) {
+ if (f->reading() && CDSConfig::is_using_full_module_graph()) {
// Must be done before ClassLoader::create_javabase()
_archived_boot_loader_data.restore(null_class_loader_data(), true, false);
ModuleEntryTable::set_javabase_moduleEntry(_archived_javabase_moduleEntry);
@@ -182,25 +182,25 @@ void ClassLoaderDataShared::serialize(SerializeClosure* f) {
}
void ClassLoaderDataShared::clear_archived_oops() {
- assert(!CDSConfig::is_loading_full_module_graph(), "must be");
+ assert(!CDSConfig::is_using_full_module_graph(), "must be");
_archived_boot_loader_data.clear_archived_oops();
_archived_platform_loader_data.clear_archived_oops();
_archived_system_loader_data.clear_archived_oops();
}
oop ClassLoaderDataShared::restore_archived_oops_for_null_class_loader_data() {
- assert(CDSConfig::is_loading_full_module_graph(), "must be");
+ assert(CDSConfig::is_using_full_module_graph(), "must be");
_archived_boot_loader_data.restore(null_class_loader_data(), false, true);
return _archived_javabase_moduleEntry->module();
}
void ClassLoaderDataShared::restore_java_platform_loader_from_archive(ClassLoaderData* loader_data) {
- assert(CDSConfig::is_loading_full_module_graph(), "must be");
+ assert(CDSConfig::is_using_full_module_graph(), "must be");
_archived_platform_loader_data.restore(loader_data, true, true);
}
void ClassLoaderDataShared::restore_java_system_loader_from_archive(ClassLoaderData* loader_data) {
- assert(CDSConfig::is_loading_full_module_graph(), "must be");
+ assert(CDSConfig::is_using_full_module_graph(), "must be");
_archived_system_loader_data.restore(loader_data, true, true);
_full_module_graph_loaded = true;
}
diff --git a/src/hotspot/share/classfile/modules.cpp b/src/hotspot/share/classfile/modules.cpp
index 4664d9565d3..d4f3cc29962 100644
--- a/src/hotspot/share/classfile/modules.cpp
+++ b/src/hotspot/share/classfile/modules.cpp
@@ -596,15 +596,15 @@ void Modules::serialize(SerializeClosure* soc) {
if (disable) {
log_info(cds)("Disabling optimized module handling");
- MetaspaceShared::disable_optimized_module_handling();
+ CDSConfig::stop_using_optimized_module_handling();
}
- log_info(cds)("optimized module handling: %s", MetaspaceShared::use_optimized_module_handling() ? "enabled" : "disabled");
- log_info(cds)("full module graph: %s", CDSConfig::is_loading_full_module_graph() ? "enabled" : "disabled");
+ log_info(cds)("optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled");
+ log_info(cds)("full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled");
}
}
void Modules::define_archived_modules(Handle h_platform_loader, Handle h_system_loader, TRAPS) {
- assert(CDSConfig::is_loading_full_module_graph(), "must be");
+ assert(CDSConfig::is_using_full_module_graph(), "must be");
// We don't want the classes used by the archived full module graph to be redefined by JVMTI.
// Luckily, such classes are loaded in the JVMTI "early" phase, and CDS is disabled if a JVMTI
diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp
index af103ae4c72..a68be89d78d 100644
--- a/src/hotspot/share/classfile/systemDictionary.cpp
+++ b/src/hotspot/share/classfile/systemDictionary.cpp
@@ -143,7 +143,7 @@ void SystemDictionary::compute_java_loaders(TRAPS) {
} else {
// It must have been restored from the archived module graph
assert(UseSharedSpaces, "must be");
- assert(CDSConfig::is_loading_full_module_graph(), "must be");
+ assert(CDSConfig::is_using_full_module_graph(), "must be");
DEBUG_ONLY(
oop system_loader = get_system_class_loader_impl(CHECK);
assert(_java_system_loader.resolve() == system_loader, "must be");
@@ -156,7 +156,7 @@ void SystemDictionary::compute_java_loaders(TRAPS) {
} else {
// It must have been restored from the archived module graph
assert(UseSharedSpaces, "must be");
- assert(CDSConfig::is_loading_full_module_graph(), "must be");
+ assert(CDSConfig::is_using_full_module_graph(), "must be");
DEBUG_ONLY(
oop platform_loader = get_platform_class_loader_impl(CHECK);
assert(_java_platform_loader.resolve() == platform_loader, "must be");
@@ -967,7 +967,7 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
// (2) Check if we are loading into the same module from the same location as in dump time.
- if (MetaspaceShared::use_optimized_module_handling()) {
+ if (CDSConfig::is_using_optimized_module_handling()) {
// Class visibility has not changed between dump time and run time, so a class
// that was visible (and thus archived) during dump time is always visible during runtime.
assert(SystemDictionary::is_shared_class_visible_impl(class_name, ik, pkg_entry, class_loader),
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
index 5d81f49546c..1196aede587 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
@@ -29,6 +29,7 @@
#include "gc/g1/g1BatchedTask.hpp"
#include "gc/g1/g1CardSetMemory.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1CollectionSetChooser.hpp"
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1ConcurrentMark.inline.hpp"
#include "gc/g1/g1ConcurrentMarkThread.inline.hpp"
@@ -1176,111 +1177,158 @@ void G1ConcurrentMark::verify_during_pause(G1HeapVerifier::G1VerifyType type,
}
}
-class G1UpdateRemSetTrackingBeforeRebuildTask : public WorkerTask {
+// Update per-region liveness info based on CM stats. Then, reclaim empty
+// regions right away and select certain regions (e.g. sparse ones) for remset
+// rebuild.
+class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask {
G1CollectedHeap* _g1h;
G1ConcurrentMark* _cm;
HeapRegionClaimer _hrclaimer;
+
uint volatile _total_selected_for_rebuild;
- G1PrintRegionLivenessInfoClosure _cl;
+ // Reclaimed empty regions
+ FreeRegionList _cleanup_list;
- class G1UpdateRemSetTrackingBeforeRebuild : public HeapRegionClosure {
+ struct G1OnRegionClosure : public HeapRegionClosure {
G1CollectedHeap* _g1h;
G1ConcurrentMark* _cm;
+ // The number of regions actually selected for rebuild.
+ uint _num_selected_for_rebuild;
- G1PrintRegionLivenessInfoClosure* _cl;
+ size_t _freed_bytes;
+ uint _num_old_regions_removed;
+ uint _num_humongous_regions_removed;
+ FreeRegionList* _local_cleanup_list;
- uint _num_regions_selected_for_rebuild; // The number of regions actually selected for rebuild.
+ G1OnRegionClosure(G1CollectedHeap* g1h,
+ G1ConcurrentMark* cm,
+ FreeRegionList* local_cleanup_list) :
+ _g1h(g1h),
+ _cm(cm),
+ _num_selected_for_rebuild(0),
+ _freed_bytes(0),
+ _num_old_regions_removed(0),
+ _num_humongous_regions_removed(0),
+ _local_cleanup_list(local_cleanup_list) {}
- void update_remset_before_rebuild(HeapRegion* hr) {
- G1RemSetTrackingPolicy* tracking_policy = _g1h->policy()->remset_tracker();
+ void reclaim_empty_humongous_region(HeapRegion* hr) {
+ assert(!hr->has_pinned_objects(), "precondition");
+ assert(hr->is_starts_humongous(), "precondition");
- bool selected_for_rebuild;
- if (hr->is_humongous()) {
- bool const is_live = _cm->contains_live_object(hr->humongous_start_region()->hrm_index());
- selected_for_rebuild = tracking_policy->update_humongous_before_rebuild(hr, is_live);
- } else {
- size_t const live_bytes = _cm->live_bytes(hr->hrm_index());
- selected_for_rebuild = tracking_policy->update_before_rebuild(hr, live_bytes);
- }
- if (selected_for_rebuild) {
- _num_regions_selected_for_rebuild++;
- }
- _cm->update_top_at_rebuild_start(hr);
- }
+ auto on_humongous_region = [&] (HeapRegion* hr) {
+ assert(hr->used() > 0, "precondition");
+ assert(!hr->has_pinned_objects(), "precondition");
+ assert(hr->is_humongous(), "precondition");
- // Distribute the given marked bytes across the humongous object starting
- // with hr and note end of marking for these regions.
- void distribute_marked_bytes(HeapRegion* hr, size_t marked_bytes) {
- // Dead humongous objects (marked_bytes == 0) may have already been unloaded.
- assert(marked_bytes == 0 || cast_to_oop(hr->bottom())->size() * HeapWordSize == marked_bytes,
- "Marked bytes should either be 0 or the same as humongous object (%zu) but is %zu",
- cast_to_oop(hr->bottom())->size() * HeapWordSize, marked_bytes);
-
- auto distribute_bytes = [&] (HeapRegion* r) {
- size_t const bytes_to_add = MIN2(HeapRegion::GrainBytes, marked_bytes);
-
- log_trace(gc, marking)("Adding %zu bytes to humongous region %u (%s)",
- bytes_to_add, r->hrm_index(), r->get_type_str());
- add_marked_bytes_and_note_end(r, bytes_to_add);
- marked_bytes -= bytes_to_add;
+ _num_humongous_regions_removed++;
+ _freed_bytes += hr->used();
+ hr->set_containing_set(nullptr);
+ hr->clear_cardtable();
+ _g1h->concurrent_mark()->clear_statistics(hr);
+ _g1h->free_humongous_region(hr, _local_cleanup_list);
};
- _g1h->humongous_obj_regions_iterate(hr, distribute_bytes);
- }
- void update_marked_bytes(HeapRegion* hr) {
- uint const region_idx = hr->hrm_index();
- size_t const marked_bytes = _cm->live_bytes(region_idx);
- // The marking attributes the object's size completely to the humongous starts
- // region. We need to distribute this value across the entire set of regions a
- // humongous object spans.
- if (hr->is_humongous()) {
- assert(hr->is_starts_humongous() || marked_bytes == 0,
- "Should not have live bytes %zu in continues humongous region %u (%s)",
- marked_bytes, region_idx, hr->get_type_str());
- if (hr->is_starts_humongous()) {
- distribute_marked_bytes(hr, marked_bytes);
- }
- } else {
- log_trace(gc, marking)("Adding %zu bytes to region %u (%s)", marked_bytes, region_idx, hr->get_type_str());
- add_marked_bytes_and_note_end(hr, marked_bytes);
- }
+ _g1h->humongous_obj_regions_iterate(hr, on_humongous_region);
}
- void add_marked_bytes_and_note_end(HeapRegion* hr, size_t marked_bytes) {
- hr->note_end_of_marking(marked_bytes);
- _cl->do_heap_region(hr);
+ void reclaim_empty_old_region(HeapRegion* hr) {
+ assert(hr->used() > 0, "precondition");
+ assert(!hr->has_pinned_objects(), "precondition");
+ assert(hr->is_old(), "precondition");
+
+ _num_old_regions_removed++;
+ _freed_bytes += hr->used();
+ hr->set_containing_set(nullptr);
+ hr->clear_cardtable();
+ _g1h->concurrent_mark()->clear_statistics(hr);
+ _g1h->free_region(hr, _local_cleanup_list);
}
- public:
- G1UpdateRemSetTrackingBeforeRebuild(G1CollectedHeap* g1h, G1ConcurrentMark* cm, G1PrintRegionLivenessInfoClosure* cl) :
- _g1h(g1h), _cm(cm), _cl(cl), _num_regions_selected_for_rebuild(0) { }
-
- virtual bool do_heap_region(HeapRegion* r) {
- update_remset_before_rebuild(r);
- update_marked_bytes(r);
+ bool do_heap_region(HeapRegion* hr) override {
+ G1RemSetTrackingPolicy* tracker = _g1h->policy()->remset_tracker();
+ if (hr->is_starts_humongous()) {
+ // The liveness of this humongous obj decided by either its allocation
+ // time (allocated after conc-mark-start, i.e. live) or conc-marking.
+ const bool is_live = hr->top_at_mark_start() == hr->bottom()
+ || _cm->contains_live_object(hr->hrm_index());
+ if (is_live) {
+ const bool selected_for_rebuild = tracker->update_humongous_before_rebuild(hr);
+ auto on_humongous_region = [&] (HeapRegion* hr) {
+ if (selected_for_rebuild) {
+ _num_selected_for_rebuild++;
+ }
+ _cm->update_top_at_rebuild_start(hr);
+ };
+
+ _g1h->humongous_obj_regions_iterate(hr, on_humongous_region);
+ } else {
+ reclaim_empty_humongous_region(hr);
+ }
+ } else if (hr->is_old()) {
+ hr->note_end_of_marking(_cm->live_bytes(hr->hrm_index()));
+
+ if (hr->live_bytes() != 0) {
+ if (tracker->update_old_before_rebuild(hr)) {
+ _num_selected_for_rebuild++;
+ }
+ _cm->update_top_at_rebuild_start(hr);
+ } else {
+ reclaim_empty_old_region(hr);
+ }
+ }
return false;
}
-
- uint num_selected_for_rebuild() const { return _num_regions_selected_for_rebuild; }
};
public:
- G1UpdateRemSetTrackingBeforeRebuildTask(G1CollectedHeap* g1h, G1ConcurrentMark* cm, uint num_workers) :
- WorkerTask("G1 Update RemSet Tracking Before Rebuild"),
- _g1h(g1h), _cm(cm), _hrclaimer(num_workers), _total_selected_for_rebuild(0), _cl("Post-Marking") { }
+ G1UpdateRegionLivenessAndSelectForRebuildTask(G1CollectedHeap* g1h,
+ G1ConcurrentMark* cm,
+ uint num_workers) :
+ WorkerTask("G1 Update Region Liveness and Select For Rebuild"),
+ _g1h(g1h),
+ _cm(cm),
+ _hrclaimer(num_workers),
+ _total_selected_for_rebuild(0),
+ _cleanup_list("Empty Regions After Mark List") {}
+
+ ~G1UpdateRegionLivenessAndSelectForRebuildTask() {
+ if (!_cleanup_list.is_empty()) {
+ log_debug(gc)("Reclaimed %u empty regions", _cleanup_list.length());
+ // Now print the empty regions list.
+ _g1h->hr_printer()->cleanup(&_cleanup_list);
+ // And actually make them available.
+ _g1h->prepend_to_freelist(&_cleanup_list);
+ }
+ }
+
+ void work(uint worker_id) override {
+ FreeRegionList local_cleanup_list("Local Cleanup List");
+ G1OnRegionClosure on_region_cl(_g1h, _cm, &local_cleanup_list);
+ _g1h->heap_region_par_iterate_from_worker_offset(&on_region_cl, &_hrclaimer, worker_id);
+
+ Atomic::add(&_total_selected_for_rebuild, on_region_cl._num_selected_for_rebuild);
- virtual void work(uint worker_id) {
- G1UpdateRemSetTrackingBeforeRebuild update_cl(_g1h, _cm, &_cl);
- _g1h->heap_region_par_iterate_from_worker_offset(&update_cl, &_hrclaimer, worker_id);
- Atomic::add(&_total_selected_for_rebuild, update_cl.num_selected_for_rebuild());
+ // Update the old/humongous region sets
+ _g1h->remove_from_old_gen_sets(on_region_cl._num_old_regions_removed,
+ on_region_cl._num_humongous_regions_removed);
+
+ {
+ MutexLocker x(G1RareEvent_lock, Mutex::_no_safepoint_check_flag);
+ _g1h->decrement_summary_bytes(on_region_cl._freed_bytes);
+
+ _cleanup_list.add_ordered(&local_cleanup_list);
+ assert(local_cleanup_list.is_empty(), "post-condition");
+ }
}
uint total_selected_for_rebuild() const { return _total_selected_for_rebuild; }
- // Number of regions for which roughly one thread should be spawned for this work.
- static const uint RegionsPerThread = 384;
+ static uint desired_num_workers(uint num_regions) {
+ const uint num_regions_per_worker = 384;
+ return (num_regions + num_regions_per_worker - 1) / num_regions_per_worker;
+ }
};
class G1UpdateRegionsAfterRebuild : public HeapRegionClosure {
@@ -1359,24 +1407,22 @@ void G1ConcurrentMark::remark() {
_g1h->verifier()->verify_bitmap_clear(true /* above_tams_only */);
{
- GCTraceTime(Debug, gc, phases) debug("Update Remembered Set Tracking Before Rebuild", _gc_timer_cm);
-
- uint const workers_by_capacity = (_g1h->num_regions() + G1UpdateRemSetTrackingBeforeRebuildTask::RegionsPerThread - 1) /
- G1UpdateRemSetTrackingBeforeRebuildTask::RegionsPerThread;
- uint const num_workers = MIN2(_g1h->workers()->active_workers(), workers_by_capacity);
+ GCTraceTime(Debug, gc, phases) debug("Select For Rebuild and Reclaim Empty Regions", _gc_timer_cm);
- G1UpdateRemSetTrackingBeforeRebuildTask cl(_g1h, this, num_workers);
+ G1UpdateRegionLivenessAndSelectForRebuildTask cl(_g1h, this, _g1h->workers()->active_workers());
+ uint const num_workers = MIN2(G1UpdateRegionLivenessAndSelectForRebuildTask::desired_num_workers(_g1h->num_regions()),
+ _g1h->workers()->active_workers());
log_debug(gc,ergo)("Running %s using %u workers for %u regions in heap", cl.name(), num_workers, _g1h->num_regions());
_g1h->workers()->run_task(&cl, num_workers);
log_debug(gc, remset, tracking)("Remembered Set Tracking update regions total %u, selected %u",
- _g1h->num_regions(), cl.total_selected_for_rebuild());
-
+ _g1h->num_regions(), cl.total_selected_for_rebuild());
_needs_remembered_set_rebuild = (cl.total_selected_for_rebuild() > 0);
}
- {
- GCTraceTime(Debug, gc, phases) debug("Reclaim Empty Regions", _gc_timer_cm);
- reclaim_empty_regions();
+
+ if (log_is_enabled(Trace, gc, liveness)) {
+ G1PrintRegionLivenessInfoClosure cl("Post-Marking");
+ _g1h->heap_region_iterate(&cl);
}
// Potentially, some empty-regions have been reclaimed; make this a
@@ -1424,98 +1470,6 @@ void G1ConcurrentMark::remark() {
policy->record_concurrent_mark_remark_end();
}
-class G1ReclaimEmptyRegionsTask : public WorkerTask {
- class G1ReclaimEmptyRegionsClosure : public HeapRegionClosure {
- G1CollectedHeap* _g1h;
- size_t _freed_bytes;
- FreeRegionList* _local_cleanup_list;
- uint _old_regions_removed;
- uint _humongous_regions_removed;
-
- public:
- G1ReclaimEmptyRegionsClosure(G1CollectedHeap* g1h,
- FreeRegionList* local_cleanup_list) :
- _g1h(g1h),
- _freed_bytes(0),
- _local_cleanup_list(local_cleanup_list),
- _old_regions_removed(0),
- _humongous_regions_removed(0) { }
-
- size_t freed_bytes() { return _freed_bytes; }
- uint old_regions_removed() { return _old_regions_removed; }
- uint humongous_regions_removed() { return _humongous_regions_removed; }
-
- bool do_heap_region(HeapRegion *hr) {
- bool can_reclaim = hr->used() > 0 && hr->live_bytes() == 0 &&
- !hr->is_young() && !hr->has_pinned_objects();
-
- if (can_reclaim) {
- log_trace(gc, marking)("Reclaimed empty old gen region %u (%s) bot " PTR_FORMAT,
- hr->hrm_index(), hr->get_short_type_str(), p2i(hr->bottom()));
- _freed_bytes += hr->used();
- hr->set_containing_set(nullptr);
- if (hr->is_humongous()) {
- _humongous_regions_removed++;
- _g1h->free_humongous_region(hr, _local_cleanup_list);
- } else {
- _old_regions_removed++;
- _g1h->free_region(hr, _local_cleanup_list);
- }
- hr->clear_cardtable();
- _g1h->concurrent_mark()->clear_statistics(hr);
- }
-
- return false;
- }
- };
-
- G1CollectedHeap* _g1h;
- FreeRegionList* _cleanup_list;
- HeapRegionClaimer _hrclaimer;
-
-public:
- G1ReclaimEmptyRegionsTask(G1CollectedHeap* g1h, FreeRegionList* cleanup_list, uint n_workers) :
- WorkerTask("G1 Cleanup"),
- _g1h(g1h),
- _cleanup_list(cleanup_list),
- _hrclaimer(n_workers) {
- }
-
- void work(uint worker_id) {
- FreeRegionList local_cleanup_list("Local Cleanup List");
- G1ReclaimEmptyRegionsClosure cl(_g1h, &local_cleanup_list);
- _g1h->heap_region_par_iterate_from_worker_offset(&cl, &_hrclaimer, worker_id);
- assert(cl.is_complete(), "Shouldn't have aborted!");
-
- // Now update the old/humongous region sets
- _g1h->remove_from_old_gen_sets(cl.old_regions_removed(),
- cl.humongous_regions_removed());
- {
- MutexLocker x(G1RareEvent_lock, Mutex::_no_safepoint_check_flag);
- _g1h->decrement_summary_bytes(cl.freed_bytes());
-
- _cleanup_list->add_ordered(&local_cleanup_list);
- assert(local_cleanup_list.is_empty(), "post-condition");
- }
- }
-};
-
-void G1ConcurrentMark::reclaim_empty_regions() {
- WorkerThreads* workers = _g1h->workers();
- FreeRegionList empty_regions_list("Empty Regions After Mark List");
-
- G1ReclaimEmptyRegionsTask cl(_g1h, &empty_regions_list, workers->active_workers());
- workers->run_task(&cl);
-
- if (!empty_regions_list.is_empty()) {
- log_debug(gc)("Reclaimed %u empty regions", empty_regions_list.length());
- // Now print the empty regions list.
- _g1h->hr_printer()->cleanup(&empty_regions_list);
- // And actually make them available.
- _g1h->prepend_to_freelist(&empty_regions_list);
- }
-}
-
void G1ConcurrentMark::compute_new_sizes() {
MetaspaceGC::compute_new_size();
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
index 3d9693bed10..8fee9670f3f 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
@@ -463,8 +463,6 @@ class G1ConcurrentMark : public CHeapObj {
void weak_refs_work();
- void reclaim_empty_regions();
-
// After reclaiming empty regions, update heap sizes.
void compute_new_sizes();
diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp
index 43b582b7dd9..a39a082bc82 100644
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp
@@ -174,6 +174,7 @@ void G1GCPhaseTimes::reset() {
_cur_merge_heap_roots_time_ms = 0.0;
_cur_optional_merge_heap_roots_time_ms = 0.0;
_cur_prepare_merge_heap_roots_time_ms = 0.0;
+ _cur_distribute_log_buffers_time_ms = 0.0;
_cur_optional_prepare_merge_heap_roots_time_ms = 0.0;
_cur_pre_evacuate_prepare_time_ms = 0.0;
_cur_post_evacuate_cleanup_1_time_ms = 0.0;
@@ -459,6 +460,7 @@ double G1GCPhaseTimes::print_evacuate_initial_collection_set() const {
debug_time("Prepare Merge Heap Roots", _cur_prepare_merge_heap_roots_time_ms);
debug_phase_merge_remset();
+ debug_time("Distribute Log Buffers", _cur_distribute_log_buffers_time_ms);
debug_phase(_gc_par_phases[MergeLB]);
info_time("Evacuate Collection Set", _cur_collection_initial_evac_time_ms);
diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp
index 713b411bda1..bae0dfa87a0 100644
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp
@@ -181,6 +181,8 @@ class G1GCPhaseTimes : public CHeapObj {
double _cur_prepare_merge_heap_roots_time_ms;
double _cur_optional_prepare_merge_heap_roots_time_ms;
+ double _cur_distribute_log_buffers_time_ms;
+
double _cur_pre_evacuate_prepare_time_ms;
double _cur_post_evacuate_cleanup_1_time_ms;
@@ -304,6 +306,10 @@ class G1GCPhaseTimes : public CHeapObj {
_cur_prepare_merge_heap_roots_time_ms += ms;
}
+ void record_distribute_log_buffers_time_ms(double ms) {
+ _cur_distribute_log_buffers_time_ms += ms;
+ }
+
void record_or_add_optional_prepare_merge_heap_roots_time(double ms) {
_cur_optional_prepare_merge_heap_roots_time_ms += ms;
}
@@ -376,6 +382,10 @@ class G1GCPhaseTimes : public CHeapObj {
return _cur_collection_start_sec;
}
+ double cur_distribute_log_buffers_time_ms() {
+ return _cur_distribute_log_buffers_time_ms;
+ }
+
double cur_collection_par_time_ms() {
return _cur_collection_initial_evac_time_ms +
_cur_optional_evac_time_ms +
diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp
index 10227dfe2ad..6e2281e12f7 100644
--- a/src/hotspot/share/gc/g1/g1Policy.cpp
+++ b/src/hotspot/share/gc/g1/g1Policy.cpp
@@ -774,6 +774,10 @@ double G1Policy::logged_cards_processing_time() const {
size_t logged_dirty_cards = phase_times()->sum_thread_work_items(G1GCPhaseTimes::MergeLB, G1GCPhaseTimes::MergeLBDirtyCards);
size_t scan_heap_roots_cards = phase_times()->sum_thread_work_items(G1GCPhaseTimes::ScanHR, G1GCPhaseTimes::ScanHRScannedCards) +
phase_times()->sum_thread_work_items(G1GCPhaseTimes::OptScanHR, G1GCPhaseTimes::ScanHRScannedCards);
+
+ double merge_logged_cards_time = average_time_ms(G1GCPhaseTimes::MergeLB) +
+ phase_times()->cur_distribute_log_buffers_time_ms();
+
// Approximate the time spent processing cards from log buffers by scaling
// the total processing time by the ratio of logged cards to total cards
// processed. There might be duplicate cards in different log buffers,
@@ -783,9 +787,9 @@ double G1Policy::logged_cards_processing_time() const {
// counts are zero, which happens especially during early GCs. So ascribe
// all of the time to the logged cards unless there are more total cards.
if (logged_dirty_cards >= scan_heap_roots_cards) {
- return all_cards_processing_time + average_time_ms(G1GCPhaseTimes::MergeLB);
+ return all_cards_processing_time + merge_logged_cards_time;
}
- return (all_cards_processing_time * logged_dirty_cards / scan_heap_roots_cards) + average_time_ms(G1GCPhaseTimes::MergeLB);
+ return (all_cards_processing_time * logged_dirty_cards / scan_heap_roots_cards) + merge_logged_cards_time;
}
// Anything below that is considered to be zero
@@ -874,6 +878,7 @@ void G1Policy::record_young_collection_end(bool concurrent_operation_is_full_mar
double avg_time_merge_cards = average_time_ms(G1GCPhaseTimes::MergeER) +
average_time_ms(G1GCPhaseTimes::MergeRS) +
average_time_ms(G1GCPhaseTimes::MergeLB) +
+ p->cur_distribute_log_buffers_time_ms() +
average_time_ms(G1GCPhaseTimes::OptMergeRS);
_analytics->report_cost_per_card_merge_ms(avg_time_merge_cards / total_cards_merged, is_young_only_pause);
}
diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp
index 21127952214..f8ea3ba7ed4 100644
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp
@@ -1258,39 +1258,90 @@ class G1MergeHeapRootsTask : public WorkerTask {
size_t cards_skipped() const { return _cards_skipped; }
};
- HeapRegionClaimer _hr_claimer;
+ uint _num_workers;
G1RemSetScanState* _scan_state;
- BufferNode::Stack _dirty_card_buffers;
+
+ // To mitigate contention due multiple threads accessing and popping BufferNodes from a shared
+ // G1DirtyCardQueueSet, we implement a sequential distribution phase. Here, BufferNodes are
+ // distributed to worker threads in a sequential manner utilizing the _dirty_card_buffers. By doing
+ // so, we effectively alleviate the bottleneck encountered during pop operations on the
+ // G1DirtyCardQueueSet. Importantly, this approach preserves the helping aspect among worker
+ // threads, allowing them to assist one another in case of imbalances in work distribution.
+ BufferNode::Stack* _dirty_card_buffers;
+
bool _initial_evacuation;
volatile bool _fast_reclaim_handled;
void apply_closure_to_dirty_card_buffers(G1MergeLogBufferCardsClosure* cl, uint worker_id) {
G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
- while (BufferNode* node = _dirty_card_buffers.pop()) {
- cl->apply_to_buffer(node, worker_id);
- dcqs.deallocate_buffer(node);
+ for (uint i = 0; i < _num_workers; i++) {
+ uint index = (worker_id + i) % _num_workers;
+ while (BufferNode* node = _dirty_card_buffers[index].pop()) {
+ cl->apply_to_buffer(node, worker_id);
+ dcqs.deallocate_buffer(node);
+ }
}
}
public:
G1MergeHeapRootsTask(G1RemSetScanState* scan_state, uint num_workers, bool initial_evacuation) :
WorkerTask("G1 Merge Heap Roots"),
- _hr_claimer(num_workers),
+ _num_workers(num_workers),
_scan_state(scan_state),
- _dirty_card_buffers(),
+ _dirty_card_buffers(nullptr),
_initial_evacuation(initial_evacuation),
_fast_reclaim_handled(false)
{
if (initial_evacuation) {
+ Ticks start = Ticks::now();
+
+ _dirty_card_buffers = NEW_C_HEAP_ARRAY(BufferNode::Stack, num_workers, mtGC);
+ for (uint i = 0; i < num_workers; i++) {
+ new (&_dirty_card_buffers[i]) BufferNode::Stack();
+ }
+
G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
BufferNodeList buffers = dcqs.take_all_completed_buffers();
- if (buffers._entry_count != 0) {
- _dirty_card_buffers.prepend(*buffers._head, *buffers._tail);
+
+ size_t entries_per_thread = ceil(buffers._entry_count / (double)num_workers);
+
+ BufferNode* head = buffers._head;
+ BufferNode* tail = head;
+
+ uint worker = 0;
+ while (tail != nullptr) {
+ size_t count = tail->size();
+ BufferNode* cur = tail->next();
+
+ while (count < entries_per_thread && cur != nullptr) {
+ tail = cur;
+ count += tail->size();
+ cur = tail->next();
+ }
+
+ tail->set_next(nullptr);
+ _dirty_card_buffers[worker++ % num_workers].prepend(*head, *tail);
+
+ assert(cur != nullptr || tail == buffers._tail, "Must be");
+ head = cur;
+ tail = cur;
}
+
+ Tickspan total = Ticks::now() - start;
+ G1CollectedHeap::heap()->phase_times()->record_distribute_log_buffers_time_ms(total.seconds() * 1000.0);
}
}
+ ~G1MergeHeapRootsTask() {
+ if (_dirty_card_buffers != nullptr) {
+ using Stack = BufferNode::Stack;
+ for (uint i = 0; i < _num_workers; i++) {
+ _dirty_card_buffers[i].~Stack();
+ }
+ FREE_C_HEAP_ARRAY(Stack, _dirty_card_buffers);
+ }
+ }
virtual void work(uint worker_id) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1GCPhaseTimes* p = g1h->phase_times();
diff --git a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp
index 8738e2bc886..2e28330865a 100644
--- a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp
+++ b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp
@@ -54,72 +54,41 @@ void G1RemSetTrackingPolicy::update_at_free(HeapRegion* r) {
/* nothing to do */
}
-static void print_before_rebuild(HeapRegion* r, bool selected_for_rebuild, size_t total_live_bytes, size_t live_bytes) {
- log_trace(gc, remset, tracking)("Before rebuild region %u "
- "(tams: " PTR_FORMAT ") "
- "total_live_bytes %zu "
- "selected %s "
- "(live_bytes %zu "
- "type %s)",
- r->hrm_index(),
- p2i(r->top_at_mark_start()),
- total_live_bytes,
- BOOL_TO_STR(selected_for_rebuild),
- live_bytes,
- r->get_type_str());
-}
-
-bool G1RemSetTrackingPolicy::update_humongous_before_rebuild(HeapRegion* r, bool is_live) {
+bool G1RemSetTrackingPolicy::update_humongous_before_rebuild(HeapRegion* r) {
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
- assert(r->is_humongous(), "Region %u should be humongous", r->hrm_index());
+ assert(r->is_starts_humongous(), "Region %u should be Humongous", r->hrm_index());
assert(!r->rem_set()->is_updating(), "Remembered set of region %u is updating before rebuild", r->hrm_index());
bool selected_for_rebuild = false;
- // For humongous regions, to be of interest for rebuilding the remembered set the following must apply:
- // - We always try to update the remembered sets of humongous regions containing
- // type arrays as they might have been reset after full gc.
- if (is_live && cast_to_oop(r->humongous_start_region()->bottom())->is_typeArray() && !r->rem_set()->is_tracked()) {
- r->rem_set()->set_state_updating();
+ // Humongous regions containing type-array objs are remset-tracked to
+ // support eager-reclaim. However, their remset state can be reset after
+ // Full-GC. Try to re-enable remset-tracking for them if possible.
+ if (cast_to_oop(r->bottom())->is_typeArray() && !r->rem_set()->is_tracked()) {
+ auto on_humongous_region = [] (HeapRegion* r) {
+ r->rem_set()->set_state_updating();
+ };
+ G1CollectedHeap::heap()->humongous_obj_regions_iterate(r, on_humongous_region);
selected_for_rebuild = true;
}
- size_t const live_bytes = is_live ? HeapRegion::GrainBytes : 0;
- print_before_rebuild(r, selected_for_rebuild, live_bytes, live_bytes);
-
return selected_for_rebuild;
}
-bool G1RemSetTrackingPolicy::update_before_rebuild(HeapRegion* r, size_t live_bytes_below_tams) {
+bool G1RemSetTrackingPolicy::update_old_before_rebuild(HeapRegion* r) {
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
- assert(!r->is_humongous(), "Region %u is humongous", r->hrm_index());
-
- // Only consider updating the remembered set for old gen regions.
- if (!r->is_old()) {
- return false;
- }
+ assert(r->is_old(), "Region %u should be Old", r->hrm_index());
assert(!r->rem_set()->is_updating(), "Remembered set of region %u is updating before rebuild", r->hrm_index());
- size_t live_bytes_above_tams = pointer_delta(r->top(), r->top_at_mark_start()) * HeapWordSize;
- size_t total_live_bytes = live_bytes_below_tams + live_bytes_above_tams;
-
bool selected_for_rebuild = false;
- // For old regions, to be of interest for rebuilding the remembered set the following must apply:
- // - They must contain some live data in them.
- // - Only need to rebuild non-complete remembered sets.
- // - Otherwise only add those old gen regions which occupancy is low enough that there
- // is a chance that we will ever evacuate them in the mixed gcs.
- if ((total_live_bytes > 0) &&
- G1CollectionSetChooser::region_occupancy_low_enough_for_evac(total_live_bytes) &&
- !r->rem_set()->is_tracked()) {
+ if (G1CollectionSetChooser::region_occupancy_low_enough_for_evac(r->live_bytes()) &&
+ !r->rem_set()->is_tracked()) {
r->rem_set()->set_state_updating();
selected_for_rebuild = true;
}
- print_before_rebuild(r, selected_for_rebuild, total_live_bytes, live_bytes_below_tams);
-
return selected_for_rebuild;
}
diff --git a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.hpp b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.hpp
index 94ff2734fbf..abe06d4b190 100644
--- a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.hpp
+++ b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.hpp
@@ -43,10 +43,10 @@ class G1RemSetTrackingPolicy : public CHeapObj {
void update_at_allocate(HeapRegion* r);
// Update remembered set tracking state for humongous regions before we are going to
// rebuild remembered sets. Called at safepoint in the remark pause.
- bool update_humongous_before_rebuild(HeapRegion* r, bool is_live);
- // Update remembered set tracking state before we are going to rebuild remembered
- // sets. Called at safepoint in the remark pause.
- bool update_before_rebuild(HeapRegion* r, size_t live_bytes_below_tams);
+ bool update_humongous_before_rebuild(HeapRegion* r);
+ // Update remembered set tracking state for old regions before we are going
+ // to rebuild remembered sets. Called at safepoint in the remark pause.
+ bool update_old_before_rebuild(HeapRegion* r);
// Update remembered set tracking state after rebuild is complete, i.e. the cleanup
// pause. Called at safepoint.
void update_after_rebuild(HeapRegion* r);
diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
index 961451e5b59..4a74e2d838d 100644
--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
+++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2024, 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
@@ -208,7 +208,8 @@ size_t ParallelScavengeHeap::used() const {
}
bool ParallelScavengeHeap::is_maximal_no_gc() const {
- return old_gen()->is_maximal_no_gc() && young_gen()->is_maximal_no_gc();
+ // We don't expand young-gen except at a GC.
+ return old_gen()->is_maximal_no_gc();
}
diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp
index daff634e81d..b22677529f8 100644
--- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp
@@ -256,11 +256,11 @@ print_generic_summary_region(size_t i, const ParallelCompactData::RegionData* c)
ParallelCompactData& sd = PSParallelCompact::summary_data();
size_t dci = c->destination() ? sd.addr_to_region_idx(c->destination()) : 0;
log_develop_trace(gc, compaction)(
- REGION_IDX_FORMAT " " PTR_FORMAT " "
+ REGION_IDX_FORMAT " "
REGION_IDX_FORMAT " " PTR_FORMAT " "
REGION_DATA_FORMAT " " REGION_DATA_FORMAT " "
REGION_DATA_FORMAT " " REGION_IDX_FORMAT " %d",
- i, p2i(c->data_location()), dci, p2i(c->destination()),
+ i, dci, p2i(c->destination()),
c->partial_obj_size(), c->live_obj_size(),
c->data_size(), c->source_region(), c->destination_count());
@@ -495,12 +495,6 @@ bool ParallelCompactData::initialize_block_data()
return false;
}
-void ParallelCompactData::clear()
-{
- memset(_region_data, 0, _region_vspace->committed_size());
- memset(_block_data, 0, _block_vspace->committed_size());
-}
-
void ParallelCompactData::clear_range(size_t beg_region, size_t end_region) {
assert(beg_region <= _region_count, "beg_region out of range");
assert(end_region <= _region_count, "end_region out of range");
@@ -541,7 +535,6 @@ ParallelCompactData::summarize_dense_prefix(HeapWord* beg, HeapWord* end)
_region_data[cur_region].set_destination(addr);
_region_data[cur_region].set_destination_count(0);
_region_data[cur_region].set_source_region(cur_region);
- _region_data[cur_region].set_data_location(addr);
// Update live_obj_size so the region appears completely full.
size_t live_size = RegionSize - _region_data[cur_region].partial_obj_size();
@@ -735,7 +728,6 @@ bool ParallelCompactData::summarize(SplitInfo& split_info,
}
_region_data[cur_region].set_destination_count(destination_count);
- _region_data[cur_region].set_data_location(region_to_addr(cur_region));
dest_addr += words;
}
@@ -899,7 +891,7 @@ PSParallelCompact::clear_data_covering_space(SpaceId id)
HeapWord* const max_top = MAX2(top, _space_info[id].new_top());
const idx_t beg_bit = _mark_bitmap.addr_to_bit(bot);
- const idx_t end_bit = _mark_bitmap.align_range_end(_mark_bitmap.addr_to_bit(top));
+ const idx_t end_bit = _mark_bitmap.addr_to_bit(top);
_mark_bitmap.clear_range(beg_bit, end_bit);
const size_t beg_region = _summary_data.addr_to_region_idx(bot);
diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp
index d13d374827f..e979f13cdb6 100644
--- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp
@@ -279,9 +279,6 @@ class ParallelCompactData
// Number of times the block table was filled.
DEBUG_ONLY(inline size_t blocks_filled_count() const;)
- // The location of the java heap data that corresponds to this region.
- inline HeapWord* data_location() const;
-
// Whether this region is available to be claimed, has been claimed, or has
// been completed.
//
@@ -304,7 +301,7 @@ class ParallelCompactData
inline void set_destination_count(uint count);
inline void set_live_obj_size(size_t words);
- inline void set_data_location(HeapWord* addr);
+
inline void set_completed();
inline bool claim_unsafe();
@@ -363,11 +360,6 @@ class ParallelCompactData
#ifdef ASSERT
size_t _blocks_filled_count; // Number of block table fills.
-
- // These enable optimizations that are only partially implemented. Use
- // debug builds to prevent the code fragments from breaking.
- HeapWord* _data_location;
- HeapWord* _highest_ref;
#endif // #ifdef ASSERT
#ifdef ASSERT
@@ -420,7 +412,6 @@ class ParallelCompactData
HeapWord* target_beg, HeapWord* target_end,
HeapWord** target_next);
- void clear();
void clear_range(size_t beg_region, size_t end_region);
void clear_range(HeapWord* beg, HeapWord* end) {
clear_range(addr_to_region_idx(beg), addr_to_region_idx(end));
@@ -538,17 +529,6 @@ inline void ParallelCompactData::RegionData::decrement_destination_count()
Atomic::add(&_dc_and_los, dc_mask);
}
-inline HeapWord* ParallelCompactData::RegionData::data_location() const
-{
- DEBUG_ONLY(return _data_location;)
- NOT_DEBUG(return nullptr;)
-}
-
-inline void ParallelCompactData::RegionData::set_data_location(HeapWord* addr)
-{
- DEBUG_ONLY(_data_location = addr;)
-}
-
inline void ParallelCompactData::RegionData::set_completed()
{
assert(claimed(), "must be claimed first");
diff --git a/src/hotspot/share/gc/parallel/psYoungGen.hpp b/src/hotspot/share/gc/parallel/psYoungGen.hpp
index 49742c29e03..fb0bf6cd43e 100644
--- a/src/hotspot/share/gc/parallel/psYoungGen.hpp
+++ b/src/hotspot/share/gc/parallel/psYoungGen.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2024, 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
@@ -123,10 +123,6 @@ class PSYoungGen : public CHeapObj {
size_t min_gen_size() const { return _min_gen_size; }
size_t max_gen_size() const { return _max_gen_size; }
- bool is_maximal_no_gc() const {
- return true; // Never expands except at a GC
- }
-
// Allocation
HeapWord* allocate(size_t word_size) {
HeapWord* result = eden_space()->cas_allocate(word_size);
diff --git a/src/hotspot/share/gc/shared/gcVMOperations.cpp b/src/hotspot/share/gc/shared/gcVMOperations.cpp
index 5f17c828bd7..d4a63605578 100644
--- a/src/hotspot/share/gc/shared/gcVMOperations.cpp
+++ b/src/hotspot/share/gc/shared/gcVMOperations.cpp
@@ -215,11 +215,9 @@ void VM_CollectForMetadataAllocation::doit() {
// Check again if the space is available. Another thread
// may have similarly failed a metadata allocation and induced
// a GC that freed space for the allocation.
- if (!MetadataAllocationFailALot) {
- _result = _loader_data->metaspace_non_null()->allocate(_size, _mdtype);
- if (_result != nullptr) {
- return;
- }
+ _result = _loader_data->metaspace_non_null()->allocate(_size, _mdtype);
+ if (_result != nullptr) {
+ return;
}
#if INCLUDE_G1GC
diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp
index b41bff01e29..1157875b7df 100644
--- a/src/hotspot/share/gc/shared/gc_globals.hpp
+++ b/src/hotspot/share/gc/shared/gc_globals.hpp
@@ -279,13 +279,6 @@
"Number of object array elements to push onto the marking stack " \
"before pushing a continuation entry") \
\
- develop(bool, MetadataAllocationFailALot, false, \
- "Fail metadata allocations at intervals controlled by " \
- "MetadataAllocationFailALotInterval") \
- \
- develop(uintx, MetadataAllocationFailALotInterval, 1000, \
- "Metadata allocation failure a lot interval") \
- \
product_pd(bool, NeverActAsServerClassMachine, \
"Never act like a server-class machine") \
\
diff --git a/src/hotspot/share/gc/shared/referenceProcessor.cpp b/src/hotspot/share/gc/shared/referenceProcessor.cpp
index bfd91becac8..274fbd4c749 100644
--- a/src/hotspot/share/gc/shared/referenceProcessor.cpp
+++ b/src/hotspot/share/gc/shared/referenceProcessor.cpp
@@ -978,10 +978,12 @@ bool ReferenceProcessor::discover_reference(oop obj, ReferenceType rt) {
log_develop_trace(gc, ref)("Already discovered reference (" PTR_FORMAT ": %s)",
p2i(obj), obj->klass()->internal_name());
- // Check assumption that an object is not potentially
- // discovered twice except by concurrent collectors that potentially
- // trace the same Reference object twice.
- assert(UseG1GC, "Only possible with a concurrent marking collector");
+ // Encountering an already-discovered non-strong ref because G1 can restart
+ // concurrent marking on marking-stack overflow. Must continue to treat
+ // this non-strong ref as discovered to avoid keeping the referent
+ // unnecessarily alive.
+ assert(UseG1GC, "inv");
+ assert(_discovery_is_concurrent, "inv");
return true;
}
diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h
index b65f758a0d1..b66e406bbdb 100644
--- a/src/hotspot/share/include/jvm.h
+++ b/src/hotspot/share/include/jvm.h
@@ -200,14 +200,8 @@ JVM_LookupLambdaProxyClassFromArchive(JNIEnv* env, jclass caller,
jobject implementationMember,
jobject dynamicMethodType);
-JNIEXPORT jboolean JNICALL
-JVM_IsCDSDumpingEnabled(JNIEnv* env);
-
-JNIEXPORT jboolean JNICALL
-JVM_IsSharingEnabled(JNIEnv* env);
-
-JNIEXPORT jboolean JNICALL
-JVM_IsDumpingClassList(JNIEnv* env);
+JNIEXPORT jint JNICALL
+JVM_GetCDSConfigStatus();
JNIEXPORT jlong JNICALL
JVM_GetRandomSeedForDumping();
diff --git a/src/hotspot/share/memory/metadataFactory.hpp b/src/hotspot/share/memory/metadataFactory.hpp
index 5930d806562..14cac8dc191 100644
--- a/src/hotspot/share/memory/metadataFactory.hpp
+++ b/src/hotspot/share/memory/metadataFactory.hpp
@@ -36,8 +36,6 @@ class MetadataFactory : AllStatic {
public:
template
static Array* new_array(ClassLoaderData* loader_data, int length, TRAPS) {
- // The "true" argument is because all metadata arrays are read only when
- // dumped to the shared archive
return new (loader_data, length, THREAD) Array(length);
}
diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp
index 573df165d0d..22ec4d942a6 100644
--- a/src/hotspot/share/memory/metaspace.cpp
+++ b/src/hotspot/share/memory/metaspace.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2021 SAP SE. All rights reserved.
* Copyright (c) 2023, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -858,6 +858,7 @@ MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
assert(false, "Should not allocate with exception pending");
return nullptr; // caller does a CHECK_NULL too
}
+ assert(!THREAD->owns_locks(), "allocating metaspace while holding mutex");
MetaWord* result = allocate(loader_data, word_size, type);
diff --git a/src/hotspot/share/memory/virtualspace.cpp b/src/hotspot/share/memory/virtualspace.cpp
index fd73cbb3362..919ab3a6c6a 100644
--- a/src/hotspot/share/memory/virtualspace.cpp
+++ b/src/hotspot/share/memory/virtualspace.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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
@@ -516,9 +516,15 @@ void ReservedHeapSpace::initialize_compressed_heap(const size_t size, size_t ali
// The necessary attach point alignment for generated wish addresses.
// This is needed to increase the chance of attaching for mmap and shmat.
+ // AIX is the only platform that uses System V shm for reserving virtual memory.
+ // In this case, the required alignment of the allocated size (64K) and the alignment
+ // of possible start points of the memory region (256M) differ.
+ // This is not reflected by os_allocation_granularity().
+ // The logic here is dual to the one in pd_reserve_memory in os_aix.cpp
const size_t os_attach_point_alignment =
- AIX_ONLY(SIZE_256M) // Known shm boundary alignment.
+ AIX_ONLY(os::vm_page_size() == 4*K ? 4*K : 256*M)
NOT_AIX(os::vm_allocation_granularity());
+
const size_t attach_point_alignment = lcm(alignment, os_attach_point_alignment);
char *aligned_heap_base_min_address = (char *)align_up((void *)HeapBaseMinAddress, alignment);
diff --git a/src/hotspot/share/nmt/memMapPrinter.cpp b/src/hotspot/share/nmt/memMapPrinter.cpp
index 0de7582e968..85a3ab7510b 100644
--- a/src/hotspot/share/nmt/memMapPrinter.cpp
+++ b/src/hotspot/share/nmt/memMapPrinter.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2023, Red Hat, Inc. and/or its affiliates.
+ * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024, Red Hat, Inc. 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
@@ -157,6 +157,13 @@ class CachedNMTInformation : public VirtualMemoryWalker {
bool fill_from_nmt() {
return VirtualMemoryTracker::walk_virtual_memory(this);
}
+
+ void print_on(outputStream* st) const {
+ for (size_t i = 0; i < _count; i ++) {
+ st->print_cr(PTR_FORMAT "-" PTR_FORMAT " %s", p2i(_ranges[i].from), p2i(_ranges[i].to),
+ NMTUtil::flag_to_enum_name(_flags[i]));
+ }
+ }
};
/////// Thread information //////////////////////////
@@ -297,7 +304,7 @@ void MemMapPrinter::print_all_mappings(outputStream* st, bool human_readable) {
// First collect all NMT information
CachedNMTInformation nmt_info;
nmt_info.fill_from_nmt();
-
+ DEBUG_ONLY(nmt_info.print_on(st);)
st->print_cr("Memory mappings:");
if (!MemTracker::enabled()) {
st->cr();
diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp
index eaa40ed4fcb..60f7b8865ec 100644
--- a/src/hotspot/share/oops/arrayKlass.cpp
+++ b/src/hotspot/share/oops/arrayKlass.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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
@@ -151,27 +151,21 @@ ArrayKlass* ArrayKlass::array_klass(int n, TRAPS) {
// lock-free read needs acquire semantics
if (higher_dimension_acquire() == nullptr) {
- ResourceMark rm(THREAD);
- {
- // Ensure atomic creation of higher dimensions
- MutexLocker mu(THREAD, MultiArray_lock);
-
- // Check if another thread beat us
- if (higher_dimension() == nullptr) {
-
- // Create multi-dim klass object and link them together
- ObjArrayKlass* ak =
- ObjArrayKlass::allocate_objArray_klass(class_loader_data(), dim + 1, this,
- false, CHECK_NULL);
- ak->set_lower_dimension(this);
- // use 'release' to pair with lock-free load
- release_set_higher_dimension(ak);
- assert(ak->is_objArray_klass(), "incorrect initialization of ObjArrayKlass");
- }
+ // Ensure atomic creation of higher dimensions
+ RecursiveLocker rl(MultiArray_lock, THREAD);
+
+ if (higher_dimension() == nullptr) {
+ // Create multi-dim klass object and link them together
+ ObjArrayKlass* ak =
+ ObjArrayKlass::allocate_objArray_klass(class_loader_data(), dim + 1, this, false, CHECK_NULL);
+ // use 'release' to pair with lock-free load
+ release_set_higher_dimension(ak);
+ assert(ak->lower_dimension() == this, "lower dimension mismatch");
}
}
- ObjArrayKlass *ak = higher_dimension();
+ ObjArrayKlass* ak = higher_dimension();
+ assert(ak != nullptr, "should be set");
THREAD->check_possible_safepoint();
return ak->array_klass(n, THREAD);
}
diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp
index a85107d2498..395dc9ec04f 100644
--- a/src/hotspot/share/oops/constantPool.cpp
+++ b/src/hotspot/share/oops/constantPool.cpp
@@ -156,7 +156,7 @@ void ConstantPool::metaspace_pointers_do(MetaspaceClosure* it) {
for (int i = 0; i < length(); i++) {
// The only MSO's embedded in the CP entries are Symbols:
- // JVM_CONSTANT_String (normal and pseudo)
+ // JVM_CONSTANT_String
// JVM_CONSTANT_Utf8
constantTag ctag = tag_at(i);
if (ctag.is_string() || ctag.is_utf8()) {
diff --git a/src/hotspot/share/oops/flatArrayKlass.cpp b/src/hotspot/share/oops/flatArrayKlass.cpp
index 8441efa1768..6ea0c76ba2b 100644
--- a/src/hotspot/share/oops/flatArrayKlass.cpp
+++ b/src/hotspot/share/oops/flatArrayKlass.cpp
@@ -91,6 +91,7 @@ void FlatArrayKlass::set_element_klass(Klass* k) {
FlatArrayKlass* FlatArrayKlass::allocate_klass(Klass* eklass, TRAPS) {
guarantee((!Universe::is_bootstrapping() || vmClasses::Object_klass_loaded()), "Really ?!");
assert(UseFlatArray, "Flatten array required");
+ assert(MultiArray_lock->holds_lock(THREAD), "must hold lock after bootstrapping");
InlineKlass* element_klass = InlineKlass::cast(eklass);
assert(element_klass->is_naturally_atomic() || (!InlineArrayAtomicAccess), "Atomic by-default");
@@ -106,33 +107,15 @@ FlatArrayKlass* FlatArrayKlass::allocate_klass(Klass* eklass, TRAPS) {
Klass* element_super = element_klass->super();
if (element_super != nullptr) {
// The element type has a direct super. E.g., String[] has direct super of Object[].
- super_klass = element_klass->array_klass_or_null();
- bool supers_exist = super_klass != nullptr;
+ super_klass = element_klass->array_klass(CHECK_NULL);
// Also, see if the element has secondary supertypes.
// We need an array type for each.
const Array* element_supers = element_klass->secondary_supers();
for( int i = element_supers->length()-1; i >= 0; i-- ) {
Klass* elem_super = element_supers->at(i);
- if (elem_super->array_klass_or_null() == nullptr) {
- supers_exist = false;
- break;
- }
- }
- if (!supers_exist) {
- // Oops. Not allocated yet. Back out, allocate it, and retry.
- Klass* ek = nullptr;
- {
- MutexUnlocker mu(MultiArray_lock);
- super_klass = element_klass->array_klass(CHECK_NULL);
- for( int i = element_supers->length()-1; i >= 0; i-- ) {
- Klass* elem_super = element_supers->at(i);
- elem_super->array_klass(CHECK_NULL);
- }
- // Now retry from the beginning
- ek = element_klass->value_array_klass(CHECK_NULL);
- } // re-lock
- return FlatArrayKlass::cast(ek);
+ elem_super->array_klass(CHECK_NULL);
}
+ // Fall through because inheritance is acyclic and we hold the global recursive lock to allocate all the arrays.
}
Symbol* name = ArrayKlass::create_element_klass_array_name(element_klass, CHECK_NULL);
@@ -341,62 +324,6 @@ void FlatArrayKlass::copy_array(arrayOop s, int src_pos,
}
}
-
-ArrayKlass* FlatArrayKlass::array_klass(int n, TRAPS) {
- assert(dimension() <= n, "check order of chain");
- int dim = dimension();
- if (dim == n) return this;
-
- // lock-free read needs acquire semantics
- if (higher_dimension_acquire() == nullptr) {
-
- ResourceMark rm(THREAD);
- {
- // Ensure atomic creation of higher dimensions
- MutexLocker mu(THREAD, MultiArray_lock);
-
- // Check if another thread beat us
- if (higher_dimension() == nullptr) {
-
- // Create multi-dim klass object and link them together
- ObjArrayKlass* ak = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), dim + 1, this, false, CHECK_NULL);
- ak->set_lower_dimension(this);
- // use 'release' to pair with lock-free load
- release_set_higher_dimension(ak);
- assert(ak->is_objArray_klass(), "incorrect initialization of ObjArrayKlass");
- }
- }
- }
-
- ObjArrayKlass *ak = ObjArrayKlass::cast(higher_dimension());
- JavaThread::cast(THREAD)->check_possible_safepoint();
- return ak->array_klass(n, THREAD);
-}
-
-ArrayKlass* FlatArrayKlass::array_klass_or_null(int n) {
-
- assert(dimension() <= n, "check order of chain");
- int dim = dimension();
- if (dim == n) return this;
-
- // lock-free read needs acquire semantics
- if (higher_dimension_acquire() == nullptr) {
- return nullptr;
- }
-
- ObjArrayKlass *ak = ObjArrayKlass::cast(higher_dimension());
- return ak->array_klass_or_null(n);
-}
-
-ArrayKlass* FlatArrayKlass::array_klass(TRAPS) {
- return array_klass(dimension() + 1, THREAD);
-}
-
-ArrayKlass* FlatArrayKlass::array_klass_or_null() {
- return array_klass_or_null(dimension() + 1);
-}
-
-
ModuleEntry* FlatArrayKlass::module() const {
assert(element_klass() != nullptr, "FlatArrayKlass returned unexpected nullptr bottom_klass");
// The array is defined in the module of its bottom class
diff --git a/src/hotspot/share/oops/flatArrayKlass.hpp b/src/hotspot/share/oops/flatArrayKlass.hpp
index cbd67dd0588..b926aef4efa 100644
--- a/src/hotspot/share/oops/flatArrayKlass.hpp
+++ b/src/hotspot/share/oops/flatArrayKlass.hpp
@@ -47,14 +47,6 @@ class FlatArrayKlass : public ArrayKlass {
FlatArrayKlass() {}
- // Returns the ObjArrayKlass for n'th dimension.
- virtual ArrayKlass* array_klass(int n, TRAPS);
- virtual ArrayKlass* array_klass_or_null(int n);
-
- // Returns the array class with this class as element type.
- virtual ArrayKlass* array_klass(TRAPS);
- virtual ArrayKlass* array_klass_or_null();
-
virtual InlineKlass* element_klass() const;
virtual void set_element_klass(Klass* k);
diff --git a/src/hotspot/share/oops/inlineKlass.cpp b/src/hotspot/share/oops/inlineKlass.cpp
index 7ed57a3096c..f269494bc62 100644
--- a/src/hotspot/share/oops/inlineKlass.cpp
+++ b/src/hotspot/share/oops/inlineKlass.cpp
@@ -185,24 +185,20 @@ bool InlineKlass::flat_array() {
Klass* InlineKlass::value_array_klass(int n, TRAPS) {
if (Atomic::load_acquire(adr_value_array_klasses()) == nullptr) {
- ResourceMark rm(THREAD);
- JavaThread *jt = JavaThread::cast(THREAD);
- {
- // Atomic creation of array_klasses
- MutexLocker ma(THREAD, MultiArray_lock);
-
- // Check if update has already taken place
- if (value_array_klasses() == nullptr) {
- ArrayKlass* k;
- if (flat_array()) {
- k = FlatArrayKlass::allocate_klass(this, CHECK_NULL);
- } else {
- k = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), 1, this, true, CHECK_NULL);
+ // Atomic creation of array_klasses
+ RecursiveLocker rl(MultiArray_lock, THREAD);
+
+ // Check if update has already taken place
+ if (value_array_klasses() == nullptr) {
+ ArrayKlass* k;
+ if (flat_array()) {
+ k = FlatArrayKlass::allocate_klass(this, CHECK_NULL);
+ } else {
+ k = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), 1, this, true, CHECK_NULL);
- }
- // use 'release' to pair with lock-free load
- Atomic::release_store(adr_value_array_klasses(), k);
}
+ // use 'release' to pair with lock-free load
+ Atomic::release_store(adr_value_array_klasses(), k);
}
}
ArrayKlass* ak = value_array_klasses();
diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp
index 66ecd32a1f4..4fed3968399 100644
--- a/src/hotspot/share/oops/instanceKlass.cpp
+++ b/src/hotspot/share/oops/instanceKlass.cpp
@@ -1769,23 +1769,21 @@ void InstanceKlass::check_valid_for_instantiation(bool throwError, TRAPS) {
ArrayKlass* InstanceKlass::array_klass(int n, TRAPS) {
// Need load-acquire for lock-free read
if (array_klasses_acquire() == nullptr) {
- ResourceMark rm(THREAD);
- JavaThread *jt = THREAD;
- {
- // Atomic creation of array_klasses
- MutexLocker ma(THREAD, MultiArray_lock);
-
- // Check if update has already taken place
- if (array_klasses() == nullptr) {
- ObjArrayKlass* k = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), 1, this,
- false, CHECK_NULL);
- // use 'release' to pair with lock-free load
- release_set_array_klasses(k);
- }
+
+ // Recursively lock array allocation
+ RecursiveLocker rl(MultiArray_lock, THREAD);
+
+ // Check if another thread created the array klass while we were waiting for the lock.
+ if (array_klasses() == nullptr) {
+ ObjArrayKlass* k = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), 1, this, false, CHECK_NULL);
+ // use 'release' to pair with lock-free load
+ release_set_array_klasses(k);
}
}
+
// array_klasses() will always be set at this point
ArrayKlass* ak = array_klasses();
+ assert(ak != nullptr, "should be set");
return ak->array_klass(n, THREAD);
}
@@ -2942,7 +2940,7 @@ void InstanceKlass::init_shared_package_entry() {
_package_entry = PackageEntry::get_archived_entry(_package_entry);
}
} else if (CDSConfig::is_dumping_dynamic_archive() &&
- CDSConfig::is_loading_full_module_graph() &&
+ CDSConfig::is_using_full_module_graph() &&
MetaspaceShared::is_in_shared_metaspace(_package_entry)) {
// _package_entry is an archived package in the base archive. Leave it as is.
} else {
@@ -3003,7 +3001,7 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl
if (array_klasses() != nullptr) {
// To get a consistent list of classes we need MultiArray_lock to ensure
// array classes aren't observed while they are being restored.
- MutexLocker ml(MultiArray_lock);
+ RecursiveLocker rl(MultiArray_lock, THREAD);
assert(this == ObjArrayKlass::cast(array_klasses())->bottom_klass(), "sanity");
// Array classes have null protection domain.
// --> see ArrayKlass::complete_create_array_klass()
@@ -3275,7 +3273,7 @@ void InstanceKlass::set_package(ClassLoaderData* loader_data, PackageEntry* pkg_
}
if (is_shared() && _package_entry != nullptr) {
- if (CDSConfig::is_loading_full_module_graph() && _package_entry == pkg_entry) {
+ if (CDSConfig::is_using_full_module_graph() && _package_entry == pkg_entry) {
// we can use the saved package
assert(MetaspaceShared::is_in_shared_metaspace(_package_entry), "must be");
return;
diff --git a/src/hotspot/share/oops/objArrayKlass.cpp b/src/hotspot/share/oops/objArrayKlass.cpp
index 68236c51ad4..91a3a4d7871 100644
--- a/src/hotspot/share/oops/objArrayKlass.cpp
+++ b/src/hotspot/share/oops/objArrayKlass.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -65,53 +65,23 @@ ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_da
// Eagerly allocate the direct array supertype.
Klass* super_klass = nullptr;
if (!Universe::is_bootstrapping() || vmClasses::Object_klass_loaded()) {
+ assert(MultiArray_lock->holds_lock(THREAD), "must hold lock after bootstrapping");
Klass* element_super = element_klass->super();
if (element_super != nullptr) {
// The element type has a direct super. E.g., String[] has direct super of Object[].
+ // Also, see if the element has secondary supertypes.
+ // We need an array type for each before creating this array type.
if (null_free) {
- super_klass = element_klass->array_klass_or_null();
+ super_klass = element_klass->array_klass(CHECK_NULL);
} else {
- super_klass = element_super->array_klass_or_null();
+ super_klass = element_super->array_klass(CHECK_NULL);
}
- bool supers_exist = super_klass != nullptr;
- // Also, see if the element has secondary supertypes.
- // We need an array type for each.
const Array* element_supers = element_klass->secondary_supers();
- for( int i = element_supers->length()-1; i >= 0; i-- ) {
+ for (int i = element_supers->length() - 1; i >= 0; i--) {
Klass* elem_super = element_supers->at(i);
- if (elem_super->array_klass_or_null() == nullptr) {
- supers_exist = false;
- break;
- }
- }
- if (null_free) {
- if (element_klass->array_klass_or_null() == nullptr) {
- supers_exist = false;
- }
- }
- if (!supers_exist) {
- // Oops. Not allocated yet. Back out, allocate it, and retry.
- Klass* ek = nullptr;
- {
- MutexUnlocker mu(MultiArray_lock);
- if (null_free) {
- element_klass->array_klass(CHECK_NULL);
- } else {
- element_super->array_klass(CHECK_NULL);
- }
- for( int i = element_supers->length()-1; i >= 0; i-- ) {
- Klass* elem_super = element_supers->at(i);
- elem_super->array_klass(CHECK_NULL);
- }
- // Now retry from the beginning
- if (null_free) {
- ek = InlineKlass::cast(element_klass)->value_array_klass(CHECK_NULL);
- } else {
- ek = element_klass->array_klass(n, CHECK_NULL);
- }
- } // re-lock
- return ObjArrayKlass::cast(ek);
+ elem_super->array_klass(CHECK_NULL);
}
+ // Fall through because inheritance is acyclic and we hold the global recursive lock to allocate all the arrays.
} else {
// The element type is already Object. Object[] has direct super of Object.
super_klass = vmClasses::Object_klass();
@@ -156,6 +126,10 @@ ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name, bool nul
set_bottom_klass(bk);
set_class_loader_data(bk->class_loader_data());
+ if (element_klass->is_array_klass()) {
+ set_lower_dimension(ArrayKlass::cast(element_klass));
+ }
+
int lh = array_layout_helper(T_OBJECT);
if (null_free) {
assert(n == 1, "Bytecode does not support null-free multi-dim");
diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp
index fd0576832cf..7fa4bc758c8 100644
--- a/src/hotspot/share/opto/loopPredicate.cpp
+++ b/src/hotspot/share/opto/loopPredicate.cpp
@@ -215,14 +215,16 @@ IfProjNode* PhaseIdealLoop::create_new_if_for_predicate(ParsePredicateSuccessPro
// Update ctrl and control inputs of all data nodes starting from 'node' to 'new_ctrl' which have 'old_ctrl' as
// current ctrl.
-void PhaseIdealLoop::set_ctrl_of_nodes_with_same_ctrl(Node* node, ProjNode* old_ctrl, Node* new_ctrl) {
- Unique_Node_List nodes_with_same_ctrl = find_nodes_with_same_ctrl(node, old_ctrl);
- for (uint j = 0; j < nodes_with_same_ctrl.size(); j++) {
- Node* next = nodes_with_same_ctrl[j];
- if (next->in(0) == old_ctrl) {
- _igvn.replace_input_of(next, 0, new_ctrl);
+void PhaseIdealLoop::set_ctrl_of_nodes_with_same_ctrl(Node* start_node, ProjNode* old_uncommon_proj,
+ Node* new_uncommon_proj) {
+ ResourceMark rm;
+ const Unique_Node_List nodes_with_same_ctrl = find_nodes_with_same_ctrl(start_node, old_uncommon_proj);
+ for (uint i = 0; i < nodes_with_same_ctrl.size(); i++) {
+ Node* node = nodes_with_same_ctrl[i];
+ if (node->in(0) == old_uncommon_proj) {
+ _igvn.replace_input_of(node, 0, new_uncommon_proj);
}
- set_ctrl(next, new_ctrl);
+ set_ctrl(node, new_uncommon_proj);
}
}
@@ -242,61 +244,31 @@ Unique_Node_List PhaseIdealLoop::find_nodes_with_same_ctrl(Node* node, const Pro
return nodes_with_same_ctrl;
}
-// Clone all nodes with the same ctrl as 'old_ctrl' starting from 'node' by following its inputs. Rewire the cloned nodes
-// to 'new_ctrl'. Returns the clone of 'node'.
-Node* PhaseIdealLoop::clone_nodes_with_same_ctrl(Node* node, ProjNode* old_ctrl, Node* new_ctrl) {
+// Clone all data nodes with a ctrl to the old uncommon projection from `start_node' by following its inputs. Rewire the
+// cloned nodes to the new uncommon projection. Returns the clone of the `start_node`.
+Node* PhaseIdealLoop::clone_nodes_with_same_ctrl(Node* start_node, ProjNode* old_uncommon_proj, Node* new_uncommon_proj) {
+ ResourceMark rm;
DEBUG_ONLY(uint last_idx = C->unique();)
- Unique_Node_List nodes_with_same_ctrl = find_nodes_with_same_ctrl(node, old_ctrl);
- Dict old_new_mapping = clone_nodes(nodes_with_same_ctrl); // Cloned but not rewired, yet
- rewire_cloned_nodes_to_ctrl(old_ctrl, new_ctrl, nodes_with_same_ctrl, old_new_mapping);
- Node* clone_phi_input = static_cast(old_new_mapping[node]);
- assert(clone_phi_input != nullptr && clone_phi_input->_idx >= last_idx, "must exist and be a proper clone");
- return clone_phi_input;
+ const Unique_Node_List nodes_with_same_ctrl = find_nodes_with_same_ctrl(start_node, old_uncommon_proj);
+ DataNodeGraph data_node_graph(nodes_with_same_ctrl, this);
+ const OrigToNewHashtable& orig_to_clone = data_node_graph.clone(new_uncommon_proj);
+ fix_cloned_data_node_controls(old_uncommon_proj, new_uncommon_proj, orig_to_clone);
+ Node** cloned_node_ptr = orig_to_clone.get(start_node);
+ assert(cloned_node_ptr != nullptr && (*cloned_node_ptr)->_idx >= last_idx, "must exist and be a proper clone");
+ return *cloned_node_ptr;
}
-// Clone all the nodes on 'list_to_clone' and return an old->new mapping.
-Dict PhaseIdealLoop::clone_nodes(const Node_List& list_to_clone) {
- Dict old_new_mapping(cmpkey, hashkey);
- for (uint i = 0; i < list_to_clone.size(); i++) {
- Node* next = list_to_clone[i];
- Node* clone = next->clone();
- _igvn.register_new_node_with_optimizer(clone);
- old_new_mapping.Insert(next, clone);
- }
- return old_new_mapping;
-}
-
-// Rewire inputs of the unprocessed cloned nodes (inputs are not updated, yet, and still point to the old nodes) by
-// using the old_new_mapping.
-void PhaseIdealLoop::rewire_cloned_nodes_to_ctrl(const ProjNode* old_ctrl, Node* new_ctrl,
- const Node_List& nodes_with_same_ctrl, const Dict& old_new_mapping) {
- for (uint i = 0; i < nodes_with_same_ctrl.size(); i++) {
- Node* next = nodes_with_same_ctrl[i];
- Node* clone = static_cast(old_new_mapping[next]);
- if (next->in(0) == old_ctrl) {
- // All data nodes with a control input to the uncommon projection in the chain need to be rewired to the new uncommon
- // projection (could not only be the last data node in the chain but also, for example, a DivNode within the chain).
- _igvn.replace_input_of(clone, 0, new_ctrl);
- set_ctrl(clone, new_ctrl);
+// All data nodes with a control input to the uncommon projection in the chain need to be rewired to the new uncommon
+// projection (could not only be the last data node in the chain but also, for example, a pinned DivNode within the chain).
+void PhaseIdealLoop::fix_cloned_data_node_controls(const ProjNode* old_uncommon_proj, Node* new_uncommon_proj,
+ const OrigToNewHashtable& orig_to_clone) {
+ auto orig_clone_action = [&](Node* orig, Node* clone) {
+ if (orig->in(0) == old_uncommon_proj) {
+ _igvn.replace_input_of(clone, 0, new_uncommon_proj);
+ set_ctrl(clone, new_uncommon_proj);
}
- rewire_inputs_of_clones_to_clones(new_ctrl, clone, old_new_mapping, next);
- }
-}
-
-// Rewire the inputs of the cloned nodes to the old nodes to the new clones.
-void PhaseIdealLoop::rewire_inputs_of_clones_to_clones(Node* new_ctrl, Node* clone, const Dict& old_new_mapping,
- const Node* next) {
- for (uint i = 1; i < next->req(); i++) {
- Node* in = next->in(i);
- if (!in->is_Phi()) {
- assert(!in->is_CFG(), "must be data node");
- Node* in_clone = static_cast(old_new_mapping[in]);
- if (in_clone != nullptr) {
- _igvn.replace_input_of(clone, i, in_clone);
- set_ctrl(clone, new_ctrl);
- }
- }
- }
+ };
+ orig_to_clone.iterate_all(orig_clone_action);
}
IfProjNode* PhaseIdealLoop::clone_parse_predicate_to_unswitched_loop(ParsePredicateSuccessProj* parse_predicate_proj,
diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp
index dff3c716644..17ce7558fab 100644
--- a/src/hotspot/share/opto/loopnode.hpp
+++ b/src/hotspot/share/opto/loopnode.hpp
@@ -1346,13 +1346,11 @@ class PhaseIdealLoop : public PhaseTransform {
private:
// Helper functions for create_new_if_for_predicate()
- void set_ctrl_of_nodes_with_same_ctrl(Node* node, ProjNode* old_ctrl, Node* new_ctrl);
+ void set_ctrl_of_nodes_with_same_ctrl(Node* start_node, ProjNode* old_uncommon_proj, Node* new_uncommon_proj);
Unique_Node_List find_nodes_with_same_ctrl(Node* node, const ProjNode* ctrl);
- Node* clone_nodes_with_same_ctrl(Node* node, ProjNode* old_ctrl, Node* new_ctrl);
- Dict clone_nodes(const Node_List& list_to_clone);
- void rewire_cloned_nodes_to_ctrl(const ProjNode* old_ctrl, Node* new_ctrl, const Node_List& nodes_with_same_ctrl,
- const Dict& old_new_mapping);
- void rewire_inputs_of_clones_to_clones(Node* new_ctrl, Node* clone, const Dict& old_new_mapping, const Node* next);
+ Node* clone_nodes_with_same_ctrl(Node* start_node, ProjNode* old_uncommon_proj, Node* new_uncommon_proj);
+ void fix_cloned_data_node_controls(const ProjNode* orig, Node* new_uncommon_proj,
+ const OrigToNewHashtable& orig_to_clone);
bool has_dominating_loop_limit_check(Node* init_trip, Node* limit, jlong stride_con, BasicType iv_bt,
Node* loop_entry);
@@ -1889,4 +1887,42 @@ class PathFrequency {
float to(Node* n);
};
+// Class to clone a data node graph by taking a list of data nodes. This is done in 2 steps:
+// 1. Clone the data nodes
+// 2. Fix the cloned data inputs pointing to the old nodes to the cloned inputs by using an old->new mapping.
+class DataNodeGraph : public StackObj {
+ PhaseIdealLoop* const _phase;
+ const Unique_Node_List& _data_nodes;
+ OrigToNewHashtable _orig_to_new;
+
+ public:
+ DataNodeGraph(const Unique_Node_List& data_nodes, PhaseIdealLoop* phase)
+ : _phase(phase),
+ _data_nodes(data_nodes),
+ // Use 107 as best guess which is the first resize value in ResizeableResourceHashtable::large_table_sizes.
+ _orig_to_new(107, MaxNodeLimit)
+ {
+#ifdef ASSERT
+ for (uint i = 0; i < data_nodes.size(); i++) {
+ assert(!data_nodes[i]->is_CFG(), "only data nodes");
+ }
+#endif
+ }
+ NONCOPYABLE(DataNodeGraph);
+
+ private:
+ void clone(Node* node, Node* new_ctrl);
+ void clone_data_nodes(Node* new_ctrl);
+ void rewire_clones_to_cloned_inputs();
+
+ public:
+ // Clone the provided data node collection and rewire the clones in such a way to create an identical graph copy.
+ // Set 'new_ctrl' as ctrl for the cloned nodes.
+ const OrigToNewHashtable& clone(Node* new_ctrl) {
+ assert(_orig_to_new.number_of_entries() == 0, "should not call this method twice in a row");
+ clone_data_nodes(new_ctrl);
+ rewire_clones_to_cloned_inputs();
+ return _orig_to_new;
+ }
+};
#endif // SHARE_OPTO_LOOPNODE_HPP
diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp
index 3c7e293f975..5d9a82449c6 100644
--- a/src/hotspot/share/opto/loopopts.cpp
+++ b/src/hotspot/share/opto/loopopts.cpp
@@ -4675,3 +4675,31 @@ void PhaseIdealLoop::move_unordered_reduction_out_of_loop(IdealLoopTree* loop) {
assert(phi->outcnt() == 1, "accumulator is the only use of phi");
}
}
+
+void DataNodeGraph::clone_data_nodes(Node* new_ctrl) {
+ for (uint i = 0; i < _data_nodes.size(); i++) {
+ clone(_data_nodes[i], new_ctrl);
+ }
+}
+
+// Clone the given node and set it up properly. Set `new_ctrl` as ctrl.
+void DataNodeGraph::clone(Node* node, Node* new_ctrl) {
+ Node* clone = node->clone();
+ _phase->igvn().register_new_node_with_optimizer(clone);
+ _orig_to_new.put(node, clone);
+ _phase->set_ctrl(clone, new_ctrl);
+}
+
+// Rewire the data inputs of all (unprocessed) cloned nodes, whose inputs are still pointing to the same inputs as their
+// corresponding orig nodes, to the newly cloned inputs to create a separate cloned graph.
+void DataNodeGraph::rewire_clones_to_cloned_inputs() {
+ _orig_to_new.iterate_all([&](Node* node, Node* clone) {
+ for (uint i = 1; i < node->req(); i++) {
+ Node** cloned_input = _orig_to_new.get(node->in(i));
+ if (cloned_input != nullptr) {
+ // Input was also cloned -> rewire clone to the cloned input.
+ _phase->igvn().replace_input_of(clone, i, *cloned_input);
+ }
+ }
+ });
+}
diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp
index f5252ebc9af..0a387a6e322 100644
--- a/src/hotspot/share/opto/node.hpp
+++ b/src/hotspot/share/opto/node.hpp
@@ -211,6 +211,8 @@ typedef Node** DUIterator_Fast;
typedef Node** DUIterator_Last;
#endif
+typedef ResizeableResourceHashtable OrigToNewHashtable;
+
// Node Sentinel
#define NodeSentinel (Node*)-1
diff --git a/src/hotspot/share/opto/replacednodes.cpp b/src/hotspot/share/opto/replacednodes.cpp
index 4ed0be6d346..31c4c55c93a 100644
--- a/src/hotspot/share/opto/replacednodes.cpp
+++ b/src/hotspot/share/opto/replacednodes.cpp
@@ -207,7 +207,7 @@ void ReplacedNodes::apply(Compile* C, Node* ctl) {
hash_table_size++;
}
// Map from current node to cloned/replaced node
- ResizeableResourceHashtable clones(hash_table_size, hash_table_size);
+ OrigToNewHashtable clones(hash_table_size, hash_table_size);
// Record mapping from initial to improved nodes
for (int i = 0; i < _replaced_nodes->length(); i++) {
ReplacedNode replaced = _replaced_nodes->at(i);
diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp
index ef4bae89426..d5b05426a89 100644
--- a/src/hotspot/share/opto/superword.cpp
+++ b/src/hotspot/share/opto/superword.cpp
@@ -46,7 +46,6 @@ SuperWord::SuperWord(const VLoopAnalyzer &vloop_analyzer) :
_node_info(arena(), _vloop.estimated_body_length(), 0, SWNodeInfo::initial), // info needed per node
_clone_map(phase()->C->clone_map()), // map of nodes created in cloning
_align_to_ref(nullptr), // memory reference to align vectors to
- _dg(arena()), // dependence graph
_race_possible(false), // cases where SDMU is true
_do_vector_loop(phase()->C->do_vector_loop()), // whether to do vectorization/simd style
_num_work_vecs(0), // amount of vector work we have
@@ -452,12 +451,6 @@ bool SuperWord::SLP_extract() {
// Ensure extra info is allocated.
initialize_node_info();
- // build _dg
- dependence_graph();
-
- // compute function depth(Node*)
- compute_max_depth();
-
// Attempt vectorization
find_adjacent_refs();
@@ -475,10 +468,14 @@ bool SuperWord::SLP_extract() {
combine_pairs_to_longer_packs();
- split_packs_longer_than_max_vector_size();
+ construct_my_pack_map();
+
+ split_packs_at_use_def_boundaries(); // a first time: create natural boundaries
+ split_packs_only_implemented_with_smaller_size();
+ split_packs_to_break_mutual_dependence();
+ split_packs_at_use_def_boundaries(); // again: propagate split of other packs
// Now we only remove packs:
- construct_my_pack_map();
filter_packs_for_power_of_2_size();
filter_packs_for_mutual_independence();
filter_packs_for_alignment();
@@ -749,86 +746,6 @@ int SuperWord::get_iv_adjustment(MemNode* mem_ref) {
return iv_adjustment;
}
-//---------------------------dependence_graph---------------------------
-// Construct dependency graph.
-// Add dependence edges to load/store nodes for memory dependence
-// A.out()->DependNode.in(1) and DependNode.out()->B.prec(x)
-void SuperWord::dependence_graph() {
- CountedLoopNode *cl = lpt()->_head->as_CountedLoop();
- assert(cl->is_main_loop(), "SLP should only work on main loops");
-
- // First, assign a dependence node to each memory node
- for (int i = 0; i < body().length(); i++ ) {
- Node* n = body().at(i);
- if (n->is_Mem() || n->is_memory_phi()) {
- _dg.make_node(n);
- }
- }
-
- const GrowableArray& mem_slice_head = _vloop_analyzer.memory_slices().heads();
- const GrowableArray& mem_slice_tail = _vloop_analyzer.memory_slices().tails();
-
- ResourceMark rm;
- GrowableArray slice_nodes;
-
- // For each memory slice, create the dependences
- for (int i = 0; i < mem_slice_head.length(); i++) {
- PhiNode* head = mem_slice_head.at(i);
- MemNode* tail = mem_slice_tail.at(i);
-
- // Get slice in predecessor order (last is first)
- _vloop_analyzer.memory_slices().get_slice_in_reverse_order(head, tail, slice_nodes);
-
- // Make the slice dependent on the root
- DepMem* slice = _dg.dep(head);
- _dg.make_edge(_dg.root(), slice);
-
- // Create a sink for the slice
- DepMem* slice_sink = _dg.make_node(nullptr);
- _dg.make_edge(slice_sink, _dg.tail());
-
- // Now visit each pair of memory ops, creating the edges
- for (int j = slice_nodes.length() - 1; j >= 0 ; j--) {
- Node* s1 = slice_nodes.at(j);
-
- // If no dependency yet, use slice
- if (_dg.dep(s1)->in_cnt() == 0) {
- _dg.make_edge(slice, s1);
- }
- VPointer p1(s1->as_Mem(), _vloop);
- bool sink_dependent = true;
- for (int k = j - 1; k >= 0; k--) {
- Node* s2 = slice_nodes.at(k);
- if (s1->is_Load() && s2->is_Load())
- continue;
- VPointer p2(s2->as_Mem(), _vloop);
-
- int cmp = p1.cmp(p2);
- if (!VPointer::not_equal(cmp)) {
- // Possibly same address
- _dg.make_edge(s1, s2);
- sink_dependent = false;
- }
- }
- if (sink_dependent) {
- _dg.make_edge(s1, slice_sink);
- }
- }
-
-#ifndef PRODUCT
- if (is_trace_superword_dependence_graph()) {
- tty->print_cr("\nDependence graph for slice: %d", head->_idx);
- for (int q = 0; q < slice_nodes.length(); q++) {
- _dg.print(slice_nodes.at(q));
- }
- tty->cr();
- }
-#endif
-
- slice_nodes.clear();
- }
-}
-
void VLoopMemorySlices::find_memory_slices() {
assert(_heads.is_empty(), "not yet computed");
assert(_tails.is_empty(), "not yet computed");
@@ -861,7 +778,7 @@ void VLoopMemorySlices::print() const {
#endif
// Get all memory nodes of a slice, in reverse order
-void VLoopMemorySlices::get_slice_in_reverse_order(PhiNode* head, MemNode* tail, GrowableArray &slice) const {
+void VLoopMemorySlices::get_slice_in_reverse_order(PhiNode* head, MemNode* tail, GrowableArray &slice) const {
assert(slice.is_empty(), "start empty");
Node* n = tail;
Node* prev = nullptr;
@@ -871,7 +788,7 @@ void VLoopMemorySlices::get_slice_in_reverse_order(PhiNode* head, MemNode* tail,
Node* out = n->fast_out(i);
if (out->is_Load()) {
if (_vloop.in_bb(out)) {
- slice.push(out);
+ slice.push(out->as_Load());
}
} else {
// FIXME
@@ -889,7 +806,7 @@ void VLoopMemorySlices::get_slice_in_reverse_order(PhiNode* head, MemNode* tail,
}//else
}//for
if (n == head) { break; }
- slice.push(n);
+ slice.push(n->as_Mem());
prev = n;
assert(n->is_Mem(), "unexpected node %s", n->Name());
n = n->in(MemNode::Memory);
@@ -922,7 +839,9 @@ bool SuperWord::stmts_can_pack(Node* s1, Node* s2, int align) {
return false; // No vectors for this type
}
- if (isomorphic(s1, s2)) {
+ // Forbid anything that looks like a PopulateIndex to be packed. It does not need to be packed,
+ // and will still be vectorized by SuperWord::vector_opd.
+ if (isomorphic(s1, s2) && !is_populate_index(s1, s2)) {
if ((independent(s1, s2) && have_similar_inputs(s1, s2)) || reduction(s1, s2)) {
if (!exists_at(s1, 0) && !exists_at(s2, 1)) {
if (!s1->is_Mem() || are_adjacent_refs(s1, s2)) {
@@ -1001,9 +920,20 @@ bool SuperWord::isomorphic(Node* s1, Node* s2) {
}
}
-//------------------------------independent---------------------------
+// Look for pattern n1 = (iv + c) and n2 = (iv + c + 1), which may lead to PopulateIndex vector node.
+// We skip the pack creation of these nodes. They will be vectorized by SuperWord::vector_opd.
+bool SuperWord::is_populate_index(const Node* n1, const Node* n2) const {
+ return n1->is_Add() &&
+ n2->is_Add() &&
+ n1->in(1) == iv() &&
+ n2->in(1) == iv() &&
+ n1->in(2)->is_Con() &&
+ n2->in(2)->is_Con() &&
+ n2->in(2)->get_int() - n1->in(2)->get_int() == 1;
+}
+
// Is there no data path from s1 to s2 or s2 to s1?
-bool SuperWord::independent(Node* s1, Node* s2) {
+bool VLoopDependencyGraph::independent(Node* s1, Node* s2) const {
int d1 = depth(s1);
int d2 = depth(s2);
@@ -1024,9 +954,9 @@ bool SuperWord::independent(Node* s1, Node* s2) {
worklist.push(deep);
for (uint i = 0; i < worklist.size(); i++) {
Node* n = worklist.at(i);
- for (DepPreds preds(n, _dg); !preds.done(); preds.next()) {
+ for (PredsIterator preds(*this, n); !preds.done(); preds.next()) {
Node* pred = preds.current();
- if (in_bb(pred) && depth(pred) >= min_d) {
+ if (_vloop.in_bb(pred) && depth(pred) >= min_d) {
if (pred == shallow) {
return false; // found it -> dependent
}
@@ -1045,7 +975,7 @@ bool SuperWord::independent(Node* s1, Node* s2) {
// is the smallest depth of all nodes from the nodes list. Once we have
// traversed all those nodes, and have not found another node from the
// nodes list, we know that all nodes in the nodes list are independent.
-bool SuperWord::mutually_independent(const Node_List* nodes) const {
+bool VLoopDependencyGraph::mutually_independent(const Node_List* nodes) const {
ResourceMark rm;
Unique_Node_List worklist;
VectorSet nodes_set;
@@ -1054,14 +984,14 @@ bool SuperWord::mutually_independent(const Node_List* nodes) const {
Node* n = nodes->at(k);
min_d = MIN2(min_d, depth(n));
worklist.push(n); // start traversal at all nodes in nodes list
- nodes_set.set(bb_idx(n));
+ nodes_set.set(_body.bb_idx(n));
}
for (uint i = 0; i < worklist.size(); i++) {
Node* n = worklist.at(i);
- for (DepPreds preds(n, _dg); !preds.done(); preds.next()) {
+ for (PredsIterator preds(*this, n); !preds.done(); preds.next()) {
Node* pred = preds.current();
- if (in_bb(pred) && depth(pred) >= min_d) {
- if (nodes_set.test(bb_idx(pred))) {
+ if (_vloop.in_bb(pred) && depth(pred) >= min_d) {
+ if (nodes_set.test(_body.bb_idx(pred))) {
return false; // found one -> dependent
}
worklist.push(pred);
@@ -1472,60 +1402,199 @@ void SuperWord::combine_pairs_to_longer_packs() {
#endif
}
-void SuperWord::split_packs_longer_than_max_vector_size() {
- assert(!_packset.is_empty(), "packset not empty");
- DEBUG_ONLY( int old_packset_length = _packset.length(); )
+SuperWord::SplitStatus SuperWord::split_pack(const char* split_name,
+ Node_List* pack,
+ SplitTask task)
+{
+ uint pack_size = pack->size();
- for (int i = 0; i < _packset.length(); i++) {
- Node_List* pack = _packset.at(i);
- assert(pack != nullptr, "no nullptr in packset");
- uint max_vlen = max_vector_size_in_def_use_chain(pack->at(0));
- assert(is_power_of_2(max_vlen), "sanity");
- uint pack_size = pack->size();
- if (pack_size <= max_vlen) {
- continue;
- }
- // Split off the "upper" nodes into new packs
- Node_List* new_pack = new Node_List();
- for (uint j = max_vlen; j < pack_size; j++) {
- Node* n = pack->at(j);
- // is new_pack full?
- if (new_pack->size() >= max_vlen) {
- assert(is_power_of_2(new_pack->size()), "sanity %d", new_pack->size());
- _packset.append(new_pack);
- new_pack = new Node_List();
- }
- new_pack->push(n);
- }
- // remaining new_pack
- if (new_pack->size() > 1) {
- _packset.append(new_pack);
- } else {
+ if (task.is_unchanged()) {
+ return SplitStatus::make_unchanged(pack);
+ }
+
+ if (task.is_rejected()) {
#ifndef PRODUCT
if (is_trace_superword_rejections()) {
tty->cr();
- tty->print_cr("WARNING: Node dropped out of odd size pack:");
- new_pack->at(0)->dump();
+ tty->print_cr("WARNING: Removed pack during split: %s:", task.message());
print_pack(pack);
}
#endif
+ for (uint i = 0; i < pack_size; i++) {
+ Node* n = pack->at(i);
+ set_my_pack(n, nullptr);
}
- // truncate
- while (pack->size() > max_vlen) {
- pack->pop();
+ return SplitStatus::make_rejected();
+ }
+
+ uint split_size = task.split_size();
+ assert(0 < split_size && split_size < pack_size, "split_size must be in range");
+
+ // Split the size
+ uint new_size = split_size;
+ uint old_size = pack_size - new_size;
+
+#ifndef PRODUCT
+ if (is_trace_superword_packset()) {
+ tty->cr();
+ tty->print_cr("INFO: splitting pack (sizes: %d %d): %s:",
+ old_size, new_size, task.message());
+ print_pack(pack);
+ }
+#endif
+
+ // Are both sizes too small to be a pack?
+ if (old_size < 2 && new_size < 2) {
+ assert(old_size == 1 && new_size == 1, "implied");
+#ifndef PRODUCT
+ if (is_trace_superword_rejections()) {
+ tty->cr();
+ tty->print_cr("WARNING: Removed size 2 pack, cannot be split: %s:", task.message());
+ print_pack(pack);
+ }
+#endif
+ for (uint i = 0; i < pack_size; i++) {
+ Node* n = pack->at(i);
+ set_my_pack(n, nullptr);
}
+ return SplitStatus::make_rejected();
+ }
+
+ // Just pop off a single node?
+ if (new_size < 2) {
+ assert(new_size == 1 && old_size >= 2, "implied");
+ Node* n = pack->pop();
+ set_my_pack(n, nullptr);
+#ifndef PRODUCT
+ if (is_trace_superword_rejections()) {
+ tty->cr();
+ tty->print_cr("WARNING: Removed node from pack, because of split: %s:", task.message());
+ n->dump();
+ }
+#endif
+ return SplitStatus::make_modified(pack);
+ }
+
+ // Just remove a single node at front?
+ if (old_size < 2) {
+ assert(old_size == 1 && new_size >= 2, "implied");
+ Node* n = pack->at(0);
+ pack->remove(0);
+ set_my_pack(n, nullptr);
+#ifndef PRODUCT
+ if (is_trace_superword_rejections()) {
+ tty->cr();
+ tty->print_cr("WARNING: Removed node from pack, because of split: %s:", task.message());
+ n->dump();
+ }
+#endif
+ return SplitStatus::make_modified(pack);
+ }
+
+ // We will have two packs
+ assert(old_size >= 2 && new_size >= 2, "implied");
+ Node_List* new_pack = new Node_List(new_size);
+
+ for (uint i = 0; i < new_size; i++) {
+ Node* n = pack->at(old_size + i);
+ new_pack->push(n);
+ set_my_pack(n, new_pack);
}
- assert(old_packset_length <= _packset.length(), "we only increased the number of packs");
+ for (uint i = 0; i < new_size; i++) {
+ pack->pop();
+ }
+
+ // We assume that new_pack is more "stable" (i.e. will have to be split less than new_pack).
+ // Put "pack" second, so that we insert it later in the list, and iterate over it again sooner.
+ return SplitStatus::make_split(new_pack, pack);
+}
+
+template
+void SuperWord::split_packs(const char* split_name,
+ SplitStrategy strategy) {
+ bool changed;
+ do {
+ changed = false;
+ int new_packset_length = 0;
+ for (int i = 0; i < _packset.length(); i++) {
+ Node_List* pack = _packset.at(i);
+ assert(pack != nullptr && pack->size() >= 2, "no nullptr, at least size 2");
+ SplitTask task = strategy(pack);
+ SplitStatus status = split_pack(split_name, pack, task);
+ changed |= !status.is_unchanged();
+ Node_List* first_pack = status.first_pack();
+ Node_List* second_pack = status.second_pack();
+ _packset.at_put(i, nullptr); // take out pack
+ if (first_pack != nullptr) {
+ // The first pack can be put at the current position
+ assert(i >= new_packset_length, "only move packs down");
+ _packset.at_put(new_packset_length++, first_pack);
+ }
+ if (second_pack != nullptr) {
+ // The second node has to be appended at the end
+ _packset.append(second_pack);
+ }
+ }
+ _packset.trunc_to(new_packset_length);
+ } while (changed);
#ifndef PRODUCT
if (is_trace_superword_packset()) {
- tty->print_cr("\nAfter Superword::split_packs_longer_than_max_vector_size");
+ tty->print_cr("\nAfter %s", split_name);
print_packset();
}
#endif
}
+// Split packs at boundaries where left and right have different use or def packs.
+void SuperWord::split_packs_at_use_def_boundaries() {
+ split_packs("SuperWord::split_packs_at_use_def_boundaries",
+ [&](const Node_List* pack) {
+ uint pack_size = pack->size();
+ uint boundary = find_use_def_boundary(pack);
+ assert(boundary < pack_size, "valid boundary %d", boundary);
+ if (boundary != 0) {
+ return SplitTask::make_split(pack_size - boundary, "found a use/def boundary");
+ }
+ return SplitTask::make_unchanged();
+ });
+}
+
+// Split packs that are only implemented with a smaller pack size. Also splits packs
+// such that they eventually have power of 2 size.
+void SuperWord::split_packs_only_implemented_with_smaller_size() {
+ split_packs("SuperWord::split_packs_only_implemented_with_smaller_size",
+ [&](const Node_List* pack) {
+ uint pack_size = pack->size();
+ uint implemented_size = max_implemented_size(pack);
+ if (implemented_size == 0) {
+ return SplitTask::make_rejected("not implemented at any smaller size");
+ }
+ assert(is_power_of_2(implemented_size), "power of 2 size or zero: %d", implemented_size);
+ if (implemented_size != pack_size) {
+ return SplitTask::make_split(implemented_size, "only implemented at smaller size");
+ }
+ return SplitTask::make_unchanged();
+ });
+}
+
+// Split packs that have a mutual dependency, until all packs are mutually_independent.
+void SuperWord::split_packs_to_break_mutual_dependence() {
+ split_packs("SuperWord::split_packs_to_break_mutual_dependence",
+ [&](const Node_List* pack) {
+ uint pack_size = pack->size();
+ assert(is_power_of_2(pack_size), "ensured by earlier splits %d", pack_size);
+ if (!is_marked_reduction(pack->at(0)) &&
+ !mutually_independent(pack)) {
+ // As a best guess, we split the pack in half. This way, we iteratively make the
+ // packs smaller, until there is no dependency.
+ return SplitTask::make_split(pack_size >> 1, "was not mutually independent");
+ }
+ return SplitTask::make_unchanged();
+ });
+}
+
template
void SuperWord::filter_packs(const char* filter_name,
const char* error_message,
@@ -1730,7 +1799,7 @@ void SuperWord::filter_packs_for_implemented() {
filter_packs("SuperWord::filter_packs_for_implemented",
"Unimplemented",
[&](const Node_List* pack) {
- return implemented(pack);
+ return implemented(pack, pack->size());
});
}
@@ -1752,7 +1821,7 @@ void SuperWord::filter_packs_for_profitable() {
while (true) {
int old_packset_length = _packset.length();
filter_packs(nullptr, // don't dump each time
- "size is not a power of 2",
+ "not profitable",
[&](const Node_List* pack) {
return profitable(pack);
});
@@ -1771,14 +1840,13 @@ void SuperWord::filter_packs_for_profitable() {
#endif
}
-//------------------------------implemented---------------------------
-// Can code be generated for pack p?
-bool SuperWord::implemented(const Node_List* p) {
+// Can code be generated for the pack, restricted to size nodes?
+bool SuperWord::implemented(const Node_List* pack, uint size) {
+ assert(size >= 2 && size <= pack->size() && is_power_of_2(size), "valid size");
bool retValue = false;
- Node* p0 = p->at(0);
+ Node* p0 = pack->at(0);
if (p0 != nullptr) {
int opc = p0->Opcode();
- uint size = p->size();
if (is_marked_reduction(p0)) {
const Type *arith_type = p0->bottom_type();
// Length 2 reductions of INT/LONG do not offer performance benefits
@@ -1820,6 +1888,22 @@ bool SuperWord::implemented(const Node_List* p) {
return retValue;
}
+// Find the maximal implemented size smaller or equal to the packs size
+uint SuperWord::max_implemented_size(const Node_List* pack) {
+ uint size = round_down_power_of_2(pack->size());
+ if (implemented(pack, size)) {
+ return size;
+ } else {
+ // Iteratively divide size by 2, and check.
+ for (uint s = size >> 1; s >= 2; s >>= 1) {
+ if (implemented(pack, s)) {
+ return s;
+ }
+ }
+ return 0; // not implementable at all
+ }
+}
+
bool SuperWord::requires_long_to_int_conversion(int opc) {
switch(opc) {
case Op_PopCountL:
@@ -1982,16 +2066,16 @@ void SuperWord::verify_packs() {
}
#endif
-// The PacksetGraph combines the DepPreds graph with the packset. In the PackSet
+// The PacksetGraph combines the dependency graph with the packset. In the PackSet
// graph, we have two kinds of nodes:
// (1) pack-node: Represents all nodes of some pack p in a single node, which
// shall later become a vector node.
// (2) scalar-node: Represents a node that is not in any pack.
-// For any edge (n1, n2) in DepPreds, we add an edge to the PacksetGraph for the
-// PacksetGraph nodes corresponding to n1 and n2.
-// We work from the DepPreds graph, because it gives us all the data-dependencies,
-// as well as more refined memory-dependencies than the C2 graph. DepPreds does
-// not have cycles. But packing nodes can introduce cyclic dependencies. Example:
+// For any edge (n1, n2) in the dependency graph, we add an edge to the PacksetGraph for
+// the PacksetGraph nodes corresponding to n1 and n2.
+// We work from the dependency graph, because it gives us all the data-dependencies,
+// as well as more refined memory-dependencies than the C2 graph. The dependency graph
+// does not have cycles. But packing nodes can introduce cyclic dependencies. Example:
//
// +--------+
// A -> X | v
@@ -2055,11 +2139,10 @@ class PacksetGraph {
GrowableArray& out(int pid) { return _out.at(pid - 1); }
bool schedule_success() const { return _schedule_success; }
- // Create nodes (from packs and scalar-nodes), and add edges, based on DepPreds.
+ // Create nodes (from packs and scalar-nodes), and add edges, based on the dependency graph.
void build() {
const GrowableArray& packset = _slp->packset();
const GrowableArray& body = _slp->body();
- const DepGraph& dg = _slp->dg();
// Map nodes in packsets
for (int i = 0; i < packset.length(); i++) {
Node_List* p = packset.at(i);
@@ -2096,7 +2179,7 @@ class PacksetGraph {
for (uint k = 0; k < p->size(); k++) {
Node* n = p->at(k);
assert(pid == get_pid(n), "all nodes in pack have same pid");
- for (DepPreds preds(n, dg); !preds.done(); preds.next()) {
+ for (VLoopDependencyGraph::PredsIterator preds(_slp->dependency_graph(), n); !preds.done(); preds.next()) {
Node* pred = preds.current();
int pred_pid = get_pid_or_zero(pred);
if (pred_pid == pid && _slp->is_marked_reduction(n)) {
@@ -2118,7 +2201,7 @@ class PacksetGraph {
if (pid <= max_pid_packset) {
continue; // Only scalar-nodes
}
- for (DepPreds preds(n, dg); !preds.done(); preds.next()) {
+ for (VLoopDependencyGraph::PredsIterator preds(_slp->dependency_graph(), n); !preds.done(); preds.next()) {
Node* pred = preds.current();
int pred_pid = get_pid_or_zero(pred);
// Only add edges for mapped nodes (in body)
@@ -2209,7 +2292,7 @@ class PacksetGraph {
};
// The C2 graph (specifically the memory graph), needs to be re-ordered.
-// (1) Build the PacksetGraph. It combines the DepPreds graph with the
+// (1) Build the PacksetGraph. It combines the dependency graph with the
// packset. The PacksetGraph gives us the dependencies that must be
// respected after scheduling.
// (2) Schedule the PacksetGraph to the memops_schedule, which represents
@@ -2852,6 +2935,94 @@ void SuperWord::verify_no_extract() {
}
#endif
+// Check if n_super's pack uses are a superset of n_sub's pack uses.
+bool SuperWord::has_use_pack_superset(const Node* n_super, const Node* n_sub) const {
+ Node_List* pack = my_pack(n_super);
+ assert(pack != nullptr && pack == my_pack(n_sub), "must have the same pack");
+
+ // For all uses of n_sub that are in a pack (use_sub) ...
+ for (DUIterator_Fast jmax, j = n_sub->fast_outs(jmax); j < jmax; j++) {
+ Node* use_sub = n_sub->fast_out(j);
+ Node_List* pack_use_sub = my_pack(use_sub);
+ if (pack_use_sub == nullptr) { continue; }
+
+ // ... and all input edges: use_sub->in(i) == n_sub.
+ uint start, end;
+ VectorNode::vector_operands(use_sub, &start, &end);
+ for (uint i = start; i < end; i++) {
+ if (use_sub->in(i) != n_sub) { continue; }
+
+ // Check if n_super has any use use_super in the same pack ...
+ bool found = false;
+ for (DUIterator_Fast kmax, k = n_super->fast_outs(kmax); k < kmax; k++) {
+ Node* use_super = n_super->fast_out(k);
+ Node_List* pack_use_super = my_pack(use_super);
+ if (pack_use_sub != pack_use_super) { continue; }
+
+ // ... and where there is an edge use_super->in(i) == n_super.
+ // For MulAddS2I it is expected to have defs over different input edges.
+ if (use_super->in(i) != n_super && !VectorNode::is_muladds2i(use_super)) { continue; }
+
+ found = true;
+ break;
+ }
+ if (!found) {
+ // n_sub has a use-edge (use_sub->in(i) == n_sub) with use_sub in a packset,
+ // but n_super does not have any edge (use_super->in(i) == n_super) with
+ // use_super in the same packset. Hence, n_super does not have a use pack
+ // superset of n_sub.
+ return false;
+ }
+ }
+ }
+ // n_super has all edges that n_sub has.
+ return true;
+}
+
+// Find a boundary in the pack, where left and right have different pack uses and defs.
+// This is a natural boundary to split a pack, to ensure that use and def packs match.
+// If no boundary is found, return zero.
+uint SuperWord::find_use_def_boundary(const Node_List* pack) const {
+ Node* p0 = pack->at(0);
+ Node* p1 = pack->at(1);
+
+ const bool is_reduction_pack = reduction(p0, p1);
+
+ // Inputs range
+ uint start, end;
+ VectorNode::vector_operands(p0, &start, &end);
+
+ for (int i = pack->size() - 2; i >= 0; i--) {
+ // For all neighbours
+ Node* n0 = pack->at(i + 0);
+ Node* n1 = pack->at(i + 1);
+
+
+ // 1. Check for matching defs
+ for (uint j = start; j < end; j++) {
+ Node* n0_in = n0->in(j);
+ Node* n1_in = n1->in(j);
+ // No boundary if:
+ // 1) the same packs OR
+ // 2) reduction edge n0->n1 or n1->n0
+ if (my_pack(n0_in) != my_pack(n1_in) &&
+ !((n0 == n1_in || n1 == n0_in) && is_reduction_pack)) {
+ return i + 1;
+ }
+ }
+
+ // 2. Check for matching uses: equal if both are superset of the other.
+ // Reductions have no pack uses, so they match trivially on the use packs.
+ if (!is_reduction_pack &&
+ !(has_use_pack_superset(n0, n1) &&
+ has_use_pack_superset(n1, n0))) {
+ return i + 1;
+ }
+ }
+
+ return 0;
+}
+
//------------------------------is_vector_use---------------------------
// Is use->in(u_idx) a vector use?
bool SuperWord::is_vector_use(Node* use, int u_idx) {
@@ -3042,41 +3213,6 @@ void SuperWord::initialize_node_info() {
grow_node_info(bb_idx(last));
}
-//------------------------------compute_max_depth---------------------------
-// Compute max depth for expressions from beginning of block
-// Use to prune search paths during test for independence.
-void SuperWord::compute_max_depth() {
- int ct = 0;
- bool again;
- do {
- again = false;
- for (int i = 0; i < body().length(); i++) {
- Node* n = body().at(i);
- if (!n->is_Phi()) {
- int d_orig = depth(n);
- int d_in = 0;
- for (DepPreds preds(n, _dg); !preds.done(); preds.next()) {
- Node* pred = preds.current();
- if (in_bb(pred)) {
- d_in = MAX2(d_in, depth(pred));
- }
- }
- if (d_in + 1 != d_orig) {
- set_depth(n, d_in + 1);
- again = true;
- }
- }
- }
- ct++;
- } while (again);
-
-#ifndef PRODUCT
- if (is_trace_superword_dependence_graph()) {
- tty->print_cr("compute_max_depth iterated: %d times", ct);
- }
-#endif
-}
-
BasicType SuperWord::longer_type_for_conversion(Node* n) {
if (!(VectorNode::is_convert_opcode(n->Opcode()) ||
requires_long_to_int_conversion(n->Opcode())) ||
@@ -3734,141 +3870,6 @@ void SuperWord::print_stmt(Node* s) {
const SWNodeInfo SWNodeInfo::initial;
-
-// ============================ DepGraph ===========================
-
-//------------------------------make_node---------------------------
-// Make a new dependence graph node for an ideal node.
-DepMem* DepGraph::make_node(Node* node) {
- DepMem* m = new (_arena) DepMem(node);
- if (node != nullptr) {
- assert(_map.at_grow(node->_idx) == nullptr, "one init only");
- _map.at_put_grow(node->_idx, m);
- }
- return m;
-}
-
-//------------------------------make_edge---------------------------
-// Make a new dependence graph edge from dpred -> dsucc
-DepEdge* DepGraph::make_edge(DepMem* dpred, DepMem* dsucc) {
- DepEdge* e = new (_arena) DepEdge(dpred, dsucc, dsucc->in_head(), dpred->out_head());
- dpred->set_out_head(e);
- dsucc->set_in_head(e);
- return e;
-}
-
-// ========================== DepMem ========================
-
-//------------------------------in_cnt---------------------------
-int DepMem::in_cnt() {
- int ct = 0;
- for (DepEdge* e = _in_head; e != nullptr; e = e->next_in()) ct++;
- return ct;
-}
-
-//------------------------------out_cnt---------------------------
-int DepMem::out_cnt() {
- int ct = 0;
- for (DepEdge* e = _out_head; e != nullptr; e = e->next_out()) ct++;
- return ct;
-}
-
-//------------------------------print-----------------------------
-void DepMem::print() {
-#ifndef PRODUCT
- tty->print(" DepNode %d (", _node->_idx);
- for (DepEdge* p = _in_head; p != nullptr; p = p->next_in()) {
- Node* pred = p->pred()->node();
- tty->print(" %d", pred != nullptr ? pred->_idx : 0);
- }
- tty->print(") [");
- for (DepEdge* s = _out_head; s != nullptr; s = s->next_out()) {
- Node* succ = s->succ()->node();
- tty->print(" %d", succ != nullptr ? succ->_idx : 0);
- }
- tty->print_cr(" ]");
-#endif
-}
-
-// =========================== DepEdge =========================
-
-//------------------------------DepPreds---------------------------
-void DepEdge::print() {
-#ifndef PRODUCT
- tty->print_cr("DepEdge: %d [ %d ]", _pred->node()->_idx, _succ->node()->_idx);
-#endif
-}
-
-// =========================== DepPreds =========================
-// Iterator over predecessor edges in the dependence graph.
-
-//------------------------------DepPreds---------------------------
-DepPreds::DepPreds(Node* n, const DepGraph& dg) {
- _n = n;
- _done = false;
- if (_n->is_Store() || _n->is_Load()) {
- _next_idx = MemNode::Address;
- _end_idx = n->req();
- _dep_next = dg.dep(_n)->in_head();
- } else if (_n->is_Mem()) {
- _next_idx = 0;
- _end_idx = 0;
- _dep_next = dg.dep(_n)->in_head();
- } else {
- _next_idx = 1;
- _end_idx = _n->req();
- _dep_next = nullptr;
- }
- next();
-}
-
-//------------------------------next---------------------------
-void DepPreds::next() {
- if (_dep_next != nullptr) {
- _current = _dep_next->pred()->node();
- _dep_next = _dep_next->next_in();
- } else if (_next_idx < _end_idx) {
- _current = _n->in(_next_idx++);
- } else {
- _done = true;
- }
-}
-
-// =========================== DepSuccs =========================
-// Iterator over successor edges in the dependence graph.
-
-//------------------------------DepSuccs---------------------------
-DepSuccs::DepSuccs(Node* n, DepGraph& dg) {
- _n = n;
- _done = false;
- if (_n->is_Load()) {
- _next_idx = 0;
- _end_idx = _n->outcnt();
- _dep_next = dg.dep(_n)->out_head();
- } else if (_n->is_Mem() || _n->is_memory_phi()) {
- _next_idx = 0;
- _end_idx = 0;
- _dep_next = dg.dep(_n)->out_head();
- } else {
- _next_idx = 0;
- _end_idx = _n->outcnt();
- _dep_next = nullptr;
- }
- next();
-}
-
-//-------------------------------next---------------------------
-void DepSuccs::next() {
- if (_dep_next != nullptr) {
- _current = _dep_next->succ()->node();
- _dep_next = _dep_next->next_out();
- } else if (_next_idx < _end_idx) {
- _current = _n->raw_out(_next_idx++);
- } else {
- _done = true;
- }
-}
-
//
// --------------------------------- vectorization/simd -----------------------------------
//
diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp
index 00a8c915ac7..ba5944d48b4 100644
--- a/src/hotspot/share/opto/superword.hpp
+++ b/src/hotspot/share/opto/superword.hpp
@@ -57,128 +57,6 @@
class VPointer;
-// ========================= Dependence Graph =====================
-
-class DepMem;
-
-//------------------------------DepEdge---------------------------
-// An edge in the dependence graph. The edges incident to a dependence
-// node are threaded through _next_in for incoming edges and _next_out
-// for outgoing edges.
-class DepEdge : public ArenaObj {
- protected:
- DepMem* _pred;
- DepMem* _succ;
- DepEdge* _next_in; // list of in edges, null terminated
- DepEdge* _next_out; // list of out edges, null terminated
-
- public:
- DepEdge(DepMem* pred, DepMem* succ, DepEdge* next_in, DepEdge* next_out) :
- _pred(pred), _succ(succ), _next_in(next_in), _next_out(next_out) {}
-
- DepEdge* next_in() { return _next_in; }
- DepEdge* next_out() { return _next_out; }
- DepMem* pred() { return _pred; }
- DepMem* succ() { return _succ; }
-
- void print();
-};
-
-//------------------------------DepMem---------------------------
-// A node in the dependence graph. _in_head starts the threaded list of
-// incoming edges, and _out_head starts the list of outgoing edges.
-class DepMem : public ArenaObj {
- protected:
- Node* _node; // Corresponding ideal node
- DepEdge* _in_head; // Head of list of in edges, null terminated
- DepEdge* _out_head; // Head of list of out edges, null terminated
-
- public:
- DepMem(Node* node) : _node(node), _in_head(nullptr), _out_head(nullptr) {}
-
- Node* node() { return _node; }
- DepEdge* in_head() { return _in_head; }
- DepEdge* out_head() { return _out_head; }
- void set_in_head(DepEdge* hd) { _in_head = hd; }
- void set_out_head(DepEdge* hd) { _out_head = hd; }
-
- int in_cnt(); // Incoming edge count
- int out_cnt(); // Outgoing edge count
-
- void print();
-};
-
-//------------------------------DepGraph---------------------------
-class DepGraph {
- protected:
- Arena* _arena;
- GrowableArray _map;
- DepMem* _root;
- DepMem* _tail;
-
- public:
- DepGraph(Arena* a) : _arena(a), _map(a, 8, 0, nullptr) {
- _root = new (_arena) DepMem(nullptr);
- _tail = new (_arena) DepMem(nullptr);
- }
-
- DepMem* root() { return _root; }
- DepMem* tail() { return _tail; }
-
- // Return dependence node corresponding to an ideal node
- DepMem* dep(Node* node) const { return _map.at(node->_idx); }
-
- // Make a new dependence graph node for an ideal node.
- DepMem* make_node(Node* node);
-
- // Make a new dependence graph edge dprec->dsucc
- DepEdge* make_edge(DepMem* dpred, DepMem* dsucc);
-
- DepEdge* make_edge(Node* pred, Node* succ) { return make_edge(dep(pred), dep(succ)); }
- DepEdge* make_edge(DepMem* pred, Node* succ) { return make_edge(pred, dep(succ)); }
- DepEdge* make_edge(Node* pred, DepMem* succ) { return make_edge(dep(pred), succ); }
-
- void print(Node* n) { dep(n)->print(); }
- void print(DepMem* d) { d->print(); }
-};
-
-//------------------------------DepPreds---------------------------
-// Iterator over predecessors in the dependence graph and
-// non-memory-graph inputs of ideal nodes.
-class DepPreds : public StackObj {
-private:
- Node* _n;
- int _next_idx, _end_idx;
- DepEdge* _dep_next;
- Node* _current;
- bool _done;
-
-public:
- DepPreds(Node* n, const DepGraph& dg);
- Node* current() { return _current; }
- bool done() { return _done; }
- void next();
-};
-
-//------------------------------DepSuccs---------------------------
-// Iterator over successors in the dependence graph and
-// non-memory-graph outputs of ideal nodes.
-class DepSuccs : public StackObj {
-private:
- Node* _n;
- int _next_idx, _end_idx;
- DepEdge* _dep_next;
- Node* _current;
- bool _done;
-
-public:
- DepSuccs(Node* n, DepGraph& dg);
- Node* current() { return _current; }
- bool done() { return _done; }
- void next();
-};
-
-
// ========================= SuperWord =====================
// -----------------------------SWNodeInfo---------------------------------
@@ -186,10 +64,9 @@ class DepSuccs : public StackObj {
class SWNodeInfo {
public:
int _alignment; // memory alignment for a node
- int _depth; // Max expression (DAG) depth from block start
Node_List* _my_pack; // pack containing this node
- SWNodeInfo() : _alignment(-1), _depth(0), _my_pack(nullptr) {}
+ SWNodeInfo() : _alignment(-1), _my_pack(nullptr) {}
static const SWNodeInfo initial;
};
@@ -212,8 +89,6 @@ class SuperWord : public ResourceObj {
CloneMap& _clone_map; // map of nodes created in cloning
MemNode const* _align_to_ref; // Memory reference that pre-loop will align to
- DepGraph _dg; // Dependence graph
-
public:
SuperWord(const VLoopAnalyzer &vloop_analyzer);
@@ -280,6 +155,19 @@ class SuperWord : public ResourceObj {
return _vloop_analyzer.types().vector_width_in_bytes(n);
}
+ // VLoopDependencyGraph Accessors
+ const VLoopDependencyGraph& dependency_graph() const {
+ return _vloop_analyzer.dependency_graph();
+ }
+
+ bool independent(Node* n1, Node* n2) const {
+ return _vloop_analyzer.dependency_graph().independent(n1, n2);
+ }
+
+ bool mutually_independent(const Node_List* nodes) const {
+ return _vloop_analyzer.dependency_graph().mutually_independent(nodes);
+ }
+
#ifndef PRODUCT
// TraceAutoVectorization and TraceSuperWord
bool is_trace_superword_alignment() const {
@@ -287,11 +175,6 @@ class SuperWord : public ResourceObj {
return _vloop.vtrace().is_trace(TraceAutoVectorizationTag::SW_ALIGNMENT);
}
- bool is_trace_superword_dependence_graph() const {
- return TraceSuperWord ||
- _vloop.vtrace().is_trace(TraceAutoVectorizationTag::SW_DEPENDENCE_GRAPH);
- }
-
bool is_trace_superword_adjacent_memops() const {
return TraceSuperWord ||
_vloop.vtrace().is_trace(TraceAutoVectorizationTag::SW_ADJACENT_MEMOPS);
@@ -321,7 +204,6 @@ class SuperWord : public ResourceObj {
return TraceSuperWord ||
is_trace_align_vector() ||
_vloop.vtrace().is_trace(TraceAutoVectorizationTag::SW_ALIGNMENT) ||
- _vloop.vtrace().is_trace(TraceAutoVectorizationTag::SW_DEPENDENCE_GRAPH) ||
_vloop.vtrace().is_trace(TraceAutoVectorizationTag::SW_ADJACENT_MEMOPS) ||
_vloop.vtrace().is_trace(TraceAutoVectorizationTag::SW_REJECTIONS) ||
_vloop.vtrace().is_trace(TraceAutoVectorizationTag::SW_PACKSET) ||
@@ -338,7 +220,6 @@ class SuperWord : public ResourceObj {
bool do_vector_loop() { return _do_vector_loop; }
const GrowableArray& packset() const { return _packset; }
- const DepGraph& dg() const { return _dg; }
private:
bool _race_possible; // In cases where SDMU is true
bool _do_vector_loop; // whether to do vectorization/simd style
@@ -362,13 +243,9 @@ class SuperWord : public ResourceObj {
int alignment(Node* n) { return _node_info.adr_at(bb_idx(n))->_alignment; }
void set_alignment(Node* n, int a) { int i = bb_idx(n); grow_node_info(i); _node_info.adr_at(i)->_alignment = a; }
- // Max expression (DAG) depth from beginning of the block for each node
- int depth(Node* n) const { return _node_info.adr_at(bb_idx(n))->_depth; }
- void set_depth(Node* n, int d) { int i = bb_idx(n); grow_node_info(i); _node_info.adr_at(i)->_depth = d; }
-
// my_pack
public:
- Node_List* my_pack(Node* n) { return !in_bb(n) ? nullptr : _node_info.adr_at(bb_idx(n))->_my_pack; }
+ Node_List* my_pack(const Node* n) const { return !in_bb(n) ? nullptr : _node_info.adr_at(bb_idx(n))->_my_pack; }
private:
void set_my_pack(Node* n, Node_List* p) { int i = bb_idx(n); grow_node_info(i); _node_info.adr_at(i)->_my_pack = p; }
// is pack good for converting into one vector node replacing bunches of Cmp, Bool, CMov nodes.
@@ -387,8 +264,6 @@ class SuperWord : public ResourceObj {
MemNode* find_align_to_ref(Node_List &memops, int &idx);
// Calculate loop's iv adjustment for this memory ops.
int get_iv_adjustment(MemNode* mem);
- // Construct dependency graph.
- void dependence_graph();
// Can s1 and s2 be in a pack with s1 immediately preceding s2 and s1 aligned at "align"
bool stmts_can_pack(Node* s1, Node* s2, int align);
@@ -398,10 +273,8 @@ class SuperWord : public ResourceObj {
bool are_adjacent_refs(Node* s1, Node* s2);
// Are s1 and s2 similar?
bool isomorphic(Node* s1, Node* s2);
- // Is there no data path from s1 to s2 or s2 to s1?
- bool independent(Node* s1, Node* s2);
- // Are all nodes in nodes list mutually independent?
- bool mutually_independent(const Node_List* nodes) const;
+ // Do we have pattern n1 = (iv + c) and n2 = (iv + c + 1)?
+ bool is_populate_index(const Node* n1, const Node* n2) const;
// For a node pair (s1, s2) which is isomorphic and independent,
// do s1 and s2 have similar input edges?
bool have_similar_inputs(Node* s1, Node* s2);
@@ -424,7 +297,102 @@ class SuperWord : public ResourceObj {
// Combine packs A and B with A.last == B.first into A.first..,A.last,B.second,..B.last
void combine_pairs_to_longer_packs();
- void split_packs_longer_than_max_vector_size();
+ class SplitTask {
+ private:
+ enum Kind {
+ // The lambda method for split_packs can return one of these tasks:
+ Unchanged, // The pack is left in the packset, unchanged.
+ Rejected, // The pack is removed from the packset.
+ Split, // Split away split_size nodes from the end of the pack.
+ };
+ const Kind _kind;
+ const uint _split_size;
+ const char* _message;
+
+ SplitTask(const Kind kind, const uint split_size, const char* message) :
+ _kind(kind), _split_size(split_size), _message(message)
+ {
+ assert(message != nullptr, "must have message");
+ assert(_kind != Unchanged || split_size == 0, "unchanged task conditions");
+ assert(_kind != Rejected || split_size == 0, "reject task conditions");
+ assert(_kind != Split || split_size != 0, "split task conditions");
+ }
+
+ public:
+ static SplitTask make_split(const uint split_size, const char* message) {
+ return SplitTask(Split, split_size, message);
+ }
+
+ static SplitTask make_unchanged() {
+ return SplitTask(Unchanged, 0, "unchanged");
+ }
+
+ static SplitTask make_rejected(const char* message) {
+ return SplitTask(Rejected, 0, message);
+ }
+
+ bool is_unchanged() const { return _kind == Unchanged; }
+ bool is_rejected() const { return _kind == Rejected; }
+ bool is_split() const { return _kind == Split; }
+ const char* message() const { return _message; }
+
+ uint split_size() const {
+ assert(is_split(), "only split tasks have split_size");
+ return _split_size;
+ }
+ };
+
+ class SplitStatus {
+ private:
+ enum Kind {
+ // After split_pack, we have: first_pack second_pack
+ Unchanged, // The pack is left in the pack, unchanged. old_pack nullptr
+ Rejected, // The pack is removed from the packset. nullptr nullptr
+ Modified, // The pack had some nodes removed. old_pack nullptr
+ Split, // The pack was split into two packs. pack1 pack2
+ };
+ Kind _kind;
+ Node_List* _first_pack;
+ Node_List* _second_pack;
+
+ SplitStatus(Kind kind, Node_List* first_pack, Node_List* second_pack) :
+ _kind(kind), _first_pack(first_pack), _second_pack(second_pack)
+ {
+ assert(_kind != Unchanged || (first_pack != nullptr && second_pack == nullptr), "unchanged status conditions");
+ assert(_kind != Rejected || (first_pack == nullptr && second_pack == nullptr), "rejected status conditions");
+ assert(_kind != Modified || (first_pack != nullptr && second_pack == nullptr), "modified status conditions");
+ assert(_kind != Split || (first_pack != nullptr && second_pack != nullptr), "split status conditions");
+ }
+
+ public:
+ static SplitStatus make_unchanged(Node_List* old_pack) {
+ return SplitStatus(Unchanged, old_pack, nullptr);
+ }
+
+ static SplitStatus make_rejected() {
+ return SplitStatus(Rejected, nullptr, nullptr);
+ }
+
+ static SplitStatus make_modified(Node_List* first_pack) {
+ return SplitStatus(Modified, first_pack, nullptr);
+ }
+
+ static SplitStatus make_split(Node_List* first_pack, Node_List* second_pack) {
+ return SplitStatus(Split, first_pack, second_pack);
+ }
+
+ bool is_unchanged() const { return _kind == Unchanged; }
+ Node_List* first_pack() const { return _first_pack; }
+ Node_List* second_pack() const { return _second_pack; }
+ };
+
+ SplitStatus split_pack(const char* split_name, Node_List* pack, SplitTask task);
+ template
+ void split_packs(const char* split_name, SplitStrategy strategy);
+
+ void split_packs_at_use_def_boundaries();
+ void split_packs_only_implemented_with_smaller_size();
+ void split_packs_to_break_mutual_dependence();
// Filter out packs with various filter predicates
template
@@ -457,14 +425,24 @@ class SuperWord : public ResourceObj {
bool output();
// Create a vector operand for the nodes in pack p for operand: in(opd_idx)
Node* vector_opd(Node_List* p, int opd_idx);
- // Can code be generated for pack p?
- bool implemented(const Node_List* p);
+
+ // Can code be generated for the pack, restricted to size nodes?
+ bool implemented(const Node_List* pack, uint size);
+ // Find the maximal implemented size smaller or equal to the packs size
+ uint max_implemented_size(const Node_List* pack);
+
// For pack p, are all operands and all uses (with in the block) vector?
bool profitable(const Node_List* p);
// Verify that all uses of packs are also packs, i.e. we do not need extract operations.
DEBUG_ONLY(void verify_no_extract();)
+
+ // Check if n_super's pack uses are a superset of n_sub's pack uses.
+ bool has_use_pack_superset(const Node* n1, const Node* n2) const;
+ // Find a boundary in the pack, where left and right have different pack uses and defs.
+ uint find_use_def_boundary(const Node_List* pack) const;
// Is use->in(u_idx) a vector use?
bool is_vector_use(Node* use, int u_idx);
+
// Initialize per node info
void initialize_node_info();
// Compute max depth for expressions from beginning of block
diff --git a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp
index 615f9230f3a..e04664caba1 100644
--- a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp
+++ b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp
@@ -35,8 +35,8 @@
flags(MEMORY_SLICES, "Trace VLoopMemorySlices") \
flags(BODY, "Trace VLoopBody") \
flags(TYPES, "Trace VLoopTypes") \
+ flags(DEPENDENCY_GRAPH, "Trace VLoopDependencyGraph") \
flags(SW_ALIGNMENT, "Trace SuperWord alignment analysis") \
- flags(SW_DEPENDENCE_GRAPH, "Trace SuperWord::dependence_graph") \
flags(SW_ADJACENT_MEMOPS, "Trace SuperWord::find_adjacent_refs") \
flags(SW_REJECTIONS, "Trace SuperWord rejections (non vectorizations)") \
flags(SW_PACKSET, "Trace SuperWord packset at different stages") \
@@ -115,14 +115,12 @@ class TraceAutoVectorizationTagValidator {
_tags.set_range(0, TRACE_AUTO_VECTORIZATION_TAG_NUM);
} else if (SW_VERBOSE == tag) {
_tags.at_put(SW_ALIGNMENT, set_bit);
- _tags.at_put(SW_DEPENDENCE_GRAPH, set_bit);
_tags.at_put(SW_ADJACENT_MEMOPS, set_bit);
_tags.at_put(SW_REJECTIONS, set_bit);
_tags.at_put(SW_PACKSET, set_bit);
_tags.at_put(SW_INFO, set_bit);
_tags.at_put(SW_VERBOSE, set_bit);
} else if (SW_INFO == tag) {
- _tags.at_put(SW_DEPENDENCE_GRAPH, set_bit);
_tags.at_put(SW_ADJACENT_MEMOPS, set_bit);
_tags.at_put(SW_REJECTIONS, set_bit);
_tags.at_put(SW_PACKSET, set_bit);
diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp
index 4acbaedd21d..f3890eee017 100644
--- a/src/hotspot/share/opto/vectorization.cpp
+++ b/src/hotspot/share/opto/vectorization.cpp
@@ -161,9 +161,170 @@ VStatus VLoopAnalyzer::setup_submodules_helper() {
_types.compute_vector_element_type();
+ _dependency_graph.construct();
+
return VStatus::make_success();
}
+// Construct the dependency graph:
+// - Data-dependencies: implicit (taken from C2 node inputs).
+// - Memory-dependencies:
+// - No edges between different slices.
+// - No Load-Load edges.
+// - Inside a slice, add all Store-Load, Load-Store, Store-Store edges,
+// except if we can prove that the memory does not overlap.
+void VLoopDependencyGraph::construct() {
+ const GrowableArray& mem_slice_heads = _memory_slices.heads();
+ const GrowableArray& mem_slice_tails = _memory_slices.tails();
+
+ ResourceMark rm;
+ GrowableArray slice_nodes;
+ GrowableArray memory_pred_edges;
+
+ // For each memory slice, create the memory subgraph
+ for (int i = 0; i < mem_slice_heads.length(); i++) {
+ PhiNode* head = mem_slice_heads.at(i);
+ MemNode* tail = mem_slice_tails.at(i);
+
+ _memory_slices.get_slice_in_reverse_order(head, tail, slice_nodes);
+
+ // In forward order (reverse of reverse), visit all memory nodes in the slice.
+ for (int j = slice_nodes.length() - 1; j >= 0 ; j--) {
+ MemNode* n1 = slice_nodes.at(j);
+ memory_pred_edges.clear();
+
+ VPointer p1(n1, _vloop);
+ // For all memory nodes before it, check if we need to add a memory edge.
+ for (int k = slice_nodes.length() - 1; k > j; k--) {
+ MemNode* n2 = slice_nodes.at(k);
+
+ // Ignore Load-Load dependencies:
+ if (n1->is_Load() && n2->is_Load()) { continue; }
+
+ VPointer p2(n2, _vloop);
+ if (!VPointer::not_equal(p1.cmp(p2))) {
+ // Possibly overlapping memory
+ memory_pred_edges.append(_body.bb_idx(n2));
+ }
+ }
+ if (memory_pred_edges.is_nonempty()) {
+ // Data edges are taken implicitly from the C2 graph, thus we only add
+ // a dependency node if we have memory edges.
+ add_node(n1, memory_pred_edges);
+ }
+ }
+ slice_nodes.clear();
+ }
+
+ compute_depth();
+
+ NOT_PRODUCT( if (_vloop.is_trace_dependency_graph()) { print(); } )
+}
+
+void VLoopDependencyGraph::add_node(MemNode* n, GrowableArray& memory_pred_edges) {
+ assert(_dependency_nodes.at_grow(_body.bb_idx(n), nullptr) == nullptr, "not yet created");
+ assert(!memory_pred_edges.is_empty(), "no need to create a node without edges");
+ DependencyNode* dn = new (_arena) DependencyNode(n, memory_pred_edges, _arena);
+ _dependency_nodes.at_put_grow(_body.bb_idx(n), dn, nullptr);
+}
+
+// We iterate over the body, which is already ordered by the dependencies, i.e. pred comes
+// before use. With a single pass, we can compute the depth of every node, since we can
+// assume that the depth of all preds is already computed when we compute the depth of use.
+void VLoopDependencyGraph::compute_depth() {
+ for (int i = 0; i < _body.body().length(); i++) {
+ Node* n = _body.body().at(i);
+ int max_pred_depth = 0;
+ if (n->is_Phi()) {
+ for (PredsIterator it(*this, n); !it.done(); it.next()) {
+ Node* pred = it.current();
+ if (_vloop.in_bb(pred)) {
+ max_pred_depth = MAX2(max_pred_depth, depth(pred));
+ }
+ }
+ }
+ set_depth(n, max_pred_depth + 1);
+ }
+}
+
+#ifndef PRODUCT
+void VLoopDependencyGraph::print() const {
+ tty->print_cr("\nVLoopDependencyGraph::print:");
+
+ tty->print_cr(" Memory pred edges:");
+ for (int i = 0; i < _body.body().length(); i++) {
+ Node* n = _body.body().at(i);
+ const DependencyNode* dn = dependency_node(n);
+ if (dn != nullptr) {
+ tty->print(" DependencyNode[%d %s:", n->_idx, n->Name());
+ for (uint j = 0; j < dn->memory_pred_edges_length(); j++) {
+ Node* pred = _body.body().at(dn->memory_pred_edge(j));
+ tty->print(" %d %s", pred->_idx, pred->Name());
+ }
+ tty->print_cr("]");
+ }
+ }
+ tty->cr();
+
+ tty->print_cr(" Complete dependency graph:");
+ for (int i = 0; i < _body.body().length(); i++) {
+ Node* n = _body.body().at(i);
+ tty->print(" d%02d Dependencies[%d %s:", depth(n), n->_idx, n->Name());
+ for (PredsIterator it(*this, n); !it.done(); it.next()) {
+ Node* pred = it.current();
+ tty->print(" %d %s", pred->_idx, pred->Name());
+ }
+ tty->print_cr("]");
+ }
+}
+#endif
+
+VLoopDependencyGraph::DependencyNode::DependencyNode(MemNode* n,
+ GrowableArray& memory_pred_edges,
+ Arena* arena) :
+ _node(n),
+ _memory_pred_edges_length(memory_pred_edges.length()),
+ _memory_pred_edges(nullptr)
+{
+ assert(memory_pred_edges.is_nonempty(), "not empty");
+ uint bytes = memory_pred_edges.length() * sizeof(int);
+ _memory_pred_edges = (int*)arena->Amalloc(bytes);
+ memcpy(_memory_pred_edges, memory_pred_edges.adr_at(0), bytes);
+}
+
+VLoopDependencyGraph::PredsIterator::PredsIterator(const VLoopDependencyGraph& dependency_graph,
+ const Node* node) :
+ _dependency_graph(dependency_graph),
+ _node(node),
+ _dependency_node(dependency_graph.dependency_node(node)),
+ _current(nullptr),
+ _next_pred(0),
+ _end_pred(node->req()),
+ _next_memory_pred(0),
+ _end_memory_pred((_dependency_node != nullptr) ? _dependency_node->memory_pred_edges_length() : 0)
+{
+ if (_node->is_Store() || _node->is_Load()) {
+ // Load: address
+ // Store: address, value
+ _next_pred = MemNode::Address;
+ } else {
+ assert(!_node->is_Mem(), "only loads and stores are expected mem nodes");
+ _next_pred = 1; // skip control
+ }
+ next();
+}
+
+void VLoopDependencyGraph::PredsIterator::next() {
+ if (_next_pred < _end_pred) {
+ _current = _node->in(_next_pred++);
+ } else if (_next_memory_pred < _end_memory_pred) {
+ int pred_bb_idx = _dependency_node->memory_pred_edge(_next_memory_pred++);
+ _current = _dependency_graph._body.body().at(pred_bb_idx);
+ } else {
+ _current = nullptr; // done
+ }
+}
+
#ifndef PRODUCT
int VPointer::Tracer::_depth = 0;
#endif
diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp
index 00f6a9de474..88a46a3d688 100644
--- a/src/hotspot/share/opto/vectorization.hpp
+++ b/src/hotspot/share/opto/vectorization.hpp
@@ -150,6 +150,10 @@ class VLoop : public StackObj {
return _vtrace.is_trace(TraceAutoVectorizationTag::TYPES);
}
+ bool is_trace_dependency_graph() const {
+ return _vtrace.is_trace(TraceAutoVectorizationTag::DEPENDENCY_GRAPH);
+ }
+
bool is_trace_pointer_analysis() const {
return _vtrace.is_trace(TraceAutoVectorizationTag::POINTER_ANALYSIS);
}
@@ -308,7 +312,7 @@ class VLoopMemorySlices : public StackObj {
const GrowableArray& tails() const { return _tails; }
// Get all memory nodes of a slice, in reverse order
- void get_slice_in_reverse_order(PhiNode* head, MemNode* tail, GrowableArray& slice) const;
+ void get_slice_in_reverse_order(PhiNode* head, MemNode* tail, GrowableArray& slice) const;
bool same_memory_slice(MemNode* m1, MemNode* m2) const;
@@ -441,6 +445,109 @@ class VLoopTypes : public StackObj {
const Type* container_type(Node* n) const;
};
+// Submodule of VLoopAnalyzer.
+// The dependency graph is used to determine if nodes are independent, and can thus potentially
+// be executed in parallel. That is a prerequisite for packing nodes into vector operations.
+// The dependency graph is a combination:
+// - Data-dependencies: they can directly be taken from the C2 node inputs.
+// - Memory-dependencies: the edges in the C2 memory-slice are too restrictive: for example all
+// stores are serialized, even if their memory does not overlap. Thus,
+// we refine the memory-dependencies (see construct method).
+class VLoopDependencyGraph : public StackObj {
+private:
+ class DependencyNode;
+
+ Arena* _arena;
+ const VLoop& _vloop;
+ const VLoopBody& _body;
+ const VLoopMemorySlices& _memory_slices;
+
+ // bb_idx -> DependenceNode*
+ GrowableArray _dependency_nodes;
+
+ // Node depth in DAG: bb_idx -> depth
+ GrowableArray _depths;
+
+public:
+ VLoopDependencyGraph(Arena* arena,
+ const VLoop& vloop,
+ const VLoopBody& body,
+ const VLoopMemorySlices& memory_slices) :
+ _arena(arena),
+ _vloop(vloop),
+ _body(body),
+ _memory_slices(memory_slices),
+ _dependency_nodes(arena,
+ vloop.estimated_body_length(),
+ vloop.estimated_body_length(),
+ nullptr),
+ _depths(arena,
+ vloop.estimated_body_length(),
+ vloop.estimated_body_length(),
+ 0) {}
+ NONCOPYABLE(VLoopDependencyGraph);
+
+ void construct();
+ bool independent(Node* s1, Node* s2) const;
+ bool mutually_independent(const Node_List* nodes) const;
+
+private:
+ void add_node(MemNode* n, GrowableArray& memory_pred_edges);
+ int depth(const Node* n) const { return _depths.at(_body.bb_idx(n)); }
+ void set_depth(const Node* n, int d) { _depths.at_put(_body.bb_idx(n), d); }
+ void compute_depth();
+ NOT_PRODUCT( void print() const; )
+
+ const DependencyNode* dependency_node(const Node* n) const {
+ return _dependency_nodes.at(_body.bb_idx(n));
+ }
+
+ class DependencyNode : public ArenaObj {
+ private:
+ MemNode* _node; // Corresponding ideal node
+ const uint _memory_pred_edges_length;
+ int* _memory_pred_edges; // memory pred-edges, mapping to bb_idx
+ public:
+ DependencyNode(MemNode* n, GrowableArray& memory_pred_edges, Arena* arena);
+ NONCOPYABLE(DependencyNode);
+ uint memory_pred_edges_length() const { return _memory_pred_edges_length; }
+
+ int memory_pred_edge(uint i) const {
+ assert(i < _memory_pred_edges_length, "bounds check");
+ return _memory_pred_edges[i];
+ }
+ };
+
+public:
+ // Iterator for dependency graph predecessors of a node.
+ class PredsIterator : public StackObj {
+ private:
+ const VLoopDependencyGraph& _dependency_graph;
+
+ const Node* _node;
+ const DependencyNode* _dependency_node;
+
+ Node* _current;
+
+ // Iterate in node->in(i)
+ int _next_pred;
+ int _end_pred;
+
+ // Iterate in dependency_node->memory_pred_edge(i)
+ int _next_memory_pred;
+ int _end_memory_pred;
+ public:
+ PredsIterator(const VLoopDependencyGraph& dependency_graph, const Node* node);
+ NONCOPYABLE(PredsIterator);
+ void next();
+ bool done() const { return _current == nullptr; }
+ Node* current() const {
+ assert(!done(), "not done yet");
+ return _current;
+ }
+ };
+};
+
// Analyze the loop in preparation for auto-vectorization. This class is
// deliberately structured into many submodules, which are as independent
// as possible, though some submodules do require other submodules.
@@ -463,6 +570,7 @@ class VLoopAnalyzer : StackObj {
VLoopMemorySlices _memory_slices;
VLoopBody _body;
VLoopTypes _types;
+ VLoopDependencyGraph _dependency_graph;
public:
VLoopAnalyzer(const VLoop& vloop, VSharedData& vshared) :
@@ -472,7 +580,8 @@ class VLoopAnalyzer : StackObj {
_reductions (&_arena, vloop),
_memory_slices (&_arena, vloop),
_body (&_arena, vloop, vshared),
- _types (&_arena, vloop, _body)
+ _types (&_arena, vloop, _body),
+ _dependency_graph(&_arena, vloop, _body, _memory_slices)
{
_success = setup_submodules();
}
@@ -486,6 +595,7 @@ class VLoopAnalyzer : StackObj {
const VLoopMemorySlices& memory_slices() const { return _memory_slices; }
const VLoopBody& body() const { return _body; }
const VLoopTypes& types() const { return _types; }
+ const VLoopDependencyGraph& dependency_graph() const { return _dependency_graph; }
private:
bool setup_submodules();
diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp
index a1f68a1bc40..b565711a1b8 100644
--- a/src/hotspot/share/prims/jvm.cpp
+++ b/src/hotspot/share/prims/jvm.cpp
@@ -3804,14 +3804,6 @@ JVM_ENTRY(jclass, JVM_LookupLambdaProxyClassFromArchive(JNIEnv* env,
#endif // INCLUDE_CDS
JVM_END
-JVM_LEAF(jboolean, JVM_IsCDSDumpingEnabled(JNIEnv* env))
- return CDSConfig::is_dumping_archive();
-JVM_END
-
-JVM_LEAF(jboolean, JVM_IsSharingEnabled(JNIEnv* env))
- return UseSharedSpaces;
-JVM_END
-
JVM_ENTRY_NO_ENV(jlong, JVM_GetRandomSeedForDumping())
if (CDSConfig::is_dumping_static_archive()) {
// We do this so that the default CDS archive can be deterministic.
@@ -3835,17 +3827,13 @@ JVM_ENTRY_NO_ENV(jlong, JVM_GetRandomSeedForDumping())
}
JVM_END
-JVM_LEAF(jboolean, JVM_IsDumpingClassList(JNIEnv *env))
-#if INCLUDE_CDS
- return ClassListWriter::is_enabled() || CDSConfig::is_dumping_dynamic_archive();
-#else
- return false;
-#endif // INCLUDE_CDS
+JVM_ENTRY_NO_ENV(jint, JVM_GetCDSConfigStatus())
+ return CDSConfig::get_status();
JVM_END
JVM_ENTRY(void, JVM_LogLambdaFormInvoker(JNIEnv *env, jstring line))
#if INCLUDE_CDS
- assert(ClassListWriter::is_enabled() || CDSConfig::is_dumping_dynamic_archive(), "Should be set and open or do dynamic dump");
+ assert(CDSConfig::is_logging_lambda_form_invokers(), "sanity");
if (line != nullptr) {
ResourceMark rm(THREAD);
Handle h_line (THREAD, JNIHandles::resolve_non_null(line));
diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp
index f95eecaf363..9d9fd010395 100644
--- a/src/hotspot/share/prims/jvmtiEnv.cpp
+++ b/src/hotspot/share/prims/jvmtiEnv.cpp
@@ -868,12 +868,7 @@ JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) {
// is a virtual thread.
return err;
}
-
- if (java_lang_VirtualThread::is_instance(thread_oop)) {
- *thread_state_ptr = JvmtiEnvBase::get_vthread_state(thread_oop, java_thread);
- } else {
- *thread_state_ptr = JvmtiEnvBase::get_thread_state(thread_oop, java_thread);
- }
+ *thread_state_ptr = JvmtiEnvBase::get_thread_or_vthread_state(thread_oop, java_thread);
return JVMTI_ERROR_NONE;
} /* end GetThreadState */
diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp
index 6a3ee718709..05d9a26444c 100644
--- a/src/hotspot/share/prims/jvmtiEnvBase.cpp
+++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp
@@ -813,6 +813,17 @@ JvmtiEnvBase::get_vthread_state(oop thread_oop, JavaThread* java_thread) {
return state;
}
+jint
+JvmtiEnvBase::get_thread_or_vthread_state(oop thread_oop, JavaThread* java_thread) {
+ jint state = 0;
+ if (java_lang_VirtualThread::is_instance(thread_oop)) {
+ state = JvmtiEnvBase::get_vthread_state(thread_oop, java_thread);
+ } else {
+ state = JvmtiEnvBase::get_thread_state(thread_oop, java_thread);
+ }
+ return state;
+}
+
jvmtiError
JvmtiEnvBase::get_live_threads(JavaThread* current_thread, Handle group_hdl, jint *count_ptr, Handle **thread_objs_p) {
jint count = 0;
@@ -933,11 +944,16 @@ JvmtiEnvBase::get_current_contended_monitor(JavaThread *calling_thread, JavaThre
obj = mon->object();
assert(obj != nullptr, "ObjectMonitor should have a valid object!");
}
- // implied else: no contended ObjectMonitor
} else {
// thread is doing an Object.wait() call
- obj = mon->object();
- assert(obj != nullptr, "Object.wait() should have an object");
+ oop thread_oop = get_vthread_or_thread_oop(java_thread);
+ jint state = get_thread_or_vthread_state(thread_oop, java_thread);
+
+ if (state & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) {
+ // thread is re-entering the monitor in an Object.wait() call
+ obj = mon->object();
+ assert(obj != nullptr, "Object.wait() should have an object");
+ }
}
if (obj == nullptr) {
@@ -1479,20 +1495,39 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
jint nWant = 0, nWait = 0;
markWord mark = hobj->mark();
+ ResourceMark rm(current_thread);
+ GrowableArray* wantList = nullptr;
+
if (mark.has_monitor()) {
mon = mark.monitor();
assert(mon != nullptr, "must have monitor");
// this object has a heavyweight monitor
- nWant = mon->contentions(); // # of threads contending for monitor
- nWait = mon->waiters(); // # of threads in Object.wait()
- ret.waiter_count = nWant + nWait;
- ret.notify_waiter_count = nWait;
+ nWant = mon->contentions(); // # of threads contending for monitor entry, but not re-entry
+ nWait = mon->waiters(); // # of threads waiting for notification,
+ // or to re-enter monitor, in Object.wait()
+
+ // Get the actual set of threads trying to enter, or re-enter, the monitor.
+ wantList = Threads::get_pending_threads(tlh.list(), nWant + nWait, (address)mon);
+ nWant = wantList->length();
} else {
// this object has a lightweight monitor
- ret.waiter_count = 0;
- ret.notify_waiter_count = 0;
}
+ if (mon != nullptr) {
+ // Robustness: the actual waiting list can be smaller.
+ // The nWait count we got from the mon->waiters() may include the re-entering
+ // the monitor threads after being notified. Here we are correcting the actual
+ // number of the waiting threads by excluding those re-entering the monitor.
+ nWait = 0;
+ for (ObjectWaiter* waiter = mon->first_waiter();
+ waiter != nullptr && (nWait == 0 || waiter != mon->first_waiter());
+ waiter = mon->next_waiter(waiter)) {
+ nWait++;
+ }
+ }
+ ret.waiter_count = nWant;
+ ret.notify_waiter_count = nWait;
+
// Allocate memory for heavyweight and lightweight monitor.
jvmtiError err;
err = allocate(ret.waiter_count * sizeof(jthread *), (unsigned char**)&ret.waiters);
@@ -1510,56 +1545,32 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
if (mon != nullptr) {
// this object has a heavyweight monitor
- // Number of waiters may actually be less than the waiter count.
- // So null out memory so that unused memory will be null.
+ // null out memory for robustness
memset(ret.waiters, 0, ret.waiter_count * sizeof(jthread *));
memset(ret.notify_waiters, 0, ret.notify_waiter_count * sizeof(jthread *));
- if (ret.waiter_count > 0) {
- // we have contending and/or waiting threads
- if (nWant > 0) {
- // we have contending threads
- ResourceMark rm(current_thread);
- // get_pending_threads returns only java thread so we do not need to
- // check for non java threads.
- GrowableArray* wantList = Threads::get_pending_threads(tlh.list(), nWant, (address)mon);
- if (wantList->length() < nWant) {
- // robustness: the pending list has gotten smaller
- nWant = wantList->length();
- }
- for (int i = 0; i < nWant; i++) {
- JavaThread *pending_thread = wantList->at(i);
- Handle th(current_thread, get_vthread_or_thread_oop(pending_thread));
- ret.waiters[i] = (jthread)jni_reference(calling_thread, th);
- }
+ if (ret.waiter_count > 0) { // we have contending threads waiting to enter/re-enter the monitor
+ // identify threads waiting to enter and re-enter the monitor
+ // get_pending_threads returns only java thread so we do not need to
+ // check for non java threads.
+ for (int i = 0; i < nWant; i++) {
+ JavaThread *pending_thread = wantList->at(i);
+ Handle th(current_thread, get_vthread_or_thread_oop(pending_thread));
+ ret.waiters[i] = (jthread)jni_reference(calling_thread, th);
}
- if (nWait > 0) {
- // we have threads in Object.wait()
- int offset = nWant; // add after any contending threads
- ObjectWaiter *waiter = mon->first_waiter();
- for (int i = 0, j = 0; i < nWait; i++) {
- if (waiter == nullptr) {
- // robustness: the waiting list has gotten smaller
- nWait = j;
- break;
- }
- JavaThread *w = mon->thread_of_waiter(waiter);
- if (w != nullptr) {
- // If the thread was found on the ObjectWaiter list, then
- // it has not been notified. This thread can't change the
- // state of the monitor so it doesn't need to be suspended.
- Handle th(current_thread, get_vthread_or_thread_oop(w));
- ret.waiters[offset + j] = (jthread)jni_reference(calling_thread, th);
- ret.notify_waiters[j++] = (jthread)jni_reference(calling_thread, th);
- }
- waiter = mon->next_waiter(waiter);
- }
+ }
+ if (ret.notify_waiter_count > 0) { // we have threads waiting to be notified in Object.wait()
+ ObjectWaiter *waiter = mon->first_waiter();
+ for (int i = 0; i < nWait; i++) {
+ JavaThread *w = mon->thread_of_waiter(waiter);
+ assert(w != nullptr, "sanity check");
+ // If the thread was found on the ObjectWaiter list, then
+ // it has not been notified.
+ Handle th(current_thread, get_vthread_or_thread_oop(w));
+ ret.notify_waiters[i] = (jthread)jni_reference(calling_thread, th);
+ waiter = mon->next_waiter(waiter);
}
- } // ThreadsListHandle is destroyed here.
-
- // Adjust count. nWant and nWait count values may be less than original.
- ret.waiter_count = nWant + nWait;
- ret.notify_waiter_count = nWait;
+ }
} else {
// this object has a lightweight monitor and we have nothing more
// to do here because the defaults are just fine.
diff --git a/src/hotspot/share/prims/jvmtiEnvBase.hpp b/src/hotspot/share/prims/jvmtiEnvBase.hpp
index 30f8183924f..7d3ea272434 100644
--- a/src/hotspot/share/prims/jvmtiEnvBase.hpp
+++ b/src/hotspot/share/prims/jvmtiEnvBase.hpp
@@ -388,9 +388,12 @@ class JvmtiEnvBase : public CHeapObj {
static jint get_thread_state_base(oop thread_oop, JavaThread* jt);
static jint get_thread_state(oop thread_oop, JavaThread* jt);
- // get virtual thread thread state
+ // get virtual thread state
static jint get_vthread_state(oop thread_oop, JavaThread* jt);
+ // get platform or virtual thread state
+ static jint get_thread_or_vthread_state(oop thread_oop, JavaThread* jt);
+
// enumerates the live threads in the given thread group
static jvmtiError get_live_threads(JavaThread* current_thread, Handle group_hdl, jint *count_ptr, Handle **thread_objs_p);
diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp
index 0a436b2778e..2afbe720732 100644
--- a/src/hotspot/share/prims/jvmtiExport.cpp
+++ b/src/hotspot/share/prims/jvmtiExport.cpp
@@ -3146,9 +3146,6 @@ bool JvmtiSampledObjectAllocEventCollector::object_alloc_is_safe_to_sample() {
return false;
}
- if (MultiArray_lock->owner() == thread) {
- return false;
- }
return true;
}
diff --git a/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp b/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp
index 405c497ab3e..26c0793f345 100644
--- a/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp
+++ b/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, 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
@@ -104,10 +104,6 @@ JvmtiGetLoadedClasses::getLoadedClasses(JvmtiEnv *env, jint* classCountPtr, jcla
LoadedClassesClosure closure(env, false);
{
- // To get a consistent list of classes we need MultiArray_lock to ensure
- // array classes aren't created.
- MutexLocker ma(MultiArray_lock);
-
// Iterate through all classes in ClassLoaderDataGraph
// and collect them using the LoadedClassesClosure
MutexLocker mcld(ClassLoaderDataGraph_lock);
@@ -124,8 +120,9 @@ JvmtiGetLoadedClasses::getClassLoaderClasses(JvmtiEnv *env, jobject initiatingLo
LoadedClassesClosure closure(env, true);
{
// To get a consistent list of classes we need MultiArray_lock to ensure
- // array classes aren't created during this walk.
- MutexLocker ma(MultiArray_lock);
+ // array classes aren't created by another thread during this walk. This walks through the
+ // InstanceKlass::_array_klasses links.
+ RecursiveLocker ma(MultiArray_lock, Thread::current());
MutexLocker sd(SystemDictionary_lock);
oop loader = JNIHandles::resolve(initiatingLoader);
// All classes loaded from this loader as initiating loader are
diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp
index 9fada531d0b..69a96747aa3 100644
--- a/src/hotspot/share/runtime/abstract_vm_version.cpp
+++ b/src/hotspot/share/runtime/abstract_vm_version.cpp
@@ -197,10 +197,6 @@ const char *Abstract_VM_Version::vm_platform_string() {
}
const char* Abstract_VM_Version::internal_vm_info_string() {
- #ifndef HOTSPOT_BUILD_USER
- #define HOTSPOT_BUILD_USER unknown
- #endif
-
#ifndef HOTSPOT_BUILD_COMPILER
#ifdef _MSC_VER
#if _MSC_VER == 1911
@@ -284,7 +280,7 @@ const char* Abstract_VM_Version::internal_vm_info_string() {
#define INTERNAL_VERSION_SUFFIX VM_RELEASE ")" \
" for " OS "-" CPU FLOAT_ARCH_STR LIBC_STR \
" JRE (" VERSION_STRING "), built on " HOTSPOT_BUILD_TIME \
- " by " XSTR(HOTSPOT_BUILD_USER) " with " HOTSPOT_BUILD_COMPILER
+ " with " HOTSPOT_BUILD_COMPILER
return strcmp(DEBUG_LEVEL, "release") == 0
? VMNAME " (" INTERNAL_VERSION_SUFFIX
diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp
index f14cf6c6e99..be1d1993f79 100644
--- a/src/hotspot/share/runtime/frame.cpp
+++ b/src/hotspot/share/runtime/frame.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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
@@ -1661,6 +1661,7 @@ void FrameValues::print_on(outputStream* st, int min_index, int max_index, intpt
intptr_t* max = MAX2(v0, v1);
intptr_t* cur = max;
intptr_t* last = nullptr;
+ intptr_t* fp = nullptr;
for (int i = max_index; i >= min_index; i--) {
FrameValue fv = _values.at(i);
while (cur > fv.location) {
@@ -1671,7 +1672,20 @@ void FrameValues::print_on(outputStream* st, int min_index, int max_index, intpt
const char* spacer = " " LP64_ONLY(" ");
st->print_cr(" %s %s %s", spacer, spacer, fv.description);
} else {
+ if (*fv.description == '#' && isdigit(fv.description[1])) {
+ // The fv.description string starting with a '#' is the line for the
+ // saved frame pointer eg. "#10 method java.lang.invoke.LambdaForm..."
+ // basicaly means frame 10.
+ fp = fv.location;
+ }
+ // To print a fp-relative value:
+ // 1. The content of *fv.location must be such that we think it's a
+ // fp-relative number, i.e [-100..100].
+ // 2. We must have found the frame pointer.
+ // 3. The line can not be the line for the saved frame pointer.
+ // 4. Recognize it as being part of the "fixed frame".
if (*fv.location != 0 && *fv.location > -100 && *fv.location < 100
+ && fp != nullptr && *fv.description != '#'
#if !defined(PPC64)
&& (strncmp(fv.description, "interpreter_frame_", 18) == 0 || strstr(fv.description, " method "))
#else // !defined(PPC64)
@@ -1680,7 +1694,8 @@ void FrameValues::print_on(outputStream* st, int min_index, int max_index, intpt
strcmp(fv.description, "locals") == 0 || strstr(fv.description, " method "))
#endif //!defined(PPC64)
) {
- st->print_cr(" " INTPTR_FORMAT ": %18d %s", p2i(fv.location), (int)*fv.location, fv.description);
+ st->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %-32s (relativized: fp%+d)",
+ p2i(fv.location), p2i(&fp[*fv.location]), fv.description, (int)*fv.location);
} else {
st->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", p2i(fv.location), *fv.location, fv.description);
}
diff --git a/src/hotspot/share/runtime/mutex.cpp b/src/hotspot/share/runtime/mutex.cpp
index 3fd7fbd8300..6466d18e538 100644
--- a/src/hotspot/share/runtime/mutex.cpp
+++ b/src/hotspot/share/runtime/mutex.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2024, 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,6 +31,7 @@
#include "runtime/os.inline.hpp"
#include "runtime/osThread.hpp"
#include "runtime/safepointMechanism.inline.hpp"
+#include "runtime/semaphore.inline.hpp"
#include "runtime/threadCrashProtection.hpp"
#include "utilities/events.hpp"
#include "utilities/macros.hpp"
@@ -522,3 +523,33 @@ void Mutex::set_owner_implementation(Thread *new_owner) {
}
}
#endif // ASSERT
+
+
+RecursiveMutex::RecursiveMutex() : _sem(1), _owner(nullptr), _recursions(0) {}
+
+void RecursiveMutex::lock(Thread* current) {
+ assert(current == Thread::current(), "must be current thread");
+ if (current == _owner) {
+ _recursions++;
+ } else {
+ // can be called by jvmti by VMThread.
+ if (current->is_Java_thread()) {
+ _sem.wait_with_safepoint_check(JavaThread::cast(current));
+ } else {
+ _sem.wait();
+ }
+ _recursions++;
+ assert(_recursions == 1, "should be");
+ _owner = current;
+ }
+}
+
+void RecursiveMutex::unlock(Thread* current) {
+ assert(current == Thread::current(), "must be current thread");
+ assert(current == _owner, "must be owner");
+ _recursions--;
+ if (_recursions == 0) {
+ _owner = nullptr;
+ _sem.signal();
+ }
+}
diff --git a/src/hotspot/share/runtime/mutex.hpp b/src/hotspot/share/runtime/mutex.hpp
index 10671d651b1..8818447e5dd 100644
--- a/src/hotspot/share/runtime/mutex.hpp
+++ b/src/hotspot/share/runtime/mutex.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2024, 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 "memory/allocation.hpp"
#include "runtime/atomic.hpp"
+#include "runtime/semaphore.hpp"
#if defined(LINUX) || defined(AIX) || defined(BSD)
# include "mutex_posix.hpp"
@@ -241,4 +242,24 @@ class PaddedMonitor : public Monitor {
PaddedMonitor(Rank rank, const char *name) : Monitor(rank, name) {};
};
+// RecursiveMutex is a minimal implementation, and has no safety and rank checks that Mutex has.
+// There are also no checks that the recursive lock is not held when going to Java or to JNI, like
+// other JVM mutexes have. This should be used only for cases where the alternatives with all the
+// nice safety features don't work.
+// Waiting on the RecursiveMutex partipates in the safepoint protocol if the current thread is a Java thread,
+// (ie. waiting sets JavaThread to blocked)
+class RecursiveMutex : public CHeapObj {
+ Semaphore _sem;
+ Thread* _owner;
+ int _recursions;
+
+ NONCOPYABLE(RecursiveMutex);
+ public:
+ RecursiveMutex();
+ void lock(Thread* current);
+ void unlock(Thread* current);
+ // For use in asserts
+ bool holds_lock(Thread* current) { return _owner == current; }
+};
+
#endif // SHARE_RUNTIME_MUTEX_HPP
diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp
index efd8490cd80..09976493fe9 100644
--- a/src/hotspot/share/runtime/mutexLocker.cpp
+++ b/src/hotspot/share/runtime/mutexLocker.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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
@@ -86,7 +86,6 @@ Monitor* Compilation_lock = nullptr;
Mutex* CompileTaskAlloc_lock = nullptr;
Mutex* CompileStatistics_lock = nullptr;
Mutex* DirectivesStack_lock = nullptr;
-Mutex* MultiArray_lock = nullptr;
Monitor* Terminator_lock = nullptr;
Monitor* InitCompleted_lock = nullptr;
Monitor* BeforeExit_lock = nullptr;
@@ -156,6 +155,8 @@ Monitor* JVMCI_lock = nullptr;
Monitor* JVMCIRuntime_lock = nullptr;
#endif
+// Only one RecursiveMutex
+RecursiveMutex* MultiArray_lock = nullptr;
#define MAX_NUM_MUTEX 128
static Mutex* _mutex_array[MAX_NUM_MUTEX];
@@ -269,7 +270,6 @@ void mutex_init() {
MUTEX_DEFN(MethodCompileQueue_lock , PaddedMonitor, safepoint);
MUTEX_DEFN(CompileStatistics_lock , PaddedMutex , safepoint);
MUTEX_DEFN(DirectivesStack_lock , PaddedMutex , nosafepoint);
- MUTEX_DEFN(MultiArray_lock , PaddedMutex , safepoint);
MUTEX_DEFN(JvmtiThreadState_lock , PaddedMutex , safepoint); // Used by JvmtiThreadState/JvmtiEventController
MUTEX_DEFN(EscapeBarrier_lock , PaddedMonitor, nosafepoint); // Used to synchronize object reallocation/relocking triggered by JVMTI
@@ -283,6 +283,7 @@ void mutex_init() {
MUTEX_DEFN(PeriodicTask_lock , PaddedMonitor, safepoint, true);
MUTEX_DEFN(RedefineClasses_lock , PaddedMonitor, safepoint);
MUTEX_DEFN(Verify_lock , PaddedMutex , safepoint);
+ MUTEX_DEFN(ClassLoaderDataGraph_lock , PaddedMutex , safepoint);
if (WhiteBoxAPI) {
MUTEX_DEFN(Compilation_lock , PaddedMonitor, nosafepoint);
@@ -334,7 +335,6 @@ void mutex_init() {
MUTEX_DEFL(PerfDataMemAlloc_lock , PaddedMutex , Heap_lock);
MUTEX_DEFL(PerfDataManager_lock , PaddedMutex , Heap_lock);
- MUTEX_DEFL(ClassLoaderDataGraph_lock , PaddedMutex , MultiArray_lock);
MUTEX_DEFL(VMOperation_lock , PaddedMonitor, Heap_lock, true);
MUTEX_DEFL(ClassInitError_lock , PaddedMonitor, Threads_lock);
@@ -357,6 +357,9 @@ void mutex_init() {
// JVMCIRuntime_lock must be acquired before JVMCI_lock to avoid deadlock
MUTEX_DEFL(JVMCI_lock , PaddedMonitor, JVMCIRuntime_lock);
#endif
+
+ // Allocate RecursiveMutex
+ MultiArray_lock = new RecursiveMutex();
}
#undef MUTEX_DEFL
diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp
index 840d01e62fa..7729189e18a 100644
--- a/src/hotspot/share/runtime/mutexLocker.hpp
+++ b/src/hotspot/share/runtime/mutexLocker.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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
@@ -83,7 +83,6 @@ extern Monitor* Compilation_lock; // a lock used to pause compila
extern Mutex* CompileTaskAlloc_lock; // a lock held when CompileTasks are allocated
extern Mutex* CompileStatistics_lock; // a lock held when updating compilation statistics
extern Mutex* DirectivesStack_lock; // a lock held when mutating the dirstack and ref counting directives
-extern Mutex* MultiArray_lock; // a lock used to guard allocation of multi-dim arrays
extern Monitor* Terminator_lock; // a lock used to guard termination of the vm
extern Monitor* InitCompleted_lock; // a lock used to signal threads waiting on init completed
extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks
@@ -332,4 +331,21 @@ class MutexUnlocker: StackObj {
}
};
+// Instance of a RecursiveLock that may be held through Java heap allocation, which may include calls to Java,
+// and JNI event notification for resource exhaustion for metaspace or heap.
+extern RecursiveMutex* MultiArray_lock;
+
+// RAII locker for a RecursiveMutex. See comments in mutex.hpp for more information.
+class RecursiveLocker {
+ RecursiveMutex* _lock;
+ Thread* _thread;
+ public:
+ RecursiveLocker(RecursiveMutex* lock, Thread* current) : _lock(lock), _thread(current) {
+ _lock->lock(_thread);
+ }
+ ~RecursiveLocker() {
+ _lock->unlock(_thread);
+ }
+};
+
#endif // SHARE_RUNTIME_MUTEXLOCKER_HPP
diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp
index 9b5bbfa772a..2f9ca1d5147 100644
--- a/src/hotspot/share/runtime/os.cpp
+++ b/src/hotspot/share/runtime/os.cpp
@@ -1892,7 +1892,16 @@ char* os::attempt_reserve_memory_between(char* min, char* max, size_t bytes, siz
char* const absolute_max = (char*)(NOT_LP64(G * 3) LP64_ONLY(G * 128 * 1024));
char* const absolute_min = (char*) os::vm_min_address();
- const size_t alignment_adjusted = MAX2(alignment, os::vm_allocation_granularity());
+ // AIX is the only platform that uses System V shm for reserving virtual memory.
+ // In this case, the required alignment of the allocated size (64K) and the alignment
+ // of possible start points of the memory region (256M) differ.
+ // This is not reflected by os_allocation_granularity().
+ // The logic here is dual to the one in pd_reserve_memory in os_aix.cpp
+ const size_t system_allocation_granularity =
+ AIX_ONLY(os::vm_page_size() == 4*K ? 4*K : 256*M)
+ NOT_AIX(os::vm_allocation_granularity());
+
+ const size_t alignment_adjusted = MAX2(alignment, system_allocation_granularity);
// Calculate first and last possible attach points:
char* const lo_att = align_up(MAX2(absolute_min, min), alignment_adjusted);
diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp
index 265f4127d41..8ff468ab4ca 100644
--- a/src/hotspot/share/runtime/threads.cpp
+++ b/src/hotspot/share/runtime/threads.cpp
@@ -60,6 +60,7 @@
#include "oops/symbol.hpp"
#include "prims/jvm_misc.hpp"
#include "prims/jvmtiAgentList.hpp"
+#include "prims/jvmtiEnvBase.hpp"
#include "runtime/arguments.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/flags/jvmFlagLimit.hpp"
@@ -1182,10 +1183,12 @@ void Threads::metadata_handles_do(void f(Metadata*)) {
threads_do(&handles_closure);
}
-// Get count Java threads that are waiting to enter the specified monitor.
+#if INCLUDE_JVMTI
+// Get count of Java threads that are waiting to enter or re-enter the specified monitor.
GrowableArray* Threads::get_pending_threads(ThreadsList * t_list,
int count,
address monitor) {
+ assert(Thread::current()->is_VM_thread(), "Must be the VM thread");
GrowableArray* result = new GrowableArray(count);
int i = 0;
@@ -1195,7 +1198,14 @@ GrowableArray* Threads::get_pending_threads(ThreadsList * t_list,
// The first stage of async deflation does not affect any field
// used by this comparison so the ObjectMonitor* is usable here.
address pending = (address)p->current_pending_monitor();
- if (pending == monitor) { // found a match
+ address waiting = (address)p->current_waiting_monitor();
+ oop thread_oop = JvmtiEnvBase::get_vthread_or_thread_oop(p);
+ bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop);
+ jint state = is_virtual ? JvmtiEnvBase::get_vthread_state(thread_oop, p)
+ : JvmtiEnvBase::get_thread_state(thread_oop, p);
+ if (pending == monitor || (waiting == monitor &&
+ (state & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER))
+ ) { // found a match
if (i < count) result->append(p); // save the first count matches
i++;
}
@@ -1203,7 +1213,7 @@ GrowableArray* Threads::get_pending_threads(ThreadsList * t_list,
return result;
}
-
+#endif // INCLUDE_JVMTI
JavaThread *Threads::owning_thread_from_monitor_owner(ThreadsList * t_list,
address owner) {
diff --git a/src/hotspot/share/runtime/threads.hpp b/src/hotspot/share/runtime/threads.hpp
index 8d61431f0ce..97cfeea07ad 100644
--- a/src/hotspot/share/runtime/threads.hpp
+++ b/src/hotspot/share/runtime/threads.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, Azul Systems, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -131,7 +131,7 @@ class Threads: AllStatic {
// Print threads busy compiling, and returns the number of printed threads.
static unsigned print_threads_compiling(outputStream* st, char* buf, int buflen, bool short_form = false);
- // Get Java threads that are waiting to enter a monitor.
+ // Get count of Java threads that are waiting to enter or re-enter the specified monitor.
static GrowableArray* get_pending_threads(ThreadsList * t_list,
int count, address monitor);
diff --git a/src/hotspot/share/utilities/bitMap.cpp b/src/hotspot/share/utilities/bitMap.cpp
index 3cef6122557..9bd5c8e0006 100644
--- a/src/hotspot/share/utilities/bitMap.cpp
+++ b/src/hotspot/share/utilities/bitMap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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
@@ -99,6 +99,54 @@ void GrowableBitMap::resize(idx_t new_size_in_bits, bool cl
update(map, new_size_in_bits);
}
+template
+bm_word_t* GrowableBitMap::copy_of_range(idx_t start_bit, idx_t end_bit) {
+ assert(start_bit < end_bit, "End bit must come after start bit");
+ assert(end_bit <= size(), "End bit not in bitmap");
+
+ // We might have extra bits at the end that we don't want to lose
+ const idx_t cutoff = bit_in_word(end_bit);
+ const idx_t start_word = to_words_align_down(start_bit);
+ const idx_t end_word = to_words_align_up(end_bit);
+ const bm_word_t* const old_map = map();
+
+ const BitMapWithAllocator* const derived = static_cast(this);
+
+ bm_word_t* const new_map = derived->allocate(end_word - start_word);
+
+ // All words need to be shifted by this amount
+ const idx_t shift = bit_in_word(start_bit);
+ // Bits shifted out by a word need to be passed into the next
+ bm_word_t carry = 0;
+
+ // Iterate the map backwards as the shift will result in carry-out bits
+ for (idx_t i = end_word; i-- > start_word;) {
+ new_map[i-start_word] = old_map[i] >> shift;
+
+ if (shift != 0) {
+ new_map[i-start_word] |= carry;
+ carry = old_map[i] << (BitsPerWord - shift);
+ }
+ }
+
+ return new_map;
+}
+
+template
+void GrowableBitMap::truncate(idx_t start_bit, idx_t end_bit) {
+ const size_t old_size_in_words = calc_size_in_words(size());
+ const idx_t new_size_in_bits = end_bit - start_bit;
+ bm_word_t* const old_map = map();
+
+ bm_word_t* const new_map = copy_of_range(start_bit, end_bit);
+
+ const BitMapWithAllocator* const derived = static_cast(this);
+ // Free and clear old map to avoid left over bits
+ derived->free(old_map, old_size_in_words);
+ update(nullptr, 0);
+ update(new_map, new_size_in_bits);
+}
+
ArenaBitMap::ArenaBitMap(Arena* arena, idx_t size_in_bits, bool clear)
: GrowableBitMap(), _arena(arena) {
initialize(size_in_bits, clear);
diff --git a/src/hotspot/share/utilities/bitMap.hpp b/src/hotspot/share/utilities/bitMap.hpp
index fd696bc7502..6d83c5cdad9 100644
--- a/src/hotspot/share/utilities/bitMap.hpp
+++ b/src/hotspot/share/utilities/bitMap.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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
@@ -566,6 +566,11 @@ class GrowableBitMap : public BitMap {
GrowableBitMap() : GrowableBitMap(nullptr, 0) {}
GrowableBitMap(bm_word_t* map, idx_t size_in_bits) : BitMap(map, size_in_bits) {}
+ private:
+ // Copy the region [start, end) of the bitmap
+ // Bits in the selected range are copied to a newly allocated map
+ bm_word_t* copy_of_range(idx_t start_bit, idx_t end_bit);
+
public:
// Set up and optionally clear the bitmap memory.
//
@@ -585,6 +590,9 @@ class GrowableBitMap : public BitMap {
// Old bits are transferred to the new memory
// and the extended memory is optionally cleared.
void resize(idx_t new_size_in_bits, bool clear = true);
+ // Reduce bitmap to the region [start, end)
+ // Previous map is deallocated and replaced with the newly allocated map from copy_of_range
+ void truncate(idx_t start_bit, idx_t end_bit);
};
// A concrete implementation of the "abstract" BitMap class.
diff --git a/src/hotspot/share/utilities/debug.hpp b/src/hotspot/share/utilities/debug.hpp
index be0ee035d08..3a9adda9054 100644
--- a/src/hotspot/share/utilities/debug.hpp
+++ b/src/hotspot/share/utilities/debug.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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
@@ -108,9 +108,8 @@ class DebuggingContext {
// constant evaluation.
#if defined(TARGET_COMPILER_gcc) || defined(TARGET_COMPILER_xlc)
-// gcc10 added both __has_builtin and __builtin_is_constant_evaluated.
-// clang has had __has_builtin for a long time, so likely also in xlclang++.
-// Similarly, clang has had __builtin_is_constant_evaluated for a long time.
+// Both __has_builtin and __builtin_is_constant_evaluated are available in our
+// minimum required versions of gcc and clang.
#ifdef __has_builtin
#if __has_builtin(__builtin_is_constant_evaluated)
diff --git a/src/hotspot/share/utilities/globalDefinitions.cpp b/src/hotspot/share/utilities/globalDefinitions.cpp
index 1c201c1709c..791492f4d4a 100644
--- a/src/hotspot/share/utilities/globalDefinitions.cpp
+++ b/src/hotspot/share/utilities/globalDefinitions.cpp
@@ -157,7 +157,6 @@ void basic_types_init() {
static_assert(is_power_of_2(HeapWordSize), "HeapWordSize must be power of 2");
static_assert((size_t)HeapWordSize >= sizeof(juint),
"HeapWord should be at least as large as juint");
- static_assert(sizeof(NULL) == sizeof(char*), "NULL must be same size as pointer");
#endif
if( JavaPriority1_To_OSPriority != -1 )
diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp
index 896801b8be1..9d421e71ffb 100644
--- a/src/hotspot/share/utilities/globalDefinitions.hpp
+++ b/src/hotspot/share/utilities/globalDefinitions.hpp
@@ -616,13 +616,6 @@ const bool support_IRIW_for_not_multiple_copy_atomic_cpu = PPC64_ONLY(true) NOT_
#endif
-//----------------------------------------------------------------------------------------------------
-// Utility macros for compilers
-// used to silence compiler warnings
-
-#define Unused_Variable(var) var
-
-
//----------------------------------------------------------------------------------------------------
// Prototyping
// "Code Missing Here" macro, un-define when integrating back from prototyping stage and break
diff --git a/src/hotspot/share/utilities/globalDefinitions_xlc.hpp b/src/hotspot/share/utilities/globalDefinitions_xlc.hpp
index 0064e15c04f..9595452d399 100644
--- a/src/hotspot/share/utilities/globalDefinitions_xlc.hpp
+++ b/src/hotspot/share/utilities/globalDefinitions_xlc.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2023 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -61,28 +61,18 @@
#include
-// check for xlc16 or higher
-#ifdef __ibmxl_version__
- #if __ibmxl_version__ < 16
- #error "xlc < 16 not supported"
- #endif
-#elif defined(__open_xl_version__)
+#if defined(__open_xl_version__)
#if __open_xl_version__ < 17
#error "open xlc < 17 not supported"
#endif
#else
- #error "xlc version not supported, macro __ibmxl_version__ or __open_xl_version__ not found"
+ #error "xlc version not supported, macro __open_xl_version__ not found"
#endif
#ifndef _AIX
#error "missing AIX-specific definition _AIX"
#endif
-// Shortcut for the new xlc 17 compiler
-#if defined(AIX) && defined(__open_xl_version__) && __open_xl_version__ >= 17
-#define AIX_XLC_GE_17
-#endif
-
// Use XLC compiler builtins instead of inline assembler
#define USE_XLC_BUILTINS
@@ -93,22 +83,8 @@
// NULL vs NULL_WORD:
// Some platform/tool-chain combinations can't assign NULL to an integer
-// type so we define NULL_WORD to use in those contexts. For xlc they are the same.
-#define NULL_WORD NULL
-
-// AIX also needs a 64 bit NULL to work as a null address pointer.
-// Most system includes on AIX would define it as an int 0 if not already defined with one
-// exception: /usr/include/dirent.h will unconditionally redefine NULL to int 0 again.
-// In this case you need to copy the following defines to a position after #include
-#include
-#ifdef _LP64
- #undef NULL
- #define NULL 0L
-#else
- #ifndef NULL
- #define NULL 0
- #endif
-#endif
+// type so we define NULL_WORD to use in those contexts.
+#define NULL_WORD 0L
// checking for nanness
inline int g_isnan(float f) { return isnan(f); }
diff --git a/src/java.base/aix/native/libnio/ch/Pollset.c b/src/java.base/aix/native/libnio/ch/Pollset.c
index 290bb548049..0ad5b5a3974 100644
--- a/src/java.base/aix/native/libnio/ch/Pollset.c
+++ b/src/java.base/aix/native/libnio/ch/Pollset.c
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 SAP SE. All rights reserved.
+ * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 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
@@ -40,13 +40,6 @@
#include
#include
-/* Initially copied from src/solaris/native/sun/nio/ch/nio_util.h */
-#define RESTARTABLE(_cmd, _result) do { \
- do { \
- _result = _cmd; \
- } while((_result == -1) && (errno == EINTR)); \
-} while(0)
-
typedef pollset_t pollset_create_func(int maxfd);
typedef int pollset_destroy_func(pollset_t ps);
typedef int pollset_ctl_func(pollset_t ps, struct poll_ctl *pollctl_array, int array_length);
diff --git a/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c b/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c
index 37628f5621a..95f78ffa135 100644
--- a/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c
+++ b/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c
@@ -50,12 +50,6 @@ typedef ssize_t copy_file_range_func(int, loff_t*, int, loff_t*, size_t,
unsigned int);
static copy_file_range_func* my_copy_file_range_func = NULL;
-#define RESTARTABLE(_cmd, _result) do { \
- do { \
- _result = _cmd; \
- } while((_result == -1) && (errno == EINTR)); \
-} while(0)
-
static void throwUnixException(JNIEnv* env, int errnum) {
jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
"(I)V", errnum);
diff --git a/src/java.base/macosx/native/libnio/fs/BsdFileSystem.c b/src/java.base/macosx/native/libnio/fs/BsdFileSystem.c
index b3ae3f6a72b..4faa3ea0332 100644
--- a/src/java.base/macosx/native/libnio/fs/BsdFileSystem.c
+++ b/src/java.base/macosx/native/libnio/fs/BsdFileSystem.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,12 +36,6 @@
#include
#include "sun_nio_fs_BsdFileSystem.h"
-#define RESTARTABLE(_cmd, _result) do { \
- do { \
- _result = _cmd; \
- } while((_result == -1) && (errno == EINTR)); \
-} while(0)
-
static void throwUnixException(JNIEnv* env, int errnum) {
jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
"(I)V", errnum);
diff --git a/src/java.base/share/classes/java/io/BufferedInputStream.java b/src/java.base/share/classes/java/io/BufferedInputStream.java
index d4531d27db1..cfc2a3d2c75 100644
--- a/src/java.base/share/classes/java/io/BufferedInputStream.java
+++ b/src/java.base/share/classes/java/io/BufferedInputStream.java
@@ -61,7 +61,7 @@ public class BufferedInputStream extends FilterInputStream {
/**
* As this class is used early during bootstrap, it's motivated to use
- * Unsafe.compareAndSetObject instead of AtomicReferenceFieldUpdater
+ * Unsafe.compareAndSetReference instead of AtomicReferenceFieldUpdater
* (or VarHandles) to reduce dependencies and improve startup time.
*/
private static final Unsafe U = Unsafe.getUnsafe();
diff --git a/src/java.base/share/classes/java/lang/Module.java b/src/java.base/share/classes/java/lang/Module.java
index 7157ace8c47..82dae27efa0 100644
--- a/src/java.base/share/classes/java/lang/Module.java
+++ b/src/java.base/share/classes/java/lang/Module.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2024, 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
@@ -143,10 +143,6 @@ public final class Module implements AnnotatedElement {
String loc = Objects.toString(uri, null);
Object[] packages = descriptor.packages().toArray();
defineModule0(this, isOpen, vs, loc, packages);
- if (loader == null || loader == ClassLoaders.platformClassLoader()) {
- // boot/builtin modules are always native
- implAddEnableNativeAccess();
- }
}
diff --git a/src/java.base/share/classes/java/lang/ModuleLayer.java b/src/java.base/share/classes/java/lang/ModuleLayer.java
index 814cdeb7e6d..3a13982c9b9 100644
--- a/src/java.base/share/classes/java/lang/ModuleLayer.java
+++ b/src/java.base/share/classes/java/lang/ModuleLayer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2024, 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
@@ -881,6 +881,24 @@ public Optional findModule(String name) {
.findAny();
}
+ /**
+ * Updates the module with the given {@code name} in this layer
+ * to allow access to restricted methods.
+ *
+ * @param name the name of the module for which the native access
+ * should be enabled
+ * @return {@code true} iff the module is present in this layer,
+ * {@code false} otherwise
+ */
+ boolean addEnableNativeAccess(String name) {
+ Module m = nameToModule.get(name);
+ if (m != null) {
+ m.implAddEnableNativeAccess();
+ return true;
+ } else {
+ return false;
+ }
+ }
/**
* Returns the {@code ClassLoader} for the module with the given name. If
diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java
index 355b7cb8934..bfd91e88122 100644
--- a/src/java.base/share/classes/java/lang/System.java
+++ b/src/java.base/share/classes/java/lang/System.java
@@ -2460,6 +2460,9 @@ public boolean isReflectivelyOpened(Module m, String pn, Module other) {
public Module addEnableNativeAccess(Module m) {
return m.implAddEnableNativeAccess();
}
+ public boolean addEnableNativeAccess(ModuleLayer layer, String name) {
+ return layer.addEnableNativeAccess(name);
+ }
public void addEnableNativeAccessToAllUnnamed() {
Module.implAddEnableNativeAccessToAllUnnamed();
}
diff --git a/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java b/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java
index ca652d8d29d..19a193a924a 100644
--- a/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java
+++ b/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2024, 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
@@ -28,6 +28,7 @@
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Opcodes;
import sun.invoke.util.Wrapper;
+import sun.util.logging.PlatformLogger;
import java.util.ArrayList;
import java.util.HashSet;
@@ -136,9 +137,7 @@ Map build() {
for (String invokerType : invokerTypes) {
MethodType mt = asMethodType(invokerType);
final int lastParam = mt.parameterCount() - 1;
- if (mt.parameterCount() < 2 ||
- mt.parameterType(0) != Object.class ||
- mt.parameterType(lastParam) != Object.class) {
+ if (!checkInvokerTypeParams(mt)) {
throw new RuntimeException(
"Invoker type parameter must start and end with Object: " + invokerType);
}
@@ -190,7 +189,7 @@ Map build() {
return result;
}
- private static MethodType asMethodType(String basicSignatureString) {
+ public static MethodType asMethodType(String basicSignatureString) {
String[] parts = basicSignatureString.split("_");
assert (parts.length == 2);
assert (parts[1].length() == 1);
@@ -207,6 +206,13 @@ private static MethodType asMethodType(String basicSignatureString) {
}
}
+ public static boolean checkInvokerTypeParams(MethodType mt) {
+ final int lastParam = mt.parameterCount() - 1;
+ return (mt.parameterCount() >= 2 &&
+ mt.parameterType(0) == Object.class &&
+ mt.parameterType(lastParam) == Object.class);
+ }
+
private void addDMHMethodType(String dmh, String methodType) {
validateMethodType(methodType);
Set methodTypes = dmhMethods.get(dmh);
@@ -315,7 +321,14 @@ static Map generateHolderClasses(Stream traces) {
"linkToCallSite".equals(parts[2])) {
builder.addCallSiteType(methodType);
} else {
- builder.addInvokerType(methodType);
+ MethodType mt = HolderClassBuilder.asMethodType(methodType);
+ // Work around JDK-8327499
+ if (HolderClassBuilder.checkInvokerTypeParams(mt)) {
+ builder.addInvokerType(methodType);
+ } else {
+ PlatformLogger.getLogger("java.lang.invoke")
+ .warning("Invalid LF_RESOLVE " + parts[1] + " " + parts[2] + " " + parts[3]);
+ }
}
} else if (parts[1].contains("DirectMethodHandle")) {
String dmh = parts[2];
diff --git a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
index 46372b1717c..329924d96f9 100644
--- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
+++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024, 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
@@ -258,7 +258,7 @@ CallSite buildCallSite() throws LambdaConversionException {
private Class> spinInnerClass() throws LambdaConversionException {
// CDS does not handle disableEagerInitialization or useImplMethodHandle
if (!disableEagerInitialization && !useImplMethodHandle) {
- if (CDS.isSharingEnabled()) {
+ if (CDS.isUsingArchive()) {
// load from CDS archive if present
Class> innerClass = LambdaProxyClassArchive.find(targetClass,
interfaceMethodName,
diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaProxyClassArchive.java b/src/java.base/share/classes/java/lang/invoke/LambdaProxyClassArchive.java
index ef79f4d473c..4d14848043a 100644
--- a/src/java.base/share/classes/java/lang/invoke/LambdaProxyClassArchive.java
+++ b/src/java.base/share/classes/java/lang/invoke/LambdaProxyClassArchive.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2024, 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
@@ -102,7 +102,7 @@ static Class> find(Class> caller,
Class>[] altInterfaces,
MethodType[] altMethods) {
if (!loadedByBuiltinLoader(caller) ||
- !CDS.isSharingEnabled() || isSerializable || altInterfaces.length > 0 || altMethods.length > 0)
+ !CDS.isUsingArchive() || isSerializable || altInterfaces.length > 0 || altMethods.length > 0)
return null;
return findFromArchive(caller, interfaceMethodName, factoryType, interfaceMethodType,
diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java
index 0191306881b..7d87d4f79a8 100644
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2024, 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
@@ -134,8 +134,8 @@ static void traceLambdaForm(String name, MethodType type, Class> holder, Membe
shortenSignature(basicTypeSignature(type)) +
(resolvedMember != null ? " (success)" : " (fail)"));
}
- if (CDS.isDumpingClassList()) {
- CDS.traceLambdaFormInvoker("[LF_RESOLVE]", holder.getName(), name, shortenSignature(basicTypeSignature(type)));
+ if (CDS.isLoggingLambdaFormInvokers()) {
+ CDS.logLambdaFormInvoker("[LF_RESOLVE]", holder.getName(), name, shortenSignature(basicTypeSignature(type)));
}
}
@@ -148,8 +148,8 @@ static void traceSpeciesType(String cn, Class> salvage) {
if (TRACE_RESOLVE) {
System.out.println("[SPECIES_RESOLVE] " + cn + (salvage != null ? " (salvaged)" : " (generated)"));
}
- if (CDS.isDumpingClassList()) {
- CDS.traceSpeciesType("[SPECIES_RESOLVE]", cn);
+ if (CDS.isLoggingLambdaFormInvokers()) {
+ CDS.logSpeciesType("[SPECIES_RESOLVE]", cn);
}
}
// handy shared exception makers (they simplify the common case code)
diff --git a/src/java.base/share/classes/java/net/SocketPermission.java b/src/java.base/share/classes/java/net/SocketPermission.java
index 6c9647d888c..ba1e7b8436c 100644
--- a/src/java.base/share/classes/java/net/SocketPermission.java
+++ b/src/java.base/share/classes/java/net/SocketPermission.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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
@@ -178,7 +178,7 @@ public final class SocketPermission extends Permission
/**
* No actions
*/
- private static final int NONE = 0x0;
+ private static final int NONE = 0x0;
/**
* All actions
@@ -188,8 +188,6 @@ public final class SocketPermission extends Permission
// various port constants
private static final int PORT_MIN = 0;
private static final int PORT_MAX = 65535;
- private static final int PRIV_PORT_MAX = 1023;
- private static final int DEF_EPH_LOW = 49152;
// the actions mask
private transient int mask;
@@ -242,9 +240,9 @@ public final class SocketPermission extends Permission
// lazy initializer
private static class EphemeralRange {
- static final int low = initEphemeralPorts("low", DEF_EPH_LOW);
- static final int high = initEphemeralPorts("high", PORT_MAX);
- };
+ static final int low = initEphemeralPorts("low");
+ static final int high = initEphemeralPorts("high");
+ }
private static synchronized Debug getDebug() {
if (!debugInit) {
@@ -342,10 +340,7 @@ private static String getHost(String host) {
}
}
- private int[] parsePort(String port)
- throws Exception
- {
-
+ private int[] parsePort(String port) {
if (port == null || port.isEmpty() || port.equals("*")) {
return new int[] {PORT_MIN, PORT_MAX};
}
@@ -466,7 +461,7 @@ private void init(String host, int mask) {
// see if we are being initialized with an IP address.
char ch = host.charAt(0);
if (ch == ':' || IPAddressUtil.digit(ch, 16) != -1) {
- byte ip[] = IPAddressUtil.textToNumericFormatV4(host);
+ byte[] ip = IPAddressUtil.textToNumericFormatV4(host);
if (ip == null) {
ip = IPAddressUtil.textToNumericFormatV6(host);
}
@@ -521,8 +516,6 @@ private static int getMask(String action) {
char[] a = action.toCharArray();
int i = a.length - 1;
- if (i < 0)
- return mask;
while (i != -1) {
char c;
@@ -619,13 +612,13 @@ private boolean isUntrusted()
if (invalid || untrusted) return true;
try {
if (!trustNameService && (defaultDeny ||
- sun.net.www.URLConnection.isProxiedHost(hostname))) {
+ sun.net.www.URLConnection.isProxiedHost(hostname))) {
if (this.cname == null) {
this.getCanonName();
}
if (!match(cname, hostname)) {
// Last chance
- if (!authorized(hostname, addresses[0].getAddress())) {
+ if (!authorized(addresses[0].getAddress())) {
untrusted = true;
Debug debug = getDebug();
if (debug != null && Debug.isOn("failure")) {
@@ -711,16 +704,16 @@ private boolean match(String cname, String hname) {
return !cdomain.isEmpty() && !hdomain.isEmpty() && cdomain.equals(hdomain);
}
- private boolean authorized(String cname, byte[] addr) {
+ private boolean authorized(byte[] addr) {
if (addr.length == 4)
- return authorizedIPv4(cname, addr);
+ return authorizedIPv4(addr);
else if (addr.length == 16)
- return authorizedIPv6(cname, addr);
+ return authorizedIPv6(addr);
else
return false;
}
- private boolean authorizedIPv4(String cname, byte[] addr) {
+ private boolean authorizedIPv4(byte[] addr) {
String authHost = "";
InetAddress auth;
@@ -749,7 +742,7 @@ private boolean authorizedIPv4(String cname, byte[] addr) {
return false;
}
- private boolean authorizedIPv6(String cname, byte[] addr) {
+ private boolean authorizedIPv6(byte[] addr) {
String authHost = "";
InetAddress auth;
@@ -854,8 +847,6 @@ void getIP()
*/
@Override
public boolean implies(Permission p) {
- int i,j;
-
if (!(p instanceof SocketPermission that))
return false;
@@ -1221,7 +1212,7 @@ private synchronized void readObject(java.io.ObjectInputStream s)
* for this system. The suffix is either "high" or "low"
*/
@SuppressWarnings("removal")
- private static int initEphemeralPorts(String suffix, int defval) {
+ private static int initEphemeralPorts(String suffix) {
return AccessController.doPrivileged(
new PrivilegedAction<>(){
public Integer run() {
diff --git a/src/java.base/share/classes/java/net/doc-files/net-properties.html b/src/java.base/share/classes/java/net/doc-files/net-properties.html
index 6c5137fc991..a61844cca6e 100644
--- a/src/java.base/share/classes/java/net/doc-files/net-properties.html
+++ b/src/java.base/share/classes/java/net/doc-files/net-properties.html
@@ -68,12 +68,20 @@
IPv4 / IPv6
Proxies
A proxy server allows indirect connection to network services and
is used mainly for security (to get through firewalls) and
-performance reasons (proxies often do provide caching mechanisms).
-The following properties allow for configuration of the various type
-of proxies.
+performance reasons (proxies often do provide caching mechanisms).
+
Applications may use the {@link java.net.ProxySelector#select(URI)} method
+to determine the proxy that should be used for connecting to a given URI.
+
The following properties are used to configure the JDK default
+ {@link java.net.ProxySelector} implementation.
+ This is the ProxySelector returned by {@link java.net.ProxySelector#getDefault()}
+ when no default ProxySelector was installed by
+ {@link java.net.ProxySelector#setDefault(ProxySelector)}
+
HTTP
-
The following proxy settings are used by the HTTP protocol handler.
+
The following properties are used to configure the proxy
+ that is {@linkplain java.net.ProxySelector#select(URI) selected}
+ for URIs with the {@code http://} scheme.
{@systemProperty http.proxyHost} (default: <none>)
The hostname, or address, of the proxy server.
@@ -86,26 +94,29 @@
Proxies
The value of this property is a list of hosts,
separated by the '|' character. In addition, the wildcard
character '*' can be used for pattern matching. For example,
- {@code -Dhttp.nonProxyHosts="*.foo.com|localhost"}
- will indicate that every host in the foo.com domain and the
- localhost should be accessed directly even if a proxy server is
+ {@code -Dhttp.nonProxyHosts="*.example.com|localhost"}
+ will indicate that every host in the example.com domain (including sub-domains)
+ and the localhost should be accessed directly even if a proxy server is
specified.
The default value excludes all common variations of the loopback address.
-
HTTPS This is HTTP over SSL, a secure version of HTTP
- mainly used when confidentiality (like on payment sites) is needed.
-
The following proxy settings are used by the HTTPS protocol handler.
+
HTTPS
+
The following properties are used to configure the proxy
+ that is {@linkplain java.net.ProxySelector#select(URI) selected}
+ for URIs with the {@code https://} scheme.
{@systemProperty https.proxyHost} (default: <none>)
The hostname, or address, of the proxy server.
{@systemProperty https.proxyPort} (default: {@code 443})
The port number of the proxy server.
-
The HTTPS protocol handler will use the same nonProxyHosts
+
The HTTPS protocol uses the same nonProxyHosts
property as the HTTP protocol.
FTP
-
The following proxy settings are used by the FTP protocol handler.
+
The following properties are used to configure the proxy
+ that is {@linkplain java.net.ProxySelector#select(URI) selected}
+ for URIs with the {@code ftp://} scheme.
{@systemProperty ftp.proxyHost} (default: <none>)
The hostname, or address, of the proxy server.
@@ -118,37 +129,38 @@
Proxies
The value of this property is a list of hosts, separated by
the '|' character. In addition, the wildcard character
'*' can be used for pattern matching. For example,
- {@code -Dhttp.nonProxyHosts="*.foo.com|localhost"}
- will indicate that every host in the foo.com domain and the
- localhost should be accessed directly even if a proxy server is
+ {@code -Dftp.nonProxyHosts="*.example.com|localhost"}
+ will indicate that every host in the example.com domain (including sub-domains)
+ and the localhost should be accessed directly even if a proxy server is
specified.
The default value excludes all common variations of the loopback address.
-
SOCKS This is another type of proxy. It allows for lower-level
- type of tunneling since it works at the TCP level. In effect,
- in the Java(tm) platform setting a SOCKS proxy server will result in
- all TCP connections to go through that proxy, unless other proxies
- are specified. If SOCKS is supported by a Java SE implementation, the
- following properties will be used:
+
SOCKS
+
This is a lower-level proxy that is
+ {@linkplain java.net.ProxySelector#select(URI) selected}
+ for all of the above URI schemes unless a scheme-specific proxy
+ is configured. It is also selected for the {@code socket://} URI scheme.
{@systemProperty socksProxyHost} (default: <none>)
The hostname, or address, of the proxy server.
{@systemProperty socksProxyPort} (default: {@code 1080})
The port number of the proxy server.
{@systemProperty socksNonProxyHosts} (default: {@code localhost|127.*|[::1]})
+ Indicates the hosts that should be accessed without going
+ through the proxy. Typically this defines internal hosts.
+ The value of this property is a list of hosts, separated by
+ the '|' character. In addition, the wildcard character
+ '*' can be used for pattern matching. For example,
+ {@code -DsocksNonProxyHosts="*.example.com|localhost"}
+ will indicate that every host in the example.com domain (including sub-domains)
+ and the localhost should be accessed directly even if a proxy server is
+ specified.
+
The default value excludes all common variations of the loopback address.
+
{@systemProperty socksProxyVersion} (default: {@code 5})
The version of the SOCKS protocol supported by the server. The
default is {@code 5} indicating SOCKS V5. Alternatively,
{@code 4} can be specified for SOCKS V4. Setting the property
to values other than these leads to unspecified behavior.
-
{@systemProperty java.net.socks.username} (default: <none>)
- Username to use if the SOCKSv5 server asks for authentication
- and no {@link java.net.Authenticator java.net.Authenticator} instance was found.
-
{@systemProperty java.net.socks.password} (default: <none>)
- Password to use if the SOCKSv5 server asks for authentication
- and no {@code java.net.Authenticator} instance was found.
-
Note that if no authentication is provided with either the above
- properties or an Authenticator, and the proxy requires one, then
- the user.name property will be used with no password.
{@systemProperty java.net.useSystemProxies} (default: {@code false})
On Windows systems, macOS systems, and Gnome systems it is possible to
@@ -192,20 +204,13 @@
These 3 properties modify the behavior of the HTTP digest
+
These properties modify the behavior of the HTTP digest
authentication mechanism. Digest authentication provides a limited
ability for the server to authenticate itself to the client (i.e.
By proving it knows the user's password). However, not all HTTP
servers support this capability and by default it is turned off. The
- first two properties can be set to true to enforce this check for
+ properties can be set to true to enforce this check for
authentication with either an origin or proxy server, respectively.
-
It is usually not necessary to change the third property. It
- determines how many times a cnonce value is re-used. This can be
- useful when the MD5-sess algorithm is being used. Increasing this
- value reduces the computational overhead on both client and server
- by reducing the amount of material that has to be hashed for each
- HTTP request.
{@systemProperty http.auth.ntlm.domain} (default: <none>)
NTLM is another authentication scheme. It uses the
{@code java.net.Authenticator} class to acquire usernames and passwords when
diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java
index ef6f0796363..c235cf5b790 100644
--- a/src/java.base/share/classes/java/text/DecimalFormat.java
+++ b/src/java.base/share/classes/java/text/DecimalFormat.java
@@ -3283,68 +3283,88 @@ private void appendAffix(StringBuilder buffer, String affix, boolean localized)
}
/**
- * Does the real work of generating a pattern. */
+ * Implementation of producing a pattern. This method returns a positive and
+ * negative (if needed), pattern string in the form of : Prefix (optional)
+ * Number Suffix (optional). A NegativePattern is only produced if the
+ * prefix or suffix patterns differs.
+ */
private String toPattern(boolean localized) {
+ // Determine symbol values; use DFS if localized
+ char zeroSymbol = localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT;
+ char digitSymbol = localized ? symbols.getDigit() : PATTERN_DIGIT;
+ char groupingSymbol = localized ?
+ (isCurrencyFormat ? symbols.getMonetaryGroupingSeparator() : symbols.getGroupingSeparator()) :
+ PATTERN_GROUPING_SEPARATOR;
+ char decimalSymbol = localized ?
+ (isCurrencyFormat ? symbols.getMonetaryDecimalSeparator() : symbols.getDecimalSeparator()) :
+ PATTERN_DECIMAL_SEPARATOR;
+ String exponentSymbol = localized ? symbols.getExponentSeparator() : PATTERN_EXPONENT;
+ char patternSeparator = localized ? symbols.getPatternSeparator() : PATTERN_SEPARATOR;
+
StringBuilder result = new StringBuilder();
+ // j == 1 denotes PositivePattern, j == 0 denotes NegativePattern
for (int j = 1; j >= 0; --j) {
- if (j == 1)
+ if (j == 1) {
+ // Append positive and negative (if needed) prefix pattern
appendAffix(result, posPrefixPattern, positivePrefix, localized);
- else appendAffix(result, negPrefixPattern, negativePrefix, localized);
- int i;
- int digitCount = useExponentialNotation
- ? getMaximumIntegerDigits()
- : Math.max(groupingSize, getMinimumIntegerDigits())+1;
- for (i = digitCount; i > 0; --i) {
+ } else {
+ appendAffix(result, negPrefixPattern, negativePrefix, localized);
+ }
+ // Append integer digits
+ int digitCount = useExponentialNotation ? getMaximumIntegerDigits() :
+ Math.max(groupingSize, getMinimumIntegerDigits()) + 1;
+ for (int i = digitCount; i > 0; --i) {
if (i != digitCount && isGroupingUsed() && groupingSize != 0 &&
- i % groupingSize == 0) {
- result.append(localized ?
- (isCurrencyFormat ? symbols.getMonetaryGroupingSeparator() : symbols.getGroupingSeparator()) :
- PATTERN_GROUPING_SEPARATOR);
+ i % groupingSize == 0) {
+ result.append(groupingSymbol);
}
- result.append(i <= getMinimumIntegerDigits()
- ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT)
- : (localized ? symbols.getDigit() : PATTERN_DIGIT));
+ result.append(i <= getMinimumIntegerDigits() ? zeroSymbol : digitSymbol);
}
- if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
- result.append(localized ?
- (isCurrencyFormat ? symbols.getMonetaryDecimalSeparator() : symbols.getDecimalSeparator()) :
- PATTERN_DECIMAL_SEPARATOR);
- for (i = 0; i < getMaximumFractionDigits(); ++i) {
- if (i < getMinimumFractionDigits()) {
- result.append(localized ? symbols.getZeroDigit() :
- PATTERN_ZERO_DIGIT);
- } else {
- result.append(localized ? symbols.getDigit() :
- PATTERN_DIGIT);
- }
+ // Append decimal symbol
+ if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown) {
+ result.append(decimalSymbol);
+ }
+ // Append fraction digits
+ result.repeat(zeroSymbol, getMinimumFractionDigits());
+ result.repeat(digitSymbol, getMaximumFractionDigits() - getMinimumFractionDigits());
+ // Append exponent symbol and digits
+ if (useExponentialNotation) {
+ result.append(exponentSymbol);
+ result.repeat(zeroSymbol, minExponentDigits);
}
- if (useExponentialNotation)
- {
- result.append(localized ? symbols.getExponentSeparator() :
- PATTERN_EXPONENT);
- for (i=0; i
+ * {@code GregorianCalendar}. In leap years, the adjustment accounts
+ * for the leap day in February to ensure the day of month is valid
+ * for the year.
*
*
{@code roll(f, delta)} adds
* {@code delta} to field {@code f} without changing larger
diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java
index 4cdafb0a44f..98e3cd2917b 100644
--- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java
+++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java
@@ -1140,9 +1140,12 @@ public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
boolean isCommon = (pool.workerNamePrefix == null);
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
- if (sm == null)
- return new ForkJoinWorkerThread(null, pool, true, false);
- else if (isCommon)
+ if (sm == null) {
+ if (isCommon)
+ return new ForkJoinWorkerThread.InnocuousForkJoinWorkerThread(pool);
+ else
+ return new ForkJoinWorkerThread(null, pool, true, false);
+ } else if (isCommon)
return newCommonWithACC(pool);
else
return newRegularWithACC(pool);
diff --git a/src/java.base/share/classes/java/util/spi/LocaleServiceProvider.java b/src/java.base/share/classes/java/util/spi/LocaleServiceProvider.java
index 996ef705269..86aa580b619 100644
--- a/src/java.base/share/classes/java/util/spi/LocaleServiceProvider.java
+++ b/src/java.base/share/classes/java/util/spi/LocaleServiceProvider.java
@@ -32,9 +32,10 @@
* This is the super class of all the locale sensitive service provider
* interfaces (SPIs).
*
- * Locale sensitive service provider interfaces are interfaces that
+ * Locale sensitive service provider interfaces are interfaces that
* correspond to locale sensitive classes in the {@code java.text}
- * and {@code java.util} packages. The interfaces enable the
+ * and {@code java.util} packages in order to provide the locale
+ * data used for each service. The interfaces enable the
* construction of locale sensitive objects and the retrieval of
* localized names for these packages. Locale sensitive factory methods
* and methods for name retrieval in the {@code java.text} and
@@ -121,13 +122,13 @@
* {@link System#setProperty(String, String)} is discouraged and it may not affect
* the order.
* JDK Reference Implementation provides the following three
- * locale providers:
+ * locale data providers:
*
- *
"CLDR": A provider based on Unicode Consortium's
- * CLDR Project.
+ *
"SPI": represents the locale sensitive services implementing the subclasses of
* this {@code LocaleServiceProvider} class.
- *
"HOST": A provider that reflects the user's custom settings in the
+ *
"HOST": A locale data provider that reflects the user's custom settings in the
* underlying operating system. This provider may not be available, depending
* on the JDK Reference Implementation.
*
@@ -139,11 +140,58 @@
* the locale sensitive services in the SPI providers are looked up first. If the
* desired locale sensitive service is not available, then the runtime looks for CLDR.
*
- * The default value for looking up the preferred locale providers is "CLDR",
- * so specifying "CLDR" is identical to the default behavior. Applications which
+ * The default value for looking up the preferred locale data providers is "CLDR",
+ * so specifying only "CLDR" is identical to the default behavior. Applications which
* require implementations of the locale sensitive services must explicitly specify
* "SPI" in order for the Java runtime to load them from the classpath.
*
+ * @implNote The JDK uses locale data from the Unicode Consortium's
+ * Common Locale Data Repository (CLDR)
+ * to implement locale-sensitive APIs in the {@code java.util} and
+ * {@code java.text} packages. This locale data derives the set of locales
+ * supported by the Java runtime environment. The following table lists the
+ * version of CLDR used in each JDK release. Unless otherwise specified, all
+ * update releases in a given JDK release family use the same CLDR version.
+ *
+ *
JDK releases and supported CLDR versions
+ *
+ *
JDK release
+ *
CLDR version
+ *
+ *
+ *
JDK 22
+ *
CLDR 44
+ *
JDK 21
+ *
CLDR 43
+ *
JDK 20
+ *
CLDR 42
+ *
JDK 19
+ *
CLDR 41
+ *
JDK 18
+ *
CLDR 39
+ *
JDK 17
+ *
CLDR 39
+ *
JDK 16
+ *
CLDR 38
+ *
JDK 15
+ *
CLDR 37
+ *
JDK 14
+ *
CLDR 36
+ *
JDK 13
+ *
CLDR 35.1
+ *
JDK 12
+ *
CLDR 33
+ *
JDK 11
+ *
CLDR 33
+ *
JDK 10
+ *
CLDR 29
+ *
JDK 9
+ *
CLDR 29
+ *
JDK 8
+ *
CLDR 21.0.1
+ *
+ *
+ *
* @since 1.6
*/
public abstract class LocaleServiceProvider {
diff --git a/src/java.base/share/classes/java/util/zip/Deflater.java b/src/java.base/share/classes/java/util/zip/Deflater.java
index 6d00a45742b..ca123bd36da 100644
--- a/src/java.base/share/classes/java/util/zip/Deflater.java
+++ b/src/java.base/share/classes/java/util/zip/Deflater.java
@@ -822,12 +822,16 @@ public int getAdler() {
/**
* Returns the total number of uncompressed bytes input so far.
*
- *
Since the number of bytes may be greater than
- * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
- * the preferred means of obtaining this information.
+ * @implSpec
+ * This method returns the equivalent of {@code (int) getBytesRead()}
+ * and therefore cannot return the correct value when it is greater
+ * than {@link Integer#MAX_VALUE}.
+ *
+ * @deprecated Use {@link #getBytesRead()} instead
*
* @return the total number of uncompressed bytes input so far
*/
+ @Deprecated(since = "23")
public int getTotalIn() {
return (int) getBytesRead();
}
@@ -848,12 +852,16 @@ public long getBytesRead() {
/**
* Returns the total number of compressed bytes output so far.
*
- *
Since the number of bytes may be greater than
- * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
- * the preferred means of obtaining this information.
+ * @implSpec
+ * This method returns the equivalent of {@code (int) getBytesWritten()}
+ * and therefore cannot return the correct value when it is greater
+ * than {@link Integer#MAX_VALUE}.
+ *
+ * @deprecated Use {@link #getBytesWritten()} instead
*
* @return the total number of compressed bytes output so far
*/
+ @Deprecated(since = "23")
public int getTotalOut() {
return (int) getBytesWritten();
}
diff --git a/src/java.base/share/classes/java/util/zip/Inflater.java b/src/java.base/share/classes/java/util/zip/Inflater.java
index 3c54efc2b2f..4b106fd39ec 100644
--- a/src/java.base/share/classes/java/util/zip/Inflater.java
+++ b/src/java.base/share/classes/java/util/zip/Inflater.java
@@ -643,12 +643,16 @@ public int getAdler() {
/**
* Returns the total number of compressed bytes input so far.
*
- *
Since the number of bytes may be greater than
- * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
- * the preferred means of obtaining this information.
+ * @implSpec
+ * This method returns the equivalent of {@code (int) getBytesRead()}
+ * and therefore cannot return the correct value when it is greater
+ * than {@link Integer#MAX_VALUE}.
+ *
+ * @deprecated Use {@link #getBytesRead()} instead
*
* @return the total number of compressed bytes input so far
*/
+ @Deprecated(since = "23")
public int getTotalIn() {
return (int) getBytesRead();
}
@@ -669,12 +673,16 @@ public long getBytesRead() {
/**
* Returns the total number of uncompressed bytes output so far.
*
- *
Since the number of bytes may be greater than
- * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
- * the preferred means of obtaining this information.
+ * @implSpec
+ * This method returns the equivalent of {@code (int) getBytesWritten()}
+ * and therefore cannot return the correct value when it is greater
+ * than {@link Integer#MAX_VALUE}.
+ *
+ * @deprecated Use {@link #getBytesWritten()} instead
*
* @return the total number of uncompressed bytes output so far
*/
+ @Deprecated(since = "23")
public int getTotalOut() {
return (int) getBytesWritten();
}
diff --git a/src/java.base/share/classes/javax/security/auth/x500/X500Principal.java b/src/java.base/share/classes/javax/security/auth/x500/X500Principal.java
index f58a37f0997..efc5b7891b8 100644
--- a/src/java.base/share/classes/javax/security/auth/x500/X500Principal.java
+++ b/src/java.base/share/classes/javax/security/auth/x500/X500Principal.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,8 @@
import java.security.Principal;
import java.util.Collections;
import java.util.Map;
+import jdk.internal.access.JavaxSecurityAccess;
+import jdk.internal.access.SharedSecrets;
import sun.security.x509.X500Name;
import sun.security.util.*;
@@ -82,16 +84,31 @@ public final class X500Principal implements Principal, java.io.Serializable {
/**
* The X500Name representing this principal.
*
- * NOTE: this field is reflectively accessed from within X500Name.
+ * NOTE: this field is accessed using shared secrets from within X500Name.
*/
private transient X500Name thisX500Name;
+ static {
+ // Set up JavaxSecurityAccess in SharedSecrets
+ SharedSecrets.setJavaxSecurityAccess(
+ new JavaxSecurityAccess() {
+ @Override
+ public X500Name asX500Name(X500Principal principal) {
+ return principal.thisX500Name;
+ }
+ @Override
+ public X500Principal asX500Principal(X500Name name) {
+ return new X500Principal(name);
+ }
+ });
+ }
+
/**
* Creates an X500Principal by wrapping an X500Name.
*
* NOTE: The constructor is package private. It is intended to be accessed
- * using privileged reflection from classes in sun.security.*.
- * Currently, it is referenced from sun.security.x509.X500Name.asX500Principal().
+ * using shared secrets from classes in sun.security.*. Currently, it is
+ * referenced from sun.security.x509.X500Name.asX500Principal().
*/
X500Principal(X500Name x500Name) {
thisX500Name = x500Name;
diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java
index 82197a97892..fe116d08835 100644
--- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java
+++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, 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
@@ -270,6 +270,12 @@ public interface JavaLangAccess {
*/
Module addEnableNativeAccess(Module m);
+ /**
+ * Updates module named {@code name} in layer {@code layer} to allow access to restricted methods.
+ * Returns true iff the given module exists in the given layer.
+ */
+ boolean addEnableNativeAccess(ModuleLayer layer, String name);
+
/**
* Updates all unnamed modules to allow access to restricted methods.
*/
diff --git a/src/java.base/share/classes/jdk/internal/access/JavaxSecurityAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaxSecurityAccess.java
new file mode 100644
index 00000000000..004b6db375b
--- /dev/null
+++ b/src/java.base/share/classes/jdk/internal/access/JavaxSecurityAccess.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2024, 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.
+ */
+
+package jdk.internal.access;
+
+import javax.security.auth.x500.X500Principal;
+import sun.security.x509.X500Name;
+
+public interface JavaxSecurityAccess {
+ X500Name asX500Name(X500Principal p);
+ X500Principal asX500Principal(X500Name n);
+}
diff --git a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java
index 919d758a6e3..eb0a7821d0d 100644
--- a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java
+++ b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,7 @@
import java.io.RandomAccessFile;
import java.security.ProtectionDomain;
import java.security.Signature;
+import javax.security.auth.x500.X500Principal;
/** A repository of "shared secrets", which are a mechanism for
calling implementation-private methods in another package without
@@ -89,6 +90,7 @@ public class SharedSecrets {
private static JavaSecuritySpecAccess javaSecuritySpecAccess;
private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess;
private static JavaxCryptoSpecAccess javaxCryptoSpecAccess;
+ private static JavaxSecurityAccess javaxSecurityAccess;
private static JavaTemplateAccess javaTemplateAccess;
public static void setJavaUtilCollectionAccess(JavaUtilCollectionAccess juca) {
@@ -517,6 +519,19 @@ public static JavaxCryptoSealedObjectAccess getJavaxCryptoSealedObjectAccess() {
return access;
}
+ public static void setJavaxSecurityAccess(JavaxSecurityAccess jsa) {
+ javaxSecurityAccess = jsa;
+ }
+
+ public static JavaxSecurityAccess getJavaxSecurityAccess() {
+ var access = javaxSecurityAccess;
+ if (access == null) {
+ ensureClassInitialized(X500Principal.class);
+ access = javaxSecurityAccess;
+ }
+ return access;
+ }
+
public static void setJavaTemplateAccess(JavaTemplateAccess jta) {
javaTemplateAccess = jta;
}
diff --git a/src/java.base/share/classes/jdk/internal/misc/CDS.java b/src/java.base/share/classes/jdk/internal/misc/CDS.java
index e3365441548..ddb25cb7904 100644
--- a/src/java.base/share/classes/jdk/internal/misc/CDS.java
+++ b/src/java.base/share/classes/jdk/internal/misc/CDS.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2024, 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
@@ -41,48 +41,42 @@
import jdk.internal.access.SharedSecrets;
public class CDS {
- private static final boolean isDumpingClassList;
- private static final boolean isDumpingArchive;
- private static final boolean isSharingEnabled;
- private static final boolean isDumpingStaticArchive;
- static {
- isDumpingClassList = isDumpingClassList0();
- isDumpingArchive = isDumpingArchive0();
- isSharingEnabled = isSharingEnabled0();
- isDumpingStaticArchive = isDumpingArchive && !isSharingEnabled;
- }
+ // Must be in sync with cdsConfig.hpp
+ private static final int IS_DUMPING_ARCHIVE = 1 << 0;
+ private static final int IS_DUMPING_STATIC_ARCHIVE = 1 << 1;
+ private static final int IS_LOGGING_LAMBDA_FORM_INVOKERS = 1 << 2;
+ private static final int IS_USING_ARCHIVE = 1 << 3;
+ private static final int configStatus = getCDSConfigStatus();
/**
- * indicator for dumping class list.
- */
- public static boolean isDumpingClassList() {
- return isDumpingClassList;
+ * Should we log the use of lambda form invokers?
+ */
+ public static boolean isLoggingLambdaFormInvokers() {
+ return (configStatus & IS_LOGGING_LAMBDA_FORM_INVOKERS) != 0;
}
/**
* Is the VM writing to a (static or dynamic) CDS archive.
*/
public static boolean isDumpingArchive() {
- return isDumpingArchive;
+ return (configStatus & IS_DUMPING_ARCHIVE) != 0;
}
/**
- * Is sharing enabled.
+ * Is the VM using at least one CDS archive?
*/
- public static boolean isSharingEnabled() {
- return isSharingEnabled;
+ public static boolean isUsingArchive() {
+ return (configStatus & IS_USING_ARCHIVE) != 0;
}
/**
* Is dumping static archive.
*/
public static boolean isDumpingStaticArchive() {
- return isDumpingStaticArchive;
+ return (configStatus & IS_DUMPING_STATIC_ARCHIVE) != 0;
}
- private static native boolean isDumpingClassList0();
- private static native boolean isDumpingArchive0();
- private static native boolean isSharingEnabled0();
+ private static native int getCDSConfigStatus();
private static native void logLambdaFormInvoker(String line);
/**
@@ -112,8 +106,8 @@ public static boolean isDumpingStaticArchive() {
/**
* log lambda form invoker holder, name and method type
*/
- public static void traceLambdaFormInvoker(String prefix, String holder, String name, String type) {
- if (isDumpingClassList) {
+ public static void logLambdaFormInvoker(String prefix, String holder, String name, String type) {
+ if (isLoggingLambdaFormInvokers()) {
logLambdaFormInvoker(prefix + " " + holder + " " + name + " " + type);
}
}
@@ -121,8 +115,8 @@ public static void traceLambdaFormInvoker(String prefix, String holder, String n
/**
* log species
*/
- public static void traceSpeciesType(String prefix, String cn) {
- if (isDumpingClassList) {
+ public static void logSpeciesType(String prefix, String cn) {
+ if (isLoggingLambdaFormInvokers()) {
logLambdaFormInvoker(prefix + " " + cn);
}
}
diff --git a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
index e6df0c9ade7..e0aa37b526a 100644
--- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
+++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
@@ -4237,91 +4237,4 @@ public void invokeCleaner(java.nio.ByteBuffer directBuffer) {
cleaner.clean();
}
}
-
- // The following deprecated methods are used by JSR 166.
-
- @Deprecated(since="12", forRemoval=true)
- public final Object getObject(Object o, long offset) {
- return getReference(o, offset);
- }
- @Deprecated(since="12", forRemoval=true)
- public final Object getObjectVolatile(Object o, long offset) {
- return getReferenceVolatile(o, offset);
- }
- @Deprecated(since="12", forRemoval=true)
- public final Object getObjectAcquire(Object o, long offset) {
- return getReferenceAcquire(o, offset);
- }
- @Deprecated(since="12", forRemoval=true)
- public final Object getObjectOpaque(Object o, long offset) {
- return getReferenceOpaque(o, offset);
- }
-
-
- @Deprecated(since="12", forRemoval=true)
- public final void putObject(Object o, long offset, Object x) {
- putReference(o, offset, x);
- }
- @Deprecated(since="12", forRemoval=true)
- public final void putObjectVolatile(Object o, long offset, Object x) {
- putReferenceVolatile(o, offset, x);
- }
- @Deprecated(since="12", forRemoval=true)
- public final void putObjectOpaque(Object o, long offset, Object x) {
- putReferenceOpaque(o, offset, x);
- }
- @Deprecated(since="12", forRemoval=true)
- public final void putObjectRelease(Object o, long offset, Object x) {
- putReferenceRelease(o, offset, x);
- }
-
-
- @Deprecated(since="12", forRemoval=true)
- public final Object getAndSetObject(Object o, long offset, Object newValue) {
- return getAndSetReference(o, offset, newValue);
- }
- @Deprecated(since="12", forRemoval=true)
- public final Object getAndSetObjectAcquire(Object o, long offset, Object newValue) {
- return getAndSetReferenceAcquire(o, offset, newValue);
- }
- @Deprecated(since="12", forRemoval=true)
- public final Object getAndSetObjectRelease(Object o, long offset, Object newValue) {
- return getAndSetReferenceRelease(o, offset, newValue);
- }
-
-
- @Deprecated(since="12", forRemoval=true)
- public final boolean compareAndSetObject(Object o, long offset, Object expected, Object x) {
- return compareAndSetReference(o, offset, expected, x);
- }
- @Deprecated(since="12", forRemoval=true)
- public final Object compareAndExchangeObject(Object o, long offset, Object expected, Object x) {
- return compareAndExchangeReference(o, offset, expected, x);
- }
- @Deprecated(since="12", forRemoval=true)
- public final Object compareAndExchangeObjectAcquire(Object o, long offset, Object expected, Object x) {
- return compareAndExchangeReferenceAcquire(o, offset, expected, x);
- }
- @Deprecated(since="12", forRemoval=true)
- public final Object compareAndExchangeObjectRelease(Object o, long offset, Object expected, Object x) {
- return compareAndExchangeReferenceRelease(o, offset, expected, x);
- }
-
-
- @Deprecated(since="12", forRemoval=true)
- public final boolean weakCompareAndSetObject(Object o, long offset, Object expected, Object x) {
- return weakCompareAndSetReference(o, offset, expected, x);
- }
- @Deprecated(since="12", forRemoval=true)
- public final boolean weakCompareAndSetObjectAcquire(Object o, long offset, Object expected, Object x) {
- return weakCompareAndSetReferenceAcquire(o, offset, expected, x);
- }
- @Deprecated(since="12", forRemoval=true)
- public final boolean weakCompareAndSetObjectPlain(Object o, long offset, Object expected, Object x) {
- return weakCompareAndSetReferencePlain(o, offset, expected, x);
- }
- @Deprecated(since="12", forRemoval=true)
- public final boolean weakCompareAndSetObjectRelease(Object o, long offset, Object expected, Object x) {
- return weakCompareAndSetReferenceRelease(o, offset, expected, x);
- }
}
diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
index 0279c8438a0..b97b0a2de40 100644
--- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2024, 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
@@ -788,31 +788,38 @@ private static void addExtraExportsOrOpens(ModuleLayer bootLayer,
}
private static final boolean HAS_ENABLE_NATIVE_ACCESS_FLAG;
- private static final Set NATIVE_ACCESS_MODULES;
+ private static final Set USER_NATIVE_ACCESS_MODULES;
+ private static final Set JDK_NATIVE_ACCESS_MODULES;
public static boolean hasEnableNativeAccessFlag() {
return HAS_ENABLE_NATIVE_ACCESS_FLAG;
}
static {
- NATIVE_ACCESS_MODULES = decodeEnableNativeAccess();
- HAS_ENABLE_NATIVE_ACCESS_FLAG = !NATIVE_ACCESS_MODULES.isEmpty();
+ USER_NATIVE_ACCESS_MODULES = decodeEnableNativeAccess();
+ HAS_ENABLE_NATIVE_ACCESS_FLAG = !USER_NATIVE_ACCESS_MODULES.isEmpty();
+ JDK_NATIVE_ACCESS_MODULES = ModuleLoaderMap.nativeAccessModules();
}
/**
- * Process the --enable-native-access option to grant access to restricted methods to selected modules.
+ * Grants native access to modules selected using the --enable-native-access
+ * command line option, and also to JDK modules that need the access.
*/
private static void addEnableNativeAccess(ModuleLayer layer) {
- for (String name : NATIVE_ACCESS_MODULES) {
+ addEnableNativeAccess(layer, USER_NATIVE_ACCESS_MODULES, true);
+ addEnableNativeAccess(layer, JDK_NATIVE_ACCESS_MODULES, false);
+ }
+
+ /**
+ * Grants native access for the given modules in the given layer.
+ * Warns optionally about modules that were specified, but not present in the layer.
+ */
+ private static void addEnableNativeAccess(ModuleLayer layer, Set moduleNames, boolean shouldWarn) {
+ for (String name : moduleNames) {
if (name.equals("ALL-UNNAMED")) {
JLA.addEnableNativeAccessToAllUnnamed();
- } else {
- Optional module = layer.findModule(name);
- if (module.isPresent()) {
- JLA.addEnableNativeAccess(module.get());
- } else {
- warnUnknownModule(ENABLE_NATIVE_ACCESS, name);
- }
+ } else if (!JLA.addEnableNativeAccess(layer, name) && shouldWarn) {
+ warnUnknownModule(ENABLE_NATIVE_ACCESS, name);
}
}
}
diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java b/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java
index a23a72dacec..a8b5eda709e 100644
--- a/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024, 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
@@ -110,6 +110,13 @@ public static Set platformModules() {
return Modules.platformModules;
}
+ /**
+ * Returns the names of the modules defined to the application loader which perform native access.
+ */
+ public static Set nativeAccessModules() {
+ return Modules.nativeAccessModules;
+ }
+
private static class Modules {
// list of boot modules is generated at build time.
private static final Set bootModules =
@@ -118,6 +125,10 @@ private static class Modules {
// list of platform modules is generated at build time.
private static final Set platformModules =
Set.of(new String[] { "@@PLATFORM_MODULE_NAMES@@" });
+
+ // list of jdk modules is generated at build time.
+ private static final Set nativeAccessModules =
+ Set.of(new String[] { "@@NATIVE_ACCESS_MODULE_NAMES@@" });
}
/**
diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/HttpAuthenticator.java b/src/java.base/share/classes/sun/net/www/protocol/http/HttpAuthenticator.java
deleted file mode 100644
index 4befe58b5b9..00000000000
--- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpAuthenticator.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 1996, 2004, 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.
- */
-
-package sun.net.www.protocol.http;
-
-import java.net.URL;
-
-/**
- * An interface for all objects that implement HTTP authentication.
- * See the HTTP spec for details on how this works in general.
- * A single class or object can implement an arbitrary number of
- * authentication schemes.
- *
- * @author David Brown
- *
- * @deprecated -- use java.net.Authenticator instead
- * @see java.net.Authenticator
- */
-//
-// REMIND: Unless compatibility with sun.* API's from 1.2 to 2.0 is
-// a goal, there's no reason to carry this forward into JDK 2.0.
-@Deprecated
-public interface HttpAuthenticator {
-
-
- /**
- * Indicate whether the specified authentication scheme is
- * supported. In accordance with HTTP specifications, the
- * scheme name should be checked in a case-insensitive fashion.
- */
-
- boolean schemeSupported (String scheme);
-
- /**
- * Returns the String that should be included in the HTTP
- * Authorization field. Return null if no info was
- * supplied or could be found.
- *
- */
-
- public String authString (URL u, String scheme, String realm);
-
-}
diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
index 644801adb77..f47261f4491 100644
--- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
+++ b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2024, 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
@@ -335,13 +335,6 @@ private static Set schemesListToSet(String list) {
private String userCookies = null;
private String userCookies2 = null;
- /* We only have a single static authenticator for now.
- * REMIND: backwards compatibility with JDK 1.1. Should be
- * eliminated for JDK 2.0.
- */
- @Deprecated
- private static HttpAuthenticator defaultAuth;
-
/* all the headers we send
* NOTE: do *NOT* dump out the content of 'requests' in the
* output or stacktrace since it may contain security-sensitive
@@ -945,14 +938,6 @@ public ResponseCache run() {
});
}
- /**
- * @deprecated. Use java.net.Authenticator.setDefault() instead.
- */
- @Deprecated
- public static void setDefaultAuthenticator(HttpAuthenticator a) {
- defaultAuth = a;
- }
-
/**
* opens a stream allowing redirects only to the same host.
*/
@@ -2524,22 +2509,6 @@ public InetAddress run()
throw new AssertionError("should not reach here");
}
}
- // For backwards compatibility, we also try defaultAuth
- // REMIND: Get rid of this for JDK2.0.
-
- if (ret == null && defaultAuth != null
- && defaultAuth.schemeSupported(scheme)) {
- try {
- @SuppressWarnings("deprecation")
- URL u = new URL("http", host, port, "/");
- String a = defaultAuth.authString(u, scheme, realm);
- if (a != null) {
- ret = new BasicAuthentication (true, host, port, realm, a);
- // not in cache by default - cache on success
- }
- } catch (java.net.MalformedURLException ignored) {
- }
- }
if (ret != null) {
if (!ret.setHeaders(this, p, raw)) {
ret.disposeContext();
@@ -2697,19 +2666,6 @@ private AuthenticationInfo getServerAuthentication(AuthenticationHeader authhdr)
throw new AssertionError("should not reach here");
}
}
-
- // For backwards compatibility, we also try defaultAuth
- // REMIND: Get rid of this for JDK2.0.
-
- if (ret == null && defaultAuth != null
- && defaultAuth.schemeSupported(scheme)) {
- String a = defaultAuth.authString(url, scheme, realm);
- if (a != null) {
- ret = new BasicAuthentication (false, url, realm, a);
- // not in cache by default - cache on success
- }
- }
-
if (ret != null ) {
if (!ret.setHeaders(this, p, raw)) {
ret.disposeContext();
diff --git a/src/java.base/share/classes/sun/security/ec/ECKeyPairGenerator.java b/src/java.base/share/classes/sun/security/ec/ECKeyPairGenerator.java
index 69c57b95bc4..155691d2fda 100644
--- a/src/java.base/share/classes/sun/security/ec/ECKeyPairGenerator.java
+++ b/src/java.base/share/classes/sun/security/ec/ECKeyPairGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,6 @@
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
-import java.security.spec.ECPoint;
import java.security.spec.InvalidParameterSpecException;
import java.util.Arrays;
import java.util.Optional;
@@ -37,7 +36,7 @@
import sun.security.jca.JCAUtil;
import sun.security.util.ECUtil;
import sun.security.util.math.*;
-import sun.security.ec.point.*;
+
import static sun.security.util.SecurityProviderConstants.DEF_EC_KEY_SIZE;
import static sun.security.ec.ECOperations.IntermediateValueException;
@@ -74,7 +73,7 @@ public ECKeyPairGenerator() {
public void initialize(int keySize, SecureRandom random) {
checkKeySize(keySize);
- this.params = ECUtil.getECParameterSpec(null, keySize);
+ this.params = ECUtil.getECParameterSpec(keySize);
if (params == null) {
throw new InvalidParameterException(
"No EC parameters available for key size " + keySize + " bits");
@@ -91,14 +90,14 @@ public void initialize(AlgorithmParameterSpec params, SecureRandom random)
if (params instanceof ECParameterSpec) {
ECParameterSpec ecParams = (ECParameterSpec) params;
- ecSpec = ECUtil.getECParameterSpec(null, ecParams);
+ ecSpec = ECUtil.getECParameterSpec(ecParams);
if (ecSpec == null) {
throw new InvalidAlgorithmParameterException(
"Curve not supported: " + params);
}
} else if (params instanceof ECGenParameterSpec) {
String name = ((ECGenParameterSpec) params).getName();
- ecSpec = ECUtil.getECParameterSpec(null, name);
+ ecSpec = ECUtil.getECParameterSpec(name);
if (ecSpec == null) {
throw new InvalidAlgorithmParameterException(
"Unknown curve name: " + name);
@@ -120,7 +119,7 @@ private static void ensureCurveIsSupported(ECParameterSpec ecSpec)
throws InvalidAlgorithmParameterException {
// Check if ecSpec is a valid curve
- AlgorithmParameters ecParams = ECUtil.getECParameters(null);
+ AlgorithmParameters ecParams = ECUtil.getECParameters();
try {
ecParams.init(ecSpec);
} catch (InvalidParameterSpecException ex) {
diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
index 04e040b611b..52393f0466a 100644
--- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
+++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, 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
@@ -295,9 +295,13 @@ static S run(RetryWithZero f, char[] password) throws Exception {
* (e.g., the given password is wrong).
*/
public Key engineGetKey(String alias, char[] password)
- throws NoSuchAlgorithmException, UnrecoverableKeyException
- {
+ throws NoSuchAlgorithmException, UnrecoverableKeyException {
Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+ return internalGetKey(entry, password);
+ }
+
+ private Key internalGetKey(Entry entry, char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException {
Key key;
if (!(entry instanceof KeyEntry)) {
@@ -321,7 +325,7 @@ public Key engineGetKey(String alias, char[] password)
try {
// get the encrypted private key
EncryptedPrivateKeyInfo encrInfo =
- new EncryptedPrivateKeyInfo(encrBytes);
+ new EncryptedPrivateKeyInfo(encrBytes);
encryptedKey = encrInfo.getEncryptedData();
// parse Algorithm parameters
@@ -332,20 +336,20 @@ public Key engineGetKey(String alias, char[] password)
} catch (IOException ioe) {
UnrecoverableKeyException uke =
- new UnrecoverableKeyException("Private key not stored as "
- + "PKCS#8 EncryptedPrivateKeyInfo: " + ioe);
+ new UnrecoverableKeyException("Private key not stored as "
+ + "PKCS#8 EncryptedPrivateKeyInfo: " + ioe);
uke.initCause(ioe);
throw uke;
}
- try {
+ try {
PBEParameterSpec pbeSpec;
int ic;
if (algParams != null) {
try {
pbeSpec =
- algParams.getParameterSpec(PBEParameterSpec.class);
+ algParams.getParameterSpec(PBEParameterSpec.class);
} catch (InvalidParameterSpecException ipse) {
throw new IOException("Invalid PBE algorithm parameters");
}
@@ -392,7 +396,7 @@ public Key engineGetKey(String alias, char[] password)
if (debug != null) {
debug.println("Retrieved a protected private key at alias" +
- " '" + alias + "' (" +
+ " '" + entry.alias + "' (" +
aid.getName() +
" iterations: " + ic + ")");
}
@@ -433,7 +437,7 @@ public Key engineGetKey(String alias, char[] password)
if (debug != null) {
debug.println("Retrieved a protected secret key at alias " +
- "'" + alias + "' (" +
+ "'" + entry.alias + "' (" +
aid.getName() +
" iterations: " + ic + ")");
}
@@ -450,8 +454,8 @@ public Key engineGetKey(String alias, char[] password)
} catch (Exception e) {
UnrecoverableKeyException uke =
- new UnrecoverableKeyException("Get Key failed: " +
- e.getMessage());
+ new UnrecoverableKeyException("Get Key failed: " +
+ e.getMessage());
uke.initCause(e);
throw uke;
}
@@ -471,6 +475,10 @@ public Key engineGetKey(String alias, char[] password)
*/
public Certificate[] engineGetCertificateChain(String alias) {
Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+ return internalGetCertificateChain(entry);
+ }
+
+ private Certificate[] internalGetCertificateChain(Entry entry) {
if (entry instanceof PrivateKeyEntry privateKeyEntry) {
if (privateKeyEntry.chain == null) {
return null;
@@ -478,8 +486,8 @@ public Certificate[] engineGetCertificateChain(String alias) {
if (debug != null) {
debug.println("Retrieved a " +
- privateKeyEntry.chain.length +
- "-certificate chain at alias '" + alias + "'");
+ privateKeyEntry.chain.length +
+ "-certificate chain at alias '" + entry.alias + "'");
}
return privateKeyEntry.chain.clone();
@@ -1013,18 +1021,19 @@ public synchronized void engineDeleteEntry(String alias)
debug.println("Removing entry at alias '" + alias + "'");
}
- Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
- if (entry instanceof PrivateKeyEntry keyEntry) {
- if (keyEntry.chain != null) {
- certificateCount -= keyEntry.chain.length;
+ Entry entry = entries.remove(alias.toLowerCase(Locale.ENGLISH));
+ if (entry != null) {
+ if (entry instanceof PrivateKeyEntry keyEntry) {
+ if (keyEntry.chain != null) {
+ certificateCount -= keyEntry.chain.length;
+ }
+ privateKeyCount--;
+ } else if (entry instanceof CertEntry) {
+ certificateCount--;
+ } else if (entry instanceof SecretKeyEntry) {
+ secretKeyCount--;
}
- privateKeyCount--;
- } else if (entry instanceof CertEntry) {
- certificateCount--;
- } else if (entry instanceof SecretKeyEntry) {
- secretKeyCount--;
}
- entries.remove(alias.toLowerCase(Locale.ENGLISH));
}
/**
@@ -1065,6 +1074,10 @@ public int engineSize() {
*/
public boolean engineIsKeyEntry(String alias) {
Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+ return internalIsKeyEntry(entry);
+ }
+
+ private boolean internalIsKeyEntry(Entry entry) {
return entry instanceof KeyEntry;
}
@@ -1075,8 +1088,13 @@ public boolean engineIsKeyEntry(String alias) {
* @return true if the entry identified by the given alias is a
* trusted certificate entry, false otherwise.
*/
+
public boolean engineIsCertificateEntry(String alias) {
Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
+ return internalIsCertificateEntry(entry);
+ }
+
+ private boolean internalIsCertificateEntry(Entry entry) {
return entry instanceof CertEntry certEntry &&
certEntry.trustedKeyUsage != null;
}
@@ -1306,18 +1324,14 @@ public KeyStore.Entry engineGetEntry(String alias,
Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
if (protParam == null) {
- if (engineIsCertificateEntry(alias)) {
- if (entry instanceof CertEntry &&
- ((CertEntry) entry).trustedKeyUsage != null) {
-
- if (debug != null) {
- debug.println("Retrieved a trusted certificate at " +
+ if (internalIsCertificateEntry(entry)) {
+ if (debug != null) {
+ debug.println("Retrieved a trusted certificate at " +
"alias '" + alias + "'");
- }
+ }
- return new KeyStore.TrustedCertificateEntry(
+ return new KeyStore.TrustedCertificateEntry(
((CertEntry)entry).cert, entry.attributes);
- }
} else {
throw new UnrecoverableKeyException
("requested entry requires a password");
@@ -1325,17 +1339,17 @@ public KeyStore.Entry engineGetEntry(String alias,
}
if (protParam instanceof KeyStore.PasswordProtection) {
- if (engineIsCertificateEntry(alias)) {
+ if (internalIsCertificateEntry(entry)) {
throw new UnsupportedOperationException
("trusted certificate entries are not password-protected");
- } else if (engineIsKeyEntry(alias)) {
+ } else if (internalIsKeyEntry(entry)) {
KeyStore.PasswordProtection pp =
(KeyStore.PasswordProtection)protParam;
char[] password = pp.getPassword();
- Key key = engineGetKey(alias, password);
+ Key key = internalGetKey(entry, password);
if (key instanceof PrivateKey) {
- Certificate[] chain = engineGetCertificateChain(alias);
+ Certificate[] chain = internalGetCertificateChain(entry);
return new KeyStore.PrivateKeyEntry((PrivateKey)key, chain,
entry.attributes);
@@ -1345,7 +1359,7 @@ public KeyStore.Entry engineGetEntry(String alias,
return new KeyStore.SecretKeyEntry((SecretKey)key,
entry.attributes);
}
- } else if (!engineIsKeyEntry(alias)) {
+ } else {
throw new UnsupportedOperationException
("untrusted certificate entries are not " +
"password-protected");
diff --git a/src/java.base/share/classes/sun/security/provider/certpath/Builder.java b/src/java.base/share/classes/sun/security/provider/certpath/Builder.java
index 6860637bed8..71e8b615a36 100644
--- a/src/java.base/share/classes/sun/security/provider/certpath/Builder.java
+++ b/src/java.base/share/classes/sun/security/provider/certpath/Builder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, 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
@@ -33,13 +33,6 @@
import sun.security.action.GetBooleanAction;
import sun.security.provider.certpath.PKIX.BuilderParams;
import sun.security.util.Debug;
-import sun.security.x509.GeneralNames;
-import sun.security.x509.GeneralNameInterface;
-import sun.security.x509.GeneralSubtrees;
-import sun.security.x509.NameConstraintsExtension;
-import sun.security.x509.SubjectAlternativeNameExtension;
-import sun.security.x509.X500Name;
-import sun.security.x509.X509CertImpl;
/**
* Abstract class representing a builder, which is able to retrieve
@@ -126,246 +119,6 @@ abstract void addCertToPath(X509Certificate cert,
abstract void removeFinalCertFromPath
(LinkedList certPathList);
- /**
- * get distance of one GeneralName from another
- *
- * @param base GeneralName at base of subtree
- * @param test GeneralName to be tested against base
- * @param incomparable the value to return if the names are
- * incomparable
- * @return distance of test name from base, where 0
- * means exact match, 1 means test is an immediate
- * child of base, 2 means test is a grandchild, etc.
- * -1 means test is a parent of base, -2 means test
- * is a grandparent, etc.
- */
- static int distance(GeneralNameInterface base,
- GeneralNameInterface test, int incomparable)
- {
- switch (base.constrains(test)) {
- case GeneralNameInterface.NAME_DIFF_TYPE:
- if (debug != null) {
- debug.println("Builder.distance(): Names are different types");
- }
- return incomparable;
- case GeneralNameInterface.NAME_SAME_TYPE:
- if (debug != null) {
- debug.println("Builder.distance(): Names are same type but " +
- "in different subtrees");
- }
- return incomparable;
- case GeneralNameInterface.NAME_MATCH:
- return 0;
- case GeneralNameInterface.NAME_WIDENS:
- case GeneralNameInterface.NAME_NARROWS:
- break;
- default: // should never occur
- return incomparable;
- }
-
- /* names are in same subtree */
- return test.subtreeDepth() - base.subtreeDepth();
- }
-
- /**
- * get hop distance of one GeneralName from another in links where
- * the names need not have an ancestor/descendant relationship.
- * For example, the hop distance from ou=D,ou=C,o=B,c=US to
- * ou=F,ou=E,ou=C,o=B,c=US is 3: D->C, C->E, E->F. The hop distance
- * from ou=C,o=B,c=US to ou=D,ou=C,o=B,c=US is -1: C->D
- *
- * @param base GeneralName
- * @param test GeneralName to be tested against base
- * @param incomparable the value to return if the names are
- * incomparable
- * @return distance of test name from base measured in hops in the
- * namespace hierarchy, where 0 means exact match. Result
- * is positive if path is some number of up hops followed by
- * some number of down hops; result is negative if path is
- * some number of down hops.
- */
- static int hops(GeneralNameInterface base, GeneralNameInterface test,
- int incomparable)
- {
- int baseRtest = base.constrains(test);
- switch (baseRtest) {
- case GeneralNameInterface.NAME_DIFF_TYPE:
- if (debug != null) {
- debug.println("Builder.hops(): Names are different types");
- }
- return incomparable;
- case GeneralNameInterface.NAME_SAME_TYPE:
- /* base and test are in different subtrees */
- break;
- case GeneralNameInterface.NAME_MATCH:
- /* base matches test */
- return 0;
- case GeneralNameInterface.NAME_WIDENS:
- /* base is ancestor of test */
- case GeneralNameInterface.NAME_NARROWS:
- /* base is descendant of test */
- return test.subtreeDepth() - base.subtreeDepth();
- default: // should never occur
- return incomparable;
- }
-
- /* names are in different subtrees */
- if (base.getType() != GeneralNameInterface.NAME_DIRECTORY) {
- if (debug != null) {
- debug.println("Builder.hops(): hopDistance not implemented " +
- "for this name type");
- }
- return incomparable;
- }
- X500Name baseName = (X500Name)base;
- X500Name testName = (X500Name)test;
- X500Name commonName = baseName.commonAncestor(testName);
- if (commonName == null) {
- if (debug != null) {
- debug.println("Builder.hops(): Names are in different " +
- "namespaces");
- }
- return incomparable;
- } else {
- int commonDistance = commonName.subtreeDepth();
- int baseDistance = baseName.subtreeDepth();
- int testDistance = testName.subtreeDepth();
- return baseDistance + testDistance - (2 * commonDistance);
- }
- }
-
- /**
- * Determine how close a given certificate gets you toward
- * a given target.
- *
- * @param constraints Current NameConstraints; if null,
- * then caller must verify NameConstraints
- * independently, realizing that this certificate
- * may not actually lead to the target at all.
- * @param cert Candidate certificate for chain
- * @param target GeneralNameInterface name of target
- * @return distance from this certificate to target:
- *
- *
-1 means certificate could be CA for target, but
- * there are no NameConstraints limiting how close
- *
0 means certificate subject or subjectAltName
- * matches target
- *
1 means certificate is permitted to be CA for
- * target.
- *
2 means certificate is permitted to be CA for
- * parent of target.
- *
>0 in general, means certificate is permitted
- * to be a CA for this distance higher in the naming
- * hierarchy than the target, plus 1.
- *
- *
Note that the subject and/or subjectAltName of the
- * candidate cert does not have to be an ancestor of the
- * target in order to be a CA that can issue a certificate to
- * the target. In these cases, the target distance is calculated
- * by inspecting the NameConstraints extension in the candidate
- * certificate. For example, suppose the target is an X.500 DN with
- * a value of "CN=mullan,OU=ireland,O=sun,C=us" and the
- * NameConstraints extension in the candidate certificate
- * includes a permitted component of "O=sun,C=us", which implies
- * that the candidate certificate is allowed to issue certs in
- * the "O=sun,C=us" namespace. The target distance is 3
- * ((distance of permitted NC from target) + 1).
- * The (+1) is added to distinguish the result from the case
- * which returns (0).
- * @throws IOException if certificate does not get closer
- */
- static int targetDistance(NameConstraintsExtension constraints,
- X509Certificate cert, GeneralNameInterface target)
- throws IOException
- {
- /* ensure that certificate satisfies existing name constraints */
- if (constraints != null && !constraints.verify(cert)) {
- throw new IOException("certificate does not satisfy existing name "
- + "constraints");
- }
-
- X509CertImpl certImpl;
- try {
- certImpl = X509CertImpl.toImpl(cert);
- } catch (CertificateException e) {
- throw new IOException("Invalid certificate", e);
- }
- /* see if certificate subject matches target */
- X500Name subject = X500Name.asX500Name(certImpl.getSubjectX500Principal());
- if (subject.equals(target)) {
- /* match! */
- return 0;
- }
-
- SubjectAlternativeNameExtension altNameExt =
- certImpl.getSubjectAlternativeNameExtension();
- if (altNameExt != null) {
- GeneralNames altNames = altNameExt.getNames();
- /* see if any alternative name matches target */
- if (altNames != null) {
- for (int j = 0, n = altNames.size(); j < n; j++) {
- GeneralNameInterface altName = altNames.get(j).getName();
- if (altName.equals(target)) {
- return 0;
- }
- }
- }
- }
-
-
- /* no exact match; see if certificate can get us to target */
-
- /* first, get NameConstraints out of certificate */
- NameConstraintsExtension ncExt = certImpl.getNameConstraintsExtension();
- if (ncExt == null) {
- return -1;
- }
-
- /* merge certificate's NameConstraints with current NameConstraints */
- if (constraints != null) {
- constraints.merge(ncExt);
- } else {
- // Make sure we do a clone here, because we're probably
- // going to modify this object later, and we don't want to
- // be sharing it with a Certificate object!
- constraints = (NameConstraintsExtension) ncExt.clone();
- }
-
- if (debug != null) {
- debug.println("Builder.targetDistance() merged constraints: "
- + constraints);
- }
- /* reduce permitted by excluded */
- GeneralSubtrees permitted = constraints.getPermittedSubtrees();
- GeneralSubtrees excluded = constraints.getExcludedSubtrees();
- if (permitted != null) {
- permitted.reduce(excluded);
- }
- if (debug != null) {
- debug.println("Builder.targetDistance() reduced constraints: "
- + permitted);
- }
- /* see if new merged constraints allow target */
- if (!constraints.verify(target)) {
- throw new IOException("New certificate not allowed to sign "
- + "certificate for target");
- }
- /* find distance to target, if any, in permitted */
- if (permitted == null) {
- /* certificate is unconstrained; could sign for anything */
- return -1;
- }
- for (int i = 0, n = permitted.size(); i < n; i++) {
- GeneralNameInterface perName = permitted.get(i).getName().getName();
- int distance = distance(perName, target, -1);
- if (distance >= 0) {
- return distance + 1;
- }
- }
- /* no matching type in permitted; cert holder could certify target */
- return -1;
- }
-
/**
* This method can be used as an optimization to filter out
* certificates that do not have policies which are valid.
diff --git a/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java b/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java
index 52a073d3b78..7dc829788a5 100644
--- a/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java
+++ b/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,10 +44,13 @@
import jdk.internal.misc.ThreadTracker;
import sun.security.provider.certpath.PKIX.BuilderParams;
import sun.security.util.Debug;
+import sun.security.util.ObjectIdentifier;
import sun.security.x509.AccessDescription;
import sun.security.x509.AuthorityInfoAccessExtension;
import sun.security.x509.AuthorityKeyIdentifierExtension;
+import sun.security.x509.AVA;
import static sun.security.x509.PKIXExtensions.*;
+import sun.security.x509.RDN;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
@@ -60,7 +63,7 @@
* @author Yassir Elley
* @author Sean Mullan
*/
-final class ForwardBuilder extends Builder {
+public final class ForwardBuilder extends Builder {
private static final Debug debug = Debug.getInstance("certpath");
private final Set trustedCerts;
@@ -412,29 +415,15 @@ private boolean getCerts(AuthorityInfoAccessExtension aiaExt,
* 2) Issuer matches a trusted subject
* Issuer: ou=D,ou=C,o=B,c=A
*
- * 3) Issuer is a descendant of a trusted subject (in order of
- * number of links to the trusted subject)
- * a) Issuer: ou=E,ou=D,ou=C,o=B,c=A [links=1]
- * b) Issuer: ou=F,ou=E,ou=D,ou=C,ou=B,c=A [links=2]
- *
- * 4) Issuer is an ancestor of a trusted subject (in order of number of
- * links to the trusted subject)
- * a) Issuer: ou=C,o=B,c=A [links=1]
- * b) Issuer: o=B,c=A [links=2]
- *
- * 5) Issuer is in the same namespace as a trusted subject (in order of
- * number of links to the trusted subject)
+ * 3) Issuer is in the same namespace as a trusted subject (in order of
+ * number of links to the trusted subject). If the last RDN of the
+ * common ancestor is geographical, then it is skipped and the next
+ * trusted certificate is checked.
* a) Issuer: ou=G,ou=C,o=B,c=A [links=2]
* b) Issuer: ou=H,o=B,c=A [links=3]
+ * c) Issuer: ou=H,o=D,c=A [skipped, only geographical c=A is same]
*
- * 6) Issuer is an ancestor of certificate subject (in order of number
- * of links to the certificate subject)
- * a) Issuer: ou=K,o=J,c=A
- * Subject: ou=L,ou=K,o=J,c=A
- * b) Issuer: o=J,c=A
- * Subject: ou=L,ou=K,0=J,c=A
- *
- * 7) Any other certificates
+ * 4) Any other certificates
*/
static class PKIXCertComparator implements Comparator {
@@ -471,8 +460,8 @@ private X509CertSelector getSelector(X509CertImpl previousCert)
}
/**
- * @param oCert1 First X509Certificate to be compared
- * @param oCert2 Second X509Certificate to be compared
+ * @param oCert1 first X509Certificate to be compared
+ * @param oCert2 second X509Certificate to be compared
* @return -1 if oCert1 is preferable to oCert2, or
* if oCert1 and oCert2 are equally preferable (in this
* case it doesn't matter which is preferable, but we don't
@@ -482,8 +471,6 @@ private X509CertSelector getSelector(X509CertImpl previousCert)
* 0 if oCert1.equals(oCert2). We only return 0 if the
* certs are equal so that this comparator behaves
* correctly when used in a SortedSet.
- * @throws ClassCastException if either argument is not of type
- * X509Certificate
*/
@Override
public int compare(X509Certificate oCert1, X509Certificate oCert2) {
@@ -503,168 +490,126 @@ public int compare(X509Certificate oCert1, X509Certificate oCert2) {
X500Principal cIssuer1 = oCert1.getIssuerX500Principal();
X500Principal cIssuer2 = oCert2.getIssuerX500Principal();
- X500Name cIssuer1Name = X500Name.asX500Name(cIssuer1);
- X500Name cIssuer2Name = X500Name.asX500Name(cIssuer2);
-
- if (debug != null) {
- debug.println(METHOD_NME + " o1 Issuer: " + cIssuer1);
- debug.println(METHOD_NME + " o2 Issuer: " + cIssuer2);
- }
/* If one cert's issuer matches a trusted subject, then it is
* preferable.
*/
if (debug != null) {
+ debug.println(METHOD_NME + " cert1 Issuer: " + cIssuer1);
+ debug.println(METHOD_NME + " cert2 Issuer: " + cIssuer2);
debug.println(METHOD_NME + " MATCH TRUSTED SUBJECT TEST...");
}
- boolean m1 = trustedSubjectDNs.contains(cIssuer1);
- boolean m2 = trustedSubjectDNs.contains(cIssuer2);
- if (debug != null) {
- debug.println(METHOD_NME + " m1: " + m1);
- debug.println(METHOD_NME + " m2: " + m2);
- }
- if (m1 && m2) {
+ if (trustedSubjectDNs.contains(cIssuer1)) {
return -1;
- } else if (m1) {
- return -1;
- } else if (m2) {
- return 1;
- }
-
- /* If one cert's issuer is a naming descendant of a trusted subject,
- * then it is preferable, in order of increasing naming distance.
- */
- if (debug != null) {
- debug.println(METHOD_NME + " NAMING DESCENDANT TEST...");
- }
- for (X500Principal tSubject : trustedSubjectDNs) {
- X500Name tSubjectName = X500Name.asX500Name(tSubject);
- int distanceTto1 =
- Builder.distance(tSubjectName, cIssuer1Name, -1);
- int distanceTto2 =
- Builder.distance(tSubjectName, cIssuer2Name, -1);
- if (debug != null) {
- debug.println(METHOD_NME +" distanceTto1: " + distanceTto1);
- debug.println(METHOD_NME +" distanceTto2: " + distanceTto2);
- }
- if (distanceTto1 > 0 || distanceTto2 > 0) {
- // at least one is positive
- if (distanceTto2 <= 0) { // only d1 is positive
- return -1;
- } else if (distanceTto1 <= 0) { // only d2 is positive
- return 1;
- } else { // all positive
- return distanceTto1 > distanceTto2 ? 1 : -1;
- }
- }
}
-
- /* If one cert's issuer is a naming ancestor of a trusted subject,
- * then it is preferable, in order of increasing naming distance.
- */
- if (debug != null) {
- debug.println(METHOD_NME + " NAMING ANCESTOR TEST...");
- }
- for (X500Principal tSubject : trustedSubjectDNs) {
- X500Name tSubjectName = X500Name.asX500Name(tSubject);
-
- int distanceTto1 = Builder.distance
- (tSubjectName, cIssuer1Name, Integer.MAX_VALUE);
- int distanceTto2 = Builder.distance
- (tSubjectName, cIssuer2Name, Integer.MAX_VALUE);
- if (debug != null) {
- debug.println(METHOD_NME +" distanceTto1: " + distanceTto1);
- debug.println(METHOD_NME +" distanceTto2: " + distanceTto2);
- }
- if (distanceTto1 < 0 || distanceTto2 < 0) {
- // at least one is negative
- if (distanceTto2 >= 0) { // only d1 is negative
- return -1;
- } else if (distanceTto1 >= 0) { // only d2 is negative
- return 1;
- } else { // all negative
- return distanceTto1 < distanceTto2 ? 1 : -1;
- }
- }
+ if (trustedSubjectDNs.contains(cIssuer2)) {
+ return 1;
}
/* If one cert's issuer is in the same namespace as a trusted
* subject, then it is preferable, in order of increasing naming
* distance.
*/
+ String debugMsg = null;
if (debug != null) {
- debug.println(METHOD_NME +" SAME NAMESPACE AS TRUSTED TEST...");
+ debug.println(METHOD_NME + " SAME NAMESPACE AS TRUSTED TEST...");
+ debugMsg = METHOD_NME + " distance (number of " +
+ "RDNs) from cert%1$s issuer to trusted subject %2$s: %3$d";
}
+
+ X500Name cIssuer1Name = X500Name.asX500Name(cIssuer1);
+ X500Name cIssuer2Name = X500Name.asX500Name(cIssuer2);
+ // Note that we stop searching if we find a trust anchor that
+ // has a common non-geographical ancestor on the basis that there
+ // is a good chance that this path is the one we want.
for (X500Principal tSubject : trustedSubjectDNs) {
X500Name tSubjectName = X500Name.asX500Name(tSubject);
- X500Name tAo1 = tSubjectName.commonAncestor(cIssuer1Name);
- X500Name tAo2 = tSubjectName.commonAncestor(cIssuer2Name);
+ int d1 = distanceToCommonAncestor(tSubjectName, cIssuer1Name);
+ int d2 = distanceToCommonAncestor(tSubjectName, cIssuer2Name);
if (debug != null) {
- debug.println(METHOD_NME +" tAo1: " + tAo1);
- debug.println(METHOD_NME +" tAo2: " + tAo2);
+ if (d1 != -1) {
+ debug.println(String.format(debugMsg, "1", tSubject, d1));
+ }
+ if (d2 != -1) {
+ debug.println(String.format(debugMsg, "2", tSubject, d2));
+ }
}
- if (tAo1 != null || tAo2 != null) {
- if (tAo1 != null && tAo2 != null) {
- int hopsTto1 = Builder.hops
- (tSubjectName, cIssuer1Name, Integer.MAX_VALUE);
- int hopsTto2 = Builder.hops
- (tSubjectName, cIssuer2Name, Integer.MAX_VALUE);
- if (debug != null) {
- debug.println(METHOD_NME +" hopsTto1: " + hopsTto1);
- debug.println(METHOD_NME +" hopsTto2: " + hopsTto2);
- }
- if (hopsTto1 == hopsTto2) {
- } else if (hopsTto1 > hopsTto2) {
- return 1;
- } else { // hopsTto1 < hopsTto2
- return -1;
- }
- } else if (tAo1 == null) {
- return 1;
+ if (d1 == -1 && d2 == -1) {
+ // neither cert has a common non-geographical ancestor with
+ // trust anchor, so continue checking other trust anchors
+ continue;
+ }
+ if (d1 != -1) {
+ if (d2 != -1) {
+ // both certs share a common non-geographical ancestor
+ // with trust anchor. Prefer the one that is closer
+ // to the trust anchor.
+ return (d1 > d2) ? 1 : -1;
} else {
+ // cert1 shares a common non-geographical ancestor with
+ // trust anchor, so it is preferred.
return -1;
}
+ } else if (d2 != -1) {
+ // cert2 shares a common non-geographical ancestor with
+ // trust anchor, so it is preferred.
+ return 1;
}
}
-
- /* If one cert's issuer is an ancestor of that cert's subject,
- * then it is preferable, in order of increasing naming distance.
+ /* Otherwise, certs are equally preferable.
*/
if (debug != null) {
- debug.println(METHOD_NME+" CERT ISSUER/SUBJECT COMPARISON TEST...");
+ debug.println(METHOD_NME + " no tests matched; RETURN -1");
}
- X500Principal cSubject1 = oCert1.getSubjectX500Principal();
- X500Principal cSubject2 = oCert2.getSubjectX500Principal();
- X500Name cSubject1Name = X500Name.asX500Name(cSubject1);
- X500Name cSubject2Name = X500Name.asX500Name(cSubject2);
+ return -1;
+ }
+ }
- if (debug != null) {
- debug.println(METHOD_NME + " o1 Subject: " + cSubject1);
- debug.println(METHOD_NME + " o2 Subject: " + cSubject2);
- }
- int distanceStoI1 = Builder.distance
- (cSubject1Name, cIssuer1Name, Integer.MAX_VALUE);
- int distanceStoI2 = Builder.distance
- (cSubject2Name, cIssuer2Name, Integer.MAX_VALUE);
- if (debug != null) {
- debug.println(METHOD_NME + " distanceStoI1: " + distanceStoI1);
- debug.println(METHOD_NME + " distanceStoI2: " + distanceStoI2);
- }
- if (distanceStoI2 > distanceStoI1) {
- return -1;
- } else if (distanceStoI2 < distanceStoI1) {
- return 1;
- }
+ /**
+ * Returns the distance (number of RDNs) from the issuer's DN to the
+ * common non-geographical ancestor of the trust anchor and issuer's DN.
+ *
+ * @param anchor the anchor's DN
+ * @param issuer the issuer's DN
+ * @return the distance or -1 if no common ancestor or an attribute of the
+ * last RDN of the common ancestor is geographical
+ */
+ private static int distanceToCommonAncestor(X500Name anchor, X500Name issuer) {
+ List anchorRdns = anchor.rdns();
+ List issuerRdns = issuer.rdns();
+ int minLen = Math.min(anchorRdns.size(), issuerRdns.size());
+ if (minLen == 0) {
+ return -1;
+ }
- /* Otherwise, certs are equally preferable.
- */
- if (debug != null) {
- debug.println(METHOD_NME + " no tests matched; RETURN 0");
+ // Compare names from highest RDN down the naming tree.
+ int i = 0;
+ for (; i < minLen; i++) {
+ RDN rdn = anchorRdns.get(i);
+ if (!rdn.equals(issuerRdns.get(i))) {
+ if (i == 0) {
+ return -1;
+ } else {
+ break;
+ }
}
- return -1;
}
+
+ // check if last RDN is geographical
+ RDN lastRDN = anchorRdns.get(i - 1);
+ for (AVA ava : lastRDN.avas()) {
+ ObjectIdentifier oid = ava.getObjectIdentifier();
+ if (oid.equals(X500Name.countryName_oid) ||
+ oid.equals(X500Name.stateName_oid) ||
+ oid.equals(X500Name.localityName_oid) ||
+ oid.equals(X500Name.streetAddress_oid)) {
+ return -1;
+ }
+ }
+
+ return issuer.size() - i;
}
/**
diff --git a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java
index 6c29db30c60..e92c7c575a6 100644
--- a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java
+++ b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, 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
@@ -201,6 +201,10 @@ public static SSLPossession createPossession(
private static SSLPossession createClientPossession(
ClientHandshakeContext chc, String[] keyTypes) {
X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager();
+ if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+ SSLLogger.finest("X509KeyManager class: " +
+ km.getClass().getName());
+ }
String clientAlias = null;
if (chc.conContext.transport instanceof SSLSocketImpl socket) {
clientAlias = km.chooseClientAlias(
@@ -270,6 +274,10 @@ private static SSLPossession createClientPossession(
private static SSLPossession createServerPossession(
ServerHandshakeContext shc, String[] keyTypes) {
X509ExtendedKeyManager km = shc.sslContext.getX509KeyManager();
+ if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
+ SSLLogger.finest("X509KeyManager class: " +
+ km.getClass().getName());
+ }
String serverAlias = null;
for (String keyType : keyTypes) {
if (shc.conContext.transport instanceof SSLSocketImpl socket) {
diff --git a/src/java.base/share/classes/sun/security/util/ECUtil.java b/src/java.base/share/classes/sun/security/util/ECUtil.java
index 011ab846048..966b13beee2 100644
--- a/src/java.base/share/classes/sun/security/util/ECUtil.java
+++ b/src/java.base/share/classes/sun/security/util/ECUtil.java
@@ -140,21 +140,16 @@ public static ECPrivateKey generateECPrivateKey(BigInteger s,
return (ECPrivateKey)keyFactory.generatePrivate(keySpec);
}
- public static AlgorithmParameters getECParameters(Provider p) {
+ public static AlgorithmParameters getECParameters() {
try {
- if (p != null) {
- return AlgorithmParameters.getInstance("EC", p);
- }
-
return AlgorithmParameters.getInstance("EC");
} catch (NoSuchAlgorithmException nsae) {
throw new RuntimeException(nsae);
}
}
- public static byte[] encodeECParameterSpec(Provider p,
- ECParameterSpec spec) {
- AlgorithmParameters parameters = getECParameters(p);
+ public static byte[] encodeECParameterSpec(ECParameterSpec spec) {
+ AlgorithmParameters parameters = getECParameters();
try {
parameters.init(spec);
@@ -170,9 +165,8 @@ public static byte[] encodeECParameterSpec(Provider p,
}
}
- public static ECParameterSpec getECParameterSpec(Provider p,
- ECParameterSpec spec) {
- AlgorithmParameters parameters = getECParameters(p);
+ public static ECParameterSpec getECParameterSpec(ECParameterSpec spec) {
+ AlgorithmParameters parameters = getECParameters();
try {
parameters.init(spec);
@@ -182,10 +176,9 @@ public static ECParameterSpec getECParameterSpec(Provider p,
}
}
- public static ECParameterSpec getECParameterSpec(Provider p,
- byte[] params)
+ public static ECParameterSpec getECParameterSpec(byte[] params)
throws IOException {
- AlgorithmParameters parameters = getECParameters(p);
+ AlgorithmParameters parameters = getECParameters();
parameters.init(params);
@@ -196,8 +189,8 @@ public static ECParameterSpec getECParameterSpec(Provider p,
}
}
- public static ECParameterSpec getECParameterSpec(Provider p, String name) {
- AlgorithmParameters parameters = getECParameters(p);
+ public static ECParameterSpec getECParameterSpec(String name) {
+ AlgorithmParameters parameters = getECParameters();
try {
parameters.init(new ECGenParameterSpec(name));
@@ -207,8 +200,8 @@ public static ECParameterSpec getECParameterSpec(Provider p, String name) {
}
}
- public static ECParameterSpec getECParameterSpec(Provider p, int keySize) {
- AlgorithmParameters parameters = getECParameters(p);
+ public static ECParameterSpec getECParameterSpec(int keySize) {
+ AlgorithmParameters parameters = getECParameters();
try {
parameters.init(new ECKeySizeParameterSpec(keySize));
@@ -219,9 +212,9 @@ public static ECParameterSpec getECParameterSpec(Provider p, int keySize) {
}
- public static String getCurveName(Provider p, ECParameterSpec spec) {
+ public static String getCurveName(ECParameterSpec spec) {
ECGenParameterSpec nameSpec;
- AlgorithmParameters parameters = getECParameters(p);
+ AlgorithmParameters parameters = getECParameters();
try {
parameters.init(spec);
diff --git a/src/java.base/share/classes/sun/security/util/KeyUtil.java b/src/java.base/share/classes/sun/security/util/KeyUtil.java
index c38889ed494..6884b9b201a 100644
--- a/src/java.base/share/classes/sun/security/util/KeyUtil.java
+++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java
@@ -153,7 +153,7 @@ public static final int getKeySize(AlgorithmParameters parameters) {
// Note: the ECGenParameterSpec case should be covered by the
// ECParameterSpec case above.
- // See ECUtil.getECParameterSpec(Provider, String).
+ // See ECUtil.getECParameterSpec(String).
break;
case "DiffieHellman":
diff --git a/src/java.base/share/classes/sun/security/x509/X500Name.java b/src/java.base/share/classes/sun/security/x509/X500Name.java
index bf115bf761b..8a407e2263a 100644
--- a/src/java.base/share/classes/sun/security/x509/X500Name.java
+++ b/src/java.base/share/classes/sun/security/x509/X500Name.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2024, 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
@@ -25,16 +25,13 @@
package sun.security.x509;
-import java.lang.reflect.*;
import java.io.IOException;
-import java.security.PrivilegedExceptionAction;
-import java.security.AccessController;
import java.security.Principal;
import java.util.*;
-import java.util.StringJoiner;
+import javax.security.auth.x500.X500Principal;
+import jdk.internal.access.SharedSecrets;
import sun.security.util.*;
-import javax.security.auth.x500.X500Principal;
/**
* Note: As of 1.4, the public class,
@@ -1272,120 +1269,22 @@ public int subtreeDepth() throws UnsupportedOperationException {
return names.length;
}
- /**
- * Return lowest common ancestor of this name and other name
- *
- * @param other another X500Name
- * @return X500Name of lowest common ancestor; null if none
- */
- public X500Name commonAncestor(X500Name other) {
-
- if (other == null) {
- return null;
- }
- int otherLen = other.names.length;
- int thisLen = this.names.length;
- if (thisLen == 0 || otherLen == 0) {
- return null;
- }
- int minLen = Math.min(thisLen, otherLen);
-
- //Compare names from highest RDN down the naming tree
- //Note that these are stored in RDN[0]...
- int i=0;
- for (; i < minLen; i++) {
- if (!names[i].equals(other.names[i])) {
- if (i == 0) {
- return null;
- } else {
- break;
- }
- }
- }
-
- //Copy matching RDNs into new RDN array
- RDN[] ancestor = new RDN[i];
- System.arraycopy(names, 0, ancestor, 0, i);
-
- X500Name commonAncestor;
- try {
- commonAncestor = new X500Name(ancestor);
- } catch (IOException ioe) {
- return null;
- }
- return commonAncestor;
- }
-
- /**
- * Constructor object for use by asX500Principal().
- */
- private static final Constructor principalConstructor;
-
- /**
- * Field object for use by asX500Name().
- */
- private static final Field principalField;
-
- /**
- * Retrieve the Constructor and Field we need for reflective access
- * and make them accessible.
- */
- static {
- PrivilegedExceptionAction