diff --git a/doc/building.html b/doc/building.html index a57d3d16abc..a49d7153ba3 100644 --- a/doc/building.html +++ b/doc/building.html @@ -68,7 +68,8 @@

Building the JDK

  • Apple Xcode
  • Microsoft Visual Studio
  • -
  • IBM XL C/C++
  • +
  • IBM Open XL +C/C++
  • Boot JDK Requirements @@ -673,11 +674,10 @@

    Microsoft Visual Studio

    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 socksProxyVersion} (default: {@code 5})
        +

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

      Misc HTTP URL stream protocol handler properties

      protocol handler.

    • {@systemProperty http.auth.digest.validateServer} (default: {@code false})

    • {@systemProperty http.auth.digest.validateProxy} (default: {@code false})

      -
    • {@systemProperty http.auth.digest.cnonceRepeat} (default: {@code 5})

      -

      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. + *
      • "CLDR": A locale data provider based on the Unicode Consortium's + * Common Locale Data Repository (CLDR). *
      • "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 releaseCLDR version
      JDK 22CLDR 44
      JDK 21CLDR 43
      JDK 20CLDR 42
      JDK 19CLDR 41
      JDK 18CLDR 39
      JDK 17CLDR 39
      JDK 16CLDR 38
      JDK 15CLDR 37
      JDK 14CLDR 36
      JDK 13CLDR 35.1
      JDK 12CLDR 33
      JDK 11CLDR 33
      JDK 10CLDR 29
      JDK 9CLDR 29
      JDK 8CLDR 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. - *

      - * Example: - *

      {@code
      -     * --> GET http://www.authorization-required.com/ HTTP/1.0
      -     * <-- HTTP/1.0 403 Unauthorized
      -     * <-- WWW-Authenticate: Basic realm="WallyWorld"
      -     * call schemeSupported("Basic"); (return true)
      -     * call authString(u, "Basic", "WallyWorld", null);
      -     *   return "QWadhgWERghghWERfdfQ=="
      -     * --> GET http://www.authorization-required.com/ HTTP/1.0
      -     * --> Authorization: Basic QWadhgWERghghWERfdfQ==
      -     * <-- HTTP/1.0 200 OK}
      -     *  YAY!!!
      -     * 
      - */ - - 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 pa = - () -> { - Class pClass = X500Principal.class; - Class[] args = new Class[] { X500Name.class }; - Constructor cons = - pClass.getDeclaredConstructor(args); - cons.setAccessible(true); - Field field = pClass.getDeclaredField("thisX500Name"); - field.setAccessible(true); - return new Object[] {cons, field}; - }; - try { - @SuppressWarnings("removal") - Object[] result = AccessController.doPrivileged(pa); - @SuppressWarnings("unchecked") - Constructor constr = - (Constructor)result[0]; - principalConstructor = constr; - principalField = (Field)result[1]; - } catch (Exception e) { - throw new InternalError("Could not obtain X500Principal access", e); - } - } - /** * Get an X500Principal backed by this X500Name. - * - * Note that we are using privileged reflection to access the hidden - * package private constructor in X500Principal. */ public X500Principal asX500Principal() { if (x500Principal == null) { - try { - Object[] args = new Object[] {this}; - x500Principal = principalConstructor.newInstance(args); - } catch (Exception e) { - throw new RuntimeException("Unexpected exception", e); - } + x500Principal = + SharedSecrets.getJavaxSecurityAccess().asX500Principal(this); } return x500Principal; } /** * Get the X500Name contained in the given X500Principal. - * - * Note that the X500Name is retrieved using reflection. */ public static X500Name asX500Name(X500Principal p) { - try { - X500Name name = (X500Name)principalField.get(p); - name.x500Principal = p; - return name; - } catch (Exception e) { - throw new RuntimeException("Unexpected exception", e); - } + return SharedSecrets.getJavaxSecurityAccess().asX500Name(p); } } diff --git a/src/java.base/share/data/lsrdata/language-subtag-registry.txt b/src/java.base/share/data/lsrdata/language-subtag-registry.txt index c6937ee80f1..4737c50e425 100644 --- a/src/java.base/share/data/lsrdata/language-subtag-registry.txt +++ b/src/java.base/share/data/lsrdata/language-subtag-registry.txt @@ -1,4 +1,4 @@ -File-Date: 2023-10-16 +File-Date: 2024-03-07 %% Type: language Subtag: aa @@ -882,6 +882,7 @@ Type: language Subtag: sa Description: Sanskrit Added: 2005-10-16 +Scope: macrolanguage %% Type: language Subtag: sc @@ -8028,6 +8029,12 @@ Description: Lowland Oaxaca Chontal Added: 2009-07-29 %% Type: language +Subtag: cls +Description: Classical Sanskrit +Added: 2024-03-04 +Macrolanguage: sa +%% +Type: language Subtag: clt Description: Lautu Chin Added: 2012-08-12 @@ -30916,6 +30923,11 @@ Description: Ririo Added: 2009-07-29 %% Type: language +Subtag: rrm +Description: Moriori +Added: 2024-03-04 +%% +Type: language Subtag: rro Description: Waima Added: 2009-07-29 @@ -37660,6 +37672,12 @@ Description: Venezuelan Sign Language Added: 2009-07-29 %% Type: language +Subtag: vsn +Description: Vedic Sanskrit +Added: 2024-03-04 +Macrolanguage: sa +%% +Type: language Subtag: vsv Description: Valencian Sign Language Description: Llengua de signes valenciana @@ -47559,6 +47577,13 @@ Comments: Aluku dialect of the "Busi Nenge Tongo" English-based Creole continuum in Eastern Suriname and Western French Guiana %% Type: variant +Subtag: anpezo +Description: Anpezo standard of Ladin +Added: 2024-03-04 +Prefix: lld +Comments: Represents the standard written form of Ladin in Anpezo +%% +Type: variant Subtag: ao1990 Description: Portuguese Language Orthographic Agreement of 1990 (Acordo Ortográfico da Língua Portuguesa de 1990) @@ -47779,6 +47804,22 @@ Added: 2012-02-05 Prefix: en %% Type: variant +Subtag: fascia +Description: Fascia standard of Ladin +Added: 2024-03-04 +Prefix: lld +Comments: Represents the standard written form of Ladin in Fascia which + unified the three subvarieties Cazet, Brach and Moenat +%% +Type: variant +Subtag: fodom +Description: Fodom standard of Ladin +Added: 2024-03-04 +Prefix: lld +Comments: Represents the standard written form of Ladin in Livinallongo + and Colle Santa Lucia +%% +Type: variant Subtag: fonipa Description: International Phonetic Alphabet Added: 2006-12-11 @@ -47819,6 +47860,13 @@ Prefix: oc Comments: Occitan variant spoken in Gascony %% Type: variant +Subtag: gherd +Description: Gherdëina standard of Ladin +Added: 2024-03-04 +Prefix: lld +Comments: Represents the standard written form of Ladin in Gherdëina +%% +Type: variant Subtag: grclass Description: Classical Occitan orthography Added: 2018-04-22 @@ -48120,6 +48168,15 @@ Comments: Peano’s Interlingua, created in 1903 by Giuseppe Peano as an Added: 2020-03-12 %% Type: variant +Subtag: pehoeji +Description: Hokkien Vernacular Romanization System +Description: Pe̍h-ōe-jī orthography/romanization +Added: 2024-03-04 +Prefix: nan-Latn +Comments: Modern Hokkien Vernacular Romanization System, evolved from + the New Dictionary in the Amoy by John Van Nest Talmage in 1894 +%% +Type: variant Subtag: petr1708 Description: Petrine orthography Added: 2010-10-10 @@ -48254,6 +48311,16 @@ Added: 2021-07-17 Prefix: da %% Type: variant +Subtag: tailo +Description: Taiwanese Hokkien Romanization System for Hokkien + languages +Description: Tâi-lô orthography/romanization +Added: 2024-03-04 +Prefix: nan-Latn +Comments: Taiwanese Hokkien Romanization System (Tâi-lô) published in + 2006 by the Taiwan Ministry of Education +%% +Type: variant Subtag: tarask Description: Belarusian in Taraskievica orthography Added: 2007-04-27 @@ -48317,6 +48384,15 @@ Comments: The most ancient dialect of Sanskrit used in verse and prose composed until about the 4th century B.C.E. %% Type: variant +Subtag: valbadia +Description: Val Badia standard of Ladin +Added: 2024-03-04 +Prefix: lld +Comments: Represents the standard written form of Ladin in the Val + Badia, unifying the three variants Marô, Mesaval and Badiot spoken + in this valley +%% +Type: variant Subtag: valencia Description: Valencian Added: 2007-03-06 diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index d386fb15b8f..6499d70f989 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -279,6 +279,11 @@ the compilation. This sets both the source version accepted by compiler and the system API that may be used by the code in the source file. .IP \[bu] 2 +If \f[V]--enable-preview\f[R] is specified, the \f[V]--source N\f[R] +arguments can be omitted. +If the Java runtime version is \f[V]N\f[R], then \f[V]--release N\f[R] +is implied when compiling source files. +.IP \[bu] 2 If a \f[V]module-info.java\f[R] file exists in the \f[V]\f[R] directory, its module declaration is used to define a named module that will contain all the classes compiled from diff --git a/src/java.base/share/native/libjava/CDS.c b/src/java.base/share/native/libjava/CDS.c index 77f0020db38..989b5aa9dbf 100644 --- a/src/java.base/share/native/libjava/CDS.c +++ b/src/java.base/share/native/libjava/CDS.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, 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 @@ -44,19 +44,9 @@ Java_jdk_internal_misc_CDS_getRandomSeedForDumping(JNIEnv *env, jclass ignore) { return JVM_GetRandomSeedForDumping(); } -JNIEXPORT jboolean JNICALL -Java_jdk_internal_misc_CDS_isDumpingArchive0(JNIEnv *env, jclass jcls) { - return JVM_IsCDSDumpingEnabled(env); -} - -JNIEXPORT jboolean JNICALL -Java_jdk_internal_misc_CDS_isSharingEnabled0(JNIEnv *env, jclass jcls) { - return JVM_IsSharingEnabled(env); -} - -JNIEXPORT jboolean JNICALL -Java_jdk_internal_misc_CDS_isDumpingClassList0(JNIEnv *env, jclass jcls) { - return JVM_IsDumpingClassList(env); +JNIEXPORT jint JNICALL +Java_jdk_internal_misc_CDS_getCDSConfigStatus(JNIEnv *env, jclass jcls) { + return JVM_GetCDSConfigStatus(); } JNIEXPORT void JNICALL diff --git a/src/java.base/share/native/libjava/jni_util.h b/src/java.base/share/native/libjava/jni_util.h index 238a20b18ea..3c73e90d62c 100644 --- a/src/java.base/share/native/libjava/jni_util.h +++ b/src/java.base/share/native/libjava/jni_util.h @@ -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 @@ -27,6 +27,7 @@ #define JNI_UTIL_H #include "jni.h" +#include "jni_util_md.h" #include "jlong.h" #ifdef __cplusplus diff --git a/src/java.base/unix/native/jspawnhelper/jspawnhelper.c b/src/java.base/unix/native/jspawnhelper/jspawnhelper.c index 5a583fda61f..974329a2857 100644 --- a/src/java.base/unix/native/jspawnhelper/jspawnhelper.c +++ b/src/java.base/unix/native/jspawnhelper/jspawnhelper.c @@ -63,6 +63,7 @@ void shutItDown() { fprintf(stdout, "only be run as the result of a call to\n"); fprintf(stdout, "ProcessBuilder.start() or Runtime.exec() in a java "); fprintf(stdout, "application\n"); + fflush(stdout); _exit(1); } @@ -140,6 +141,10 @@ int main(int argc, char *argv[]) { int r, fdinr, fdinw, fdout; sigset_t unblock_signals; + if (argc != 2) { + shutItDown(); + } + #ifdef DEBUG jtregSimulateCrash(0, 4); #endif diff --git a/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c b/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c index c13f7334526..57d911e35de 100644 --- a/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c +++ b/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c @@ -30,7 +30,6 @@ #include "ProcessHandleImpl_unix.h" - #include #include #include @@ -131,19 +130,6 @@ */ #define WTERMSIG_RETURN(status) (WTERMSIG(status) + 0x80) -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == -1) && (errno == EINTR)); \ -} while(0) - -#define RESTARTABLE_RETURN_PTR(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == NULL) && (errno == EINTR)); \ -} while(0) - - /* Field id for jString 'command' in java.lang.ProcessHandleImpl.Info */ jfieldID ProcessHandleImpl_Info_commandID; diff --git a/src/java.base/unix/native/libjava/TimeZone_md.c b/src/java.base/unix/native/libjava/TimeZone_md.c index 8124f3c0a9c..988c4bd2646 100644 --- a/src/java.base/unix/native/libjava/TimeZone_md.c +++ b/src/java.base/unix/native/libjava/TimeZone_md.c @@ -37,19 +37,12 @@ #include #include "jvm.h" +#include "jni_util.h" #include "TimeZone_md.h" #include "path_util.h" static char *isFileIdentical(char* buf, size_t size, char *pathname); -#define SKIP_SPACE(p) while (*p == ' ' || *p == '\t') p++; - -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == -1) && (errno == EINTR)); \ -} while(0) - #define fileopen fopen #define filegets fgets #define fileclose fclose diff --git a/src/java.base/unix/native/libjava/childproc.c b/src/java.base/unix/native/libjava/childproc.c index 52769ec642f..a061bc0e210 100644 --- a/src/java.base/unix/native/libjava/childproc.c +++ b/src/java.base/unix/native/libjava/childproc.c @@ -33,6 +33,7 @@ #include #include "childproc.h" +#include "jni_util.h" const char * const *parentPathv; diff --git a/src/java.base/unix/native/libjava/childproc.h b/src/java.base/unix/native/libjava/childproc.h index 49026b388c9..77ec41921d2 100644 --- a/src/java.base/unix/native/libjava/childproc.h +++ b/src/java.base/unix/native/libjava/childproc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -72,13 +72,6 @@ extern char **environ; #define FAIL_FILENO (STDERR_FILENO + 1) -/* TODO: Refactor. */ -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == -1) && (errno == EINTR)); \ -} while(0) - /* These numbers must be the same as the Enum in ProcessImpl.java * Must be a better way of doing this. */ diff --git a/src/java.base/unix/native/libjava/io_util_md.h b/src/java.base/unix/native/libjava/io_util_md.h index d6b4d40f3d2..84e97b4ace5 100644 --- a/src/java.base/unix/native/libjava/io_util_md.h +++ b/src/java.base/unix/native/libjava/io_util_md.h @@ -72,14 +72,6 @@ FD getFD(JNIEnv *env, jobject cur, jfieldID fid); */ #define SET_HANDLE(fd) return (jlong)-1 -/* - * Retry the operation if it is interrupted - */ -#define RESTARTABLE(_cmd, _result) \ - do { \ - _result = _cmd; \ - } while ((_result == -1) && (errno == EINTR)) - void fileDescriptorClose(JNIEnv *env, jobject this); #ifdef MACOSX diff --git a/src/java.base/unix/native/libjava/jni_util_md.h b/src/java.base/unix/native/libjava/jni_util_md.h new file mode 100644 index 00000000000..af526bc6e50 --- /dev/null +++ b/src/java.base/unix/native/libjava/jni_util_md.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#ifndef JNI_UTIL_MD_H +#define JNI_UTIL_MD_H + +#define RESTARTABLE(_cmd, _result) do { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ +} while(0) + +#endif /* JNI_UTIL_MD_H */ + diff --git a/src/java.base/unix/native/libnet/SdpSupport.c b/src/java.base/unix/native/libnet/SdpSupport.c index 4a1f54ea5a0..6729170efb4 100644 --- a/src/java.base/unix/native/libnet/SdpSupport.c +++ b/src/java.base/unix/native/libnet/SdpSupport.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, 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 @@ -37,13 +37,6 @@ #include "jni_util.h" #include "net_util.h" -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == -1) && (errno == EINTR)); \ -} while(0) - - /** * Creates a SDP socket. */ diff --git a/src/java.base/unix/native/libnio/ch/nio_util.h b/src/java.base/unix/native/libnio/ch/nio_util.h index 5e20934678c..6cd3c858a7b 100644 --- a/src/java.base/unix/native/libnio/ch/nio_util.h +++ b/src/java.base/unix/native/libnio/ch/nio_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, 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 @@ -31,12 +31,6 @@ #include #include -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == -1) && (errno == EINTR)); \ -} while(0) - /* Defines SO_REUSEPORT */ #ifndef SO_REUSEPORT #ifdef __linux__ diff --git a/src/java.base/unix/native/libnio/fs/UnixFileSystem.c b/src/java.base/unix/native/libnio/fs/UnixFileSystem.c index c3626368246..f3977175eb0 100644 --- a/src/java.base/unix/native/libnio/fs/UnixFileSystem.c +++ b/src/java.base/unix/native/libnio/fs/UnixFileSystem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -35,12 +35,6 @@ #include "sun_nio_fs_UnixFileSystem.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/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index 79143b45a50..b7afaf4cdce 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -162,18 +162,6 @@ struct my_statx */ #define ENT_BUF_SIZE 1024 -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == -1) && (errno == EINTR)); \ -} while(0) - -#define RESTARTABLE_RETURN_PTR(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == NULL) && (errno == EINTR)); \ -} while(0) - static jfieldID attrs_st_mode; static jfieldID attrs_st_ino; static jfieldID attrs_st_dev; diff --git a/src/java.base/windows/native/libjava/jni_util_md.h b/src/java.base/windows/native/libjava/jni_util_md.h new file mode 100644 index 00000000000..d5f1602673f --- /dev/null +++ b/src/java.base/windows/native/libjava/jni_util_md.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#ifndef JNI_UTIL_MD_H +#define JNI_UTIL_MD_H + +#endif /* JNI_UTIL_MD_H */ + diff --git a/src/java.desktop/share/classes/java/awt/GraphicsEnvironment.java b/src/java.desktop/share/classes/java/awt/GraphicsEnvironment.java index 0265142aee3..2e89aa6f672 100644 --- a/src/java.desktop/share/classes/java/awt/GraphicsEnvironment.java +++ b/src/java.desktop/share/classes/java/awt/GraphicsEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, 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 @@ -23,7 +23,6 @@ * questions. */ - package java.awt; import java.awt.image.BufferedImage; @@ -36,7 +35,6 @@ import sun.font.FontManagerFactory; import sun.java2d.HeadlessGraphicsEnvironment; import sun.java2d.SunGraphicsEnvironment; -import sun.security.action.GetPropertyAction; /** * diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XFramePeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XFramePeer.java index 70a01dc0b05..c7f3ba95bc1 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XFramePeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XFramePeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, 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 @@ -328,6 +328,15 @@ void setExtendedState(int newState) { XWM.getWM().setExtendedState(this, newState); } + @Override + public void toFront() { + if ((state & Frame.ICONIFIED) != 0) { + changeState(state & ~Frame.ICONIFIED); + } + + super.toFront(); + } + public void handlePropertyNotify(XEvent xev) { super.handlePropertyNotify(xev); XPropertyEvent ev = xev.get_xproperty(); diff --git a/src/java.desktop/windows/classes/sun/awt/PlatformGraphicsInfo.java b/src/java.desktop/windows/classes/sun/awt/PlatformGraphicsInfo.java index 02527d4f207..4644a2e5f46 100644 --- a/src/java.desktop/windows/classes/sun/awt/PlatformGraphicsInfo.java +++ b/src/java.desktop/windows/classes/sun/awt/PlatformGraphicsInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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,20 +28,41 @@ import java.awt.GraphicsEnvironment; import java.awt.Toolkit; +import sun.awt.windows.WToolkit; + public class PlatformGraphicsInfo { + private static final boolean hasDisplays; + + static { + loadAWTLibrary(); + hasDisplays = hasDisplays0(); + } + + @SuppressWarnings("removal") + private static void loadAWTLibrary() { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + System.loadLibrary("awt"); + return null; + } + }); + } + + private static native boolean hasDisplays0(); + public static GraphicsEnvironment createGE() { return new Win32GraphicsEnvironment(); } public static Toolkit createToolkit() { - return new sun.awt.windows.WToolkit(); + return new WToolkit(); } public static boolean getDefaultHeadlessProperty() { - // On Windows, we assume we can always create headful apps. - // Here is where we can add code that would actually check. - return false; + // If we don't find usable displays, we run headless. + return !hasDisplays; } /* @@ -54,5 +75,4 @@ public static String getDefaultHeadlessMessage() { "\nThe application does not have desktop access,\n" + "but this program performed an operation which requires it."; } - } diff --git a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java index 04b3f7b77d7..cb7ab363cdf 100644 --- a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java +++ b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, 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 @@ -60,7 +60,8 @@ public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment { WToolkit.loadLibraries(); // setup flags before initializing native layer WindowsFlags.initFlags(); - initDisplayWrapper(); + + initDisplay(); // Install correct surface manager factory. SurfaceManagerFactory.setInstance(new WindowsSurfaceManagerFactory()); @@ -82,20 +83,12 @@ public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment { } /** - * Initializes native components of the graphics environment. This + * Initializes native components of the graphics environment. This * includes everything from the native GraphicsDevice elements to * the DirectX rendering layer. */ private static native void initDisplay(); - private static boolean displayInitialized; // = false; - public static void initDisplayWrapper() { - if (!displayInitialized) { - displayInitialized = true; - initDisplay(); - } - } - public Win32GraphicsEnvironment() { } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java index 6b3fa5823fe..a5612b08dc4 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, 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 @@ -65,6 +65,16 @@ public int getExtendedState() { return AWTAccessor.getFrameAccessor().getExtendedState((Frame)target); } + @Override + public void toFront() { + int state = getState(); + if ((state & Frame.ICONIFIED) != 0) { + setState(state & ~Frame.ICONIFIED); + } + + super.toFront(); + } + // Convenience methods to save us from trouble of extracting // Rectangle fields in native code. private native void setMaximizedBounds(int x, int y, int w, int h); diff --git a/src/java.desktop/windows/native/libawt/windows/Devices.cpp b/src/java.desktop/windows/native/libawt/windows/Devices.cpp index f36914e4606..e275cb77a57 100644 --- a/src/java.desktop/windows/native/libawt/windows/Devices.cpp +++ b/src/java.desktop/windows/native/libawt/windows/Devices.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, 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 @@ -85,60 +85,75 @@ #include "Trace.h" #include "D3DPipelineManager.h" +typedef struct { + int monitorCounter; + int monitorLimit; + HMONITOR* hmpMonitors; +} MonitorData; -/* Some helper functions (from awt_MMStub.h/cpp) */ -int g_nMonitorCounter; -int g_nMonitorLimit; -HMONITOR* g_hmpMonitors; +// Only monitors where CreateDC does not fail are valid +static BOOL IsValidMonitor(HMONITOR hMon) +{ + MONITORINFOEX mieInfo; + memset((void*)(&mieInfo), 0, sizeof(MONITORINFOEX)); + mieInfo.cbSize = sizeof(MONITORINFOEX); + if (!::GetMonitorInfo(hMon, (LPMONITORINFOEX)(&mieInfo))) { + J2dTraceLn1(J2D_TRACE_INFO, "Devices::IsValidMonitor: GetMonitorInfo failed for monitor with handle %p", hMon); + return FALSE; + } + + HDC hDC = CreateDC(mieInfo.szDevice, NULL, NULL, NULL); + if (NULL == hDC) { + J2dTraceLn2(J2D_TRACE_INFO, "Devices::IsValidMonitor: CreateDC failed for monitor with handle %p, device: %S", hMon, mieInfo.szDevice); + return FALSE; + } + + ::DeleteDC(hDC); + return TRUE; +} // Callback for CountMonitors below -BOOL WINAPI clb_fCountMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lP) +static BOOL WINAPI clb_fCountMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorCounter) { - g_nMonitorCounter ++; + if (IsValidMonitor(hMon)) { + (*((int *)lpMonitorCounter))++; + } + return TRUE; } int WINAPI CountMonitors(void) { - g_nMonitorCounter = 0; - ::EnumDisplayMonitors(NULL, NULL, clb_fCountMonitors, 0L); - return g_nMonitorCounter; - + int monitorCounter = 0; + ::EnumDisplayMonitors(NULL, NULL, clb_fCountMonitors, (LPARAM)&monitorCounter); + return monitorCounter; } // Callback for CollectMonitors below -BOOL WINAPI clb_fCollectMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lP) +static BOOL WINAPI clb_fCollectMonitors(HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorData) { - - if ((g_nMonitorCounter < g_nMonitorLimit) && (NULL != g_hmpMonitors)) { - g_hmpMonitors[g_nMonitorCounter] = hMon; - g_nMonitorCounter ++; + MonitorData* pMonitorData = (MonitorData *)lpMonitorData; + if ((pMonitorData->monitorCounter < pMonitorData->monitorLimit) && (IsValidMonitor(hMon))) { + pMonitorData->hmpMonitors[pMonitorData->monitorCounter] = hMon; + pMonitorData->monitorCounter++; } return TRUE; } -int WINAPI CollectMonitors(HMONITOR* hmpMonitors, int nNum) +static int WINAPI CollectMonitors(HMONITOR* hmpMonitors, int nNum) { - int retCode = 0; - if (NULL != hmpMonitors) { - - g_nMonitorCounter = 0; - g_nMonitorLimit = nNum; - g_hmpMonitors = hmpMonitors; - - ::EnumDisplayMonitors(NULL, NULL, clb_fCollectMonitors, 0L); - - retCode = g_nMonitorCounter; - - g_nMonitorCounter = 0; - g_nMonitorLimit = 0; - g_hmpMonitors = NULL; - + MonitorData monitorData; + monitorData.monitorCounter = 0; + monitorData.monitorLimit = nNum; + monitorData.hmpMonitors = hmpMonitors; + ::EnumDisplayMonitors(NULL, NULL, clb_fCollectMonitors, (LPARAM)&monitorData); + return monitorData.monitorCounter; + } else { + return 0; } - return retCode; } BOOL WINAPI MonitorBounds(HMONITOR hmMonitor, RECT* rpBounds) diff --git a/src/java.desktop/windows/native/libawt/windows/Devices.h b/src/java.desktop/windows/native/libawt/windows/Devices.h index b6fd56a777f..0972ef1414e 100644 --- a/src/java.desktop/windows/native/libawt/windows/Devices.h +++ b/src/java.desktop/windows/native/libawt/windows/Devices.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, 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 @@ -74,4 +74,6 @@ static CriticalSection arrayLock; BOOL WINAPI MonitorBounds (HMONITOR, RECT*); +int WINAPI CountMonitors (void); + #endif // _DEVICES_H_ diff --git a/src/java.desktop/windows/native/libawt/windows/awt_PlatformGraphicsInfo.cpp b/src/java.desktop/windows/native/libawt/windows/awt_PlatformGraphicsInfo.cpp new file mode 100644 index 00000000000..638cd100b1f --- /dev/null +++ b/src/java.desktop/windows/native/libawt/windows/awt_PlatformGraphicsInfo.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include "Devices.h" + +/* + * Class: sun_awt_PlatformGraphicsInfo + * Method: hasDisplays0 + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL +Java_sun_awt_PlatformGraphicsInfo_hasDisplays0(JNIEnv *env, jclass thisClass) { + return CountMonitors() > 0 ? JNI_TRUE : JNI_FALSE; +} diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp index 74df808ee30..7712147c43c 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp @@ -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 @@ -179,7 +179,9 @@ void AwtWin32GraphicsDevice::Initialize() } gpBitmapInfo->bmiHeader.biBitCount = 0; HDC hBMDC = this->GetDC(); + VERIFY(hBMDC != NULL); HBITMAP hBM = ::CreateCompatibleBitmap(hBMDC, 1, 1); + VERIFY(hBM != NULL); VERIFY(::GetDIBits(hBMDC, hBM, 0, 1, NULL, gpBitmapInfo, DIB_RGB_COLORS)); if (colorData->bitsperpixel > 8) { diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp index 6c949b564e9..9991427c75e 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp @@ -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 @@ -36,10 +36,8 @@ BOOL DWMIsCompositionEnabled(); void initScreens(JNIEnv *env) { - if (!Devices::UpdateInstance(env)) { JNU_ThrowInternalError(env, "Could not update the devices array."); - return; } } diff --git a/src/java.se/share/data/jdwp/jdwp.spec b/src/java.se/share/data/jdwp/jdwp.spec index 47a83270536..df23a602b13 100644 --- a/src/java.se/share/data/jdwp/jdwp.spec +++ b/src/java.se/share/data/jdwp/jdwp.spec @@ -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 @@ -1619,8 +1619,8 @@ JDWP "Java(tm) Debug Wire Protocol" (Reply (threadObject owner "The monitor owner, or null if it is not currently owned.") (int entryCount "The number of times the monitor has been entered.") - (Repeat waiters "The number of threads that are waiting for the monitor " - "0 if there is no current owner" + (Repeat waiters "The total number of threads that are waiting to enter or re-enter " + "the monitor, or waiting to be notified by the monitor." (threadObject thread "A thread waiting for this monitor.") ) ) @@ -1980,9 +1980,9 @@ JDWP "Java(tm) Debug Wire Protocol" ) (Command CurrentContendedMonitor=9 "Returns the object, if any, for which this thread is waiting. The " - "thread may be waiting to enter a monitor, or it may be waiting, via " - "the java.lang.Object.wait method, for another thread to invoke the " - "notify method. " + "thread may be waiting to enter the object's monitor, or in " + "java.lang.Object.wait waiting to re-enter the monitor after being " + "notified, interrupted, or timed-out." "The thread must be suspended, and the returned information is " "relevant only while the thread is suspended. " "Requires canGetCurrentContendedMonitor capability - see " diff --git a/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c b/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c index d0e943398e1..6b24c9faf4f 100644 --- a/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c +++ b/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2015, 2018 SAP SE. All rights reserved. + * Copyright (c) 2015, 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 @@ -39,13 +39,6 @@ #include "sun_tools_attach_VirtualMachineImpl.h" -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == -1) && (errno == EINTR)); \ -} while(0) - - #define ROOT_UID 0 /* diff --git a/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c b/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c index 56339ed0932..3aec395a1ba 100644 --- a/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c +++ b/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c @@ -38,12 +38,6 @@ #include "sun_tools_attach_VirtualMachineImpl.h" -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == -1) && (errno == EINTR)); \ -} while(0) - #define ROOT_UID 0 /* diff --git a/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c b/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c index d20a6f012f2..4e5b2aad695 100644 --- a/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c +++ b/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, 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 @@ -40,12 +40,6 @@ #include "sun_tools_attach_VirtualMachineImpl.h" -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == -1) && (errno == EINTR)); \ -} while(0) - #define ROOT_UID 0 /* diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/RelevantJavacOptions.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/RelevantJavacOptions.java index 88d1c875bc5..f619807f9bf 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/RelevantJavacOptions.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/RelevantJavacOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -112,7 +112,9 @@ static RelevantJavacOptions of(ProgramDescriptor program, String... runtimeArgs) programOptions.add(opt); subsequentOptions.add(opt); if (sourceOpt == null) { - throw new Fault(Errors.EnablePreviewRequiresSource); + String feature = String.valueOf(Runtime.version().feature()); + programOptions.addAll(List.of("--release", feature)); + subsequentOptions.addAll(List.of("--release", feature)); } } default -> { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties index 134d2ccd839..1bf209a7fd6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher.properties @@ -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 @@ -139,9 +139,6 @@ launcher.err.no.value.for.option=\ launcher.err.invalid.value.for.source=\ invalid value for --source option: {0} -launcher.err.enable.preview.requires.source=\ - --enable-preview must be used with --source - launcher.err.unnamed.pkg.not.allowed.named.modules=\ unnamed package is not allowed in named modules diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java index 9918503c7fd..9896cb738bb 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -64,25 +64,25 @@ private static Provider getSunECProvider() { } static ECParameterSpec getECParameterSpec(String name) { - return ECUtil.getECParameterSpec(getSunECProvider(), name); + return ECUtil.getECParameterSpec(name); } static ECParameterSpec getECParameterSpec(int keySize) { - return ECUtil.getECParameterSpec(getSunECProvider(), keySize); + return ECUtil.getECParameterSpec(keySize); } // Check that spec is a known supported curve and convert it to our // ECParameterSpec subclass. If not possible, return null. static ECParameterSpec getECParameterSpec(ECParameterSpec spec) { - return ECUtil.getECParameterSpec(getSunECProvider(), spec); + return ECUtil.getECParameterSpec(spec); } static ECParameterSpec decodeParameters(byte[] params) throws IOException { - return ECUtil.getECParameterSpec(getSunECProvider(), params); + return ECUtil.getECParameterSpec(params); } static byte[] encodeParameters(ECParameterSpec params) { - return ECUtil.encodeECParameterSpec(getSunECProvider(), params); + return ECUtil.encodeECParameterSpec(params); } static ECPoint decodePoint(byte[] encoded, EllipticCurve curve) throws IOException { @@ -220,7 +220,7 @@ protected PrivateKey engineGeneratePrivate(KeySpec keySpec) private PublicKey generatePublic(ECPoint point, ECParameterSpec params) throws PKCS11Exception { byte[] encodedParams = - ECUtil.encodeECParameterSpec(getSunECProvider(), params); + ECUtil.encodeECParameterSpec(params); byte[] encodedPoint = ECUtil.encodePoint(point, params.getCurve()); @@ -254,7 +254,7 @@ private PublicKey generatePublic(ECPoint point, ECParameterSpec params) private PrivateKey generatePrivate(BigInteger s, ECParameterSpec params) throws PKCS11Exception { byte[] encodedParams = - ECUtil.encodeECParameterSpec(getSunECProvider(), params); + ECUtil.encodeECParameterSpec(params); CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY), new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC), diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java index c3383f52190..d1377b807fe 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.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 @@ -1378,7 +1378,7 @@ private PrivateKey loadPkey(Session session, long oHandle) byte[] encodedParams = attrs[0].getByteArray(); try { ECParameterSpec params = - ECUtil.getECParameterSpec(null, encodedParams); + ECUtil.getECParameterSpec(encodedParams); keyLength = params.getCurve().getField().getFieldSize(); } catch (IOException e) { // we do not want to accept key with unsupported parameters @@ -1776,7 +1776,7 @@ private void storePkey(String alias, KeyStore.PrivateKeyEntry pke) } byte[] encodedParams = - ECUtil.encodeECParameterSpec(null, ecKey.getParams()); + ECUtil.encodeECParameterSpec(ecKey.getParams()); attrs = new CK_ATTRIBUTE[] { ATTR_TOKEN_TRUE, ATTR_CLASS_PKEY, diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java index cfe6b01a2e5..77783870df7 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java @@ -776,7 +776,7 @@ protected Object engineGetParameter(String param) protected AlgorithmParameters engineGetParameters() { if (this.sigParams != null) { try { - AlgorithmParameters ap = AlgorithmParameters.getInstance("RSASSA-PSS"); + AlgorithmParameters ap = AlgorithmParameters.getInstance("RSASSA-PSS", token.provider); ap.init(this.sigParams); return ap; } catch (GeneralSecurityException e) { diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java index e8dc0880d22..3e112bfe0ed 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java @@ -42,7 +42,9 @@ import com.sun.crypto.provider.ChaCha20Poly1305Parameters; +import com.sun.crypto.provider.DHParameters; import jdk.internal.misc.InnocuousThread; +import sun.security.rsa.PSSParameters; import sun.security.util.Debug; import sun.security.util.ResourcesMgr; import static sun.security.util.SecurityConstants.PROVIDER_VER; @@ -707,6 +709,14 @@ private static void register(Descriptor d) { "com.sun.crypto.provider.ChaCha20Poly1305Parameters", m(CKM_CHACHA20_POLY1305)); + dA(AGP, "RSASSA-PSS", + "sun.security.rsa.PSSParameters", + m(CKM_RSA_PKCS_PSS)); + + dA(AGP, "DiffieHellman", + "com.sun.crypto.provider.DHParameters", + m(CKM_DH_PKCS_DERIVE)); + d(KA, "DH", P11KeyAgreement, dhAlias, m(CKM_DH_PKCS_DERIVE)); @@ -1496,6 +1506,10 @@ public Object newInstance0(Object param) throws return new sun.security.util.GCMParameters(); } else if (algorithm == "ChaCha20-Poly1305") { return new ChaCha20Poly1305Parameters(); // from SunJCE + } else if (algorithm == "RSASSA-PSS") { + return new PSSParameters(); // from SunRsaSign + } else if (algorithm == "DiffieHellman") { + return new DHParameters(); // from SunJCE } else { throw new NoSuchAlgorithmException("Unsupported algorithm: " + algorithm); diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsParameters.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsParameters.java index 5943b70615c..3a0a3d76680 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsParameters.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, 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 @@ -90,9 +90,13 @@ protected HttpsParameters() {} * Returns a copy of the array of ciphersuites or {@code null} if none * have been set. * + * @deprecated It is recommended that the SSL parameters be configured and + * read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}. + * * @return a copy of the array of ciphersuites or {@code null} if none have * been set */ + @Deprecated(since = "23") public String[] getCipherSuites() { return cipherSuites != null ? cipherSuites.clone() : null; } @@ -100,8 +104,13 @@ public String[] getCipherSuites() { /** * Sets the array of ciphersuites. * + * @deprecated It is recommended that the SSL parameters be configured and + * read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}. Use + * {@link SSLParameters#setCipherSuites(String[])} instead. + * * @param cipherSuites the array of ciphersuites (or {@code null}) */ + @Deprecated(since = "23") public void setCipherSuites(String[] cipherSuites) { this.cipherSuites = cipherSuites != null ? cipherSuites.clone() : null; } @@ -110,9 +119,13 @@ public void setCipherSuites(String[] cipherSuites) { * Returns a copy of the array of protocols or {@code null} if none have been * set. * + * @deprecated It is recommended that the SSL parameters be configured and + * read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}. + * * @return a copy of the array of protocols or {@code null} if none have been * set */ + @Deprecated(since = "23") public String[] getProtocols() { return protocols != null ? protocols.clone() : null; } @@ -120,8 +133,13 @@ public String[] getProtocols() { /** * Sets the array of protocols. * + * @deprecated It is recommended that the SSL parameters be configured and + * read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}. Use + * {@link SSLParameters#setProtocols(String[])} instead. + * * @param protocols the array of protocols (or {@code null}) */ + @Deprecated(since = "23") public void setProtocols(String[] protocols) { this.protocols = protocols != null ? protocols.clone() : null; } @@ -129,8 +147,12 @@ public void setProtocols(String[] protocols) { /** * Returns whether client authentication should be requested. * + * @deprecated It is recommended that the SSL parameters be configured and + * read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}. + * * @return whether client authentication should be requested */ + @Deprecated(since = "23") public boolean getWantClientAuth() { return wantClientAuth; } @@ -139,17 +161,27 @@ public boolean getWantClientAuth() { * Sets whether client authentication should be requested. Calling this * method clears the {@code needClientAuth} flag. * + * @deprecated It is recommended that the SSL parameters be configured and + * read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}. Use + * {@link SSLParameters#setWantClientAuth(boolean)} instead. + * * @param wantClientAuth whether client authentication should be requested */ + @Deprecated(since = "23") public void setWantClientAuth(boolean wantClientAuth) { this.wantClientAuth = wantClientAuth; + this.needClientAuth = false; } /** * Returns whether client authentication should be required. * + * @deprecated It is recommended that the SSL parameters be configured and + * read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}. + * * @return whether client authentication should be required */ + @Deprecated(since = "23") public boolean getNeedClientAuth() { return needClientAuth; } @@ -158,9 +190,15 @@ public boolean getNeedClientAuth() { * Sets whether client authentication should be required. Calling this method * clears the {@code wantClientAuth} flag. * + * @deprecated It is recommended that the SSL parameters be configured and + * read through the use of {@link #setSSLParameters(SSLParameters) SSLParameters}. Use + * {@link SSLParameters#setNeedClientAuth(boolean)} instead. + * * @param needClientAuth whether client authentication should be required */ + @Deprecated(since = "23") public void setNeedClientAuth(boolean needClientAuth) { this.needClientAuth = needClientAuth; + this.wantClientAuth = false; } } diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java index b740189b3e7..5cc16befa96 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java @@ -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 @@ -66,6 +66,7 @@ class SSLStreams { wrapper = new EngineWrapper (chan, engine); } + @SuppressWarnings("deprecation") private void configureEngine(HttpsConfigurator cfg, InetSocketAddress addr){ if (cfg != null) { Parameters params = new Parameters (cfg, addr); @@ -85,8 +86,11 @@ private void configureEngine(HttpsConfigurator cfg, InetSocketAddress addr){ ); } catch (IllegalArgumentException e) { /* LOG */} } - engine.setNeedClientAuth (params.getNeedClientAuth()); - engine.setWantClientAuth (params.getWantClientAuth()); + if (params.getNeedClientAuth()) { + engine.setNeedClientAuth(true); + } else if (params.getWantClientAuth()) { + engine.setWantClientAuth(true); + } if (params.getProtocols() != null) { try { engine.setEnabledProtocols ( diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java index 9b6b0e9c352..9f611b0dfce 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java @@ -232,6 +232,7 @@ public enum CPUFeature implements CPUFeatureName { CET_IBT, CET_SS, AVX512_IFMA, + AVX_IFMA, } private final EnumSet features; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java index 37762e759fc..fff2a6dc2b2 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, 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 @@ -40,10 +40,12 @@ public interface ResolvedJavaType extends JavaType, ModifiersProvider, Annotated boolean hasFinalizer(); /** - * Checks whether this type has any finalizable subclasses so far. Any decisions based on this - * information require the registration of a dependency, since this information may change. + * Checks whether this type might have finalizable subclasses. Any decisions based on a + * negative answer require the registration of a dependency, since this information may change. + * For example, dynamic class loading can later load a finalizable subclass. * - * @return {@code true} if this class has any subclasses with finalizers + * @return an {@link AssumptionResult} specifying if this class may have any subclasses with + * finalizers along with any assumptions under which this answer holds */ AssumptionResult hasFinalizableSubclass(); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java index bc0f1e52bbd..684e198ef1b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java @@ -32,8 +32,6 @@ import com.sun.source.doctree.DeprecatedTree; import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.Text; @@ -83,10 +81,19 @@ protected void addContentSelectors(Content target) { if (releases.size() > 1) { Content tabs = HtmlTree.DIV(HtmlStyle.checkboxes, contents.getContent( "doclet.Deprecated_API_Checkbox_Label")); - for (int i = 0; i < releases.size(); i++) { - // Table column ids are 1-based - tabs.add(Text.of(" ")).add(getReleaseCheckbox(releases.get(i), i + 1)); + // Table column ids are 1-based + int index = 1; + for (String release : releases) { + // Empty string represents other/uncategorized releases. Since we can't make any assumptions + // about release names this is arguably the safest way to avoid naming collisions. + Content label = !release.isEmpty() + ? Text.of(release) + : contents.getContent("doclet.Deprecated_API_Checkbox_Other_Releases"); + String id = release.isEmpty() ? ID_OTHER : String.valueOf(index++); + tabs.add(Text.of(" ")).add(getCheckbox(label, id, "release-")); } + tabs.add(Text.of(" ")).add(getCheckbox( + contents.getContent("doclet.Deprecated_API_Checkbox_All_Releases"), ID_ALL, "release-")); target.add(tabs); } } @@ -97,23 +104,6 @@ protected void addExtraSection(Content content) { TERMINALLY_DEPRECATED_KEY, "doclet.Element", content); } - private Content getReleaseCheckbox(String name, int index) { - // Empty string represents other/uncategorized releases. Since we can't make any assumptions - // about release names this is arguably the safest way to avoid naming collisions. - boolean isOtherReleases = name.isEmpty(); - Content releaseLabel = isOtherReleases - ? contents.getContent("doclet.Deprecated_API_Checkbox_Other_Releases") - : Text.of(name); - HtmlId htmlId = HtmlId.of("release-" + index); - String releaseId = isOtherReleases ? "" : Integer.toString(index); - return HtmlTree.LABEL(htmlId.name(), - HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, htmlId) - .put(HtmlAttr.CHECKED, "") - .put(HtmlAttr.ONCLICK, - "toggleGlobal(this, '" + releaseId + "', 3)")) - .add(HtmlTree.SPAN(releaseLabel)); - } - @Override protected void addExtraIndexLink(Content target) { if (!builder.getForRemoval().isEmpty()) { @@ -139,7 +129,6 @@ protected void addTableTabs(Table table, String headingKey) { } if (releases.size() > 1) { table.setDefaultTab(getTableCaption(headingKey)) - .setAlwaysShowDefaultTab(true) .setRenderTabs(false); for (String release : releases) { Content tab = TERMINALLY_DEPRECATED_KEY.equals(headingKey) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 4eb05aeb695..3962631fb49 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -113,6 +113,7 @@ import jdk.javadoc.internal.doclint.HtmlTag; import static com.sun.source.doctree.DocTree.Kind.COMMENT; +import static com.sun.source.doctree.DocTree.Kind.START_ELEMENT; import static com.sun.source.doctree.DocTree.Kind.TEXT; @@ -1171,21 +1172,28 @@ private void addCommentTags(Element element, List tags, boole } } - boolean ignoreNonInlineTag(DocTree dtree) { + boolean ignoreNonInlineTag(DocTree dtree, List openTags) { Name name = null; - if (dtree.getKind() == Kind.START_ELEMENT) { - StartElementTree setree = (StartElementTree)dtree; - name = setree.getName(); - } else if (dtree.getKind() == Kind.END_ELEMENT) { - EndElementTree eetree = (EndElementTree)dtree; - name = eetree.getName(); + Kind kind = dtree.getKind(); + if (kind == Kind.START_ELEMENT) { + name = ((StartElementTree)dtree).getName(); + } else if (kind == Kind.END_ELEMENT) { + name = ((EndElementTree)dtree).getName(); } if (name != null) { HtmlTag htmlTag = HtmlTag.get(name); - if (htmlTag != null && - htmlTag.blockType != jdk.javadoc.internal.doclint.HtmlTag.BlockType.INLINE) { - return true; + if (htmlTag != null) { + if (htmlTag.blockType != HtmlTag.BlockType.INLINE) { + return true; + } + // Keep track of open inline tags that need to be closed, see 8326332 + if (kind == START_ELEMENT && htmlTag.endKind == HtmlTag.EndKind.REQUIRED) { + openTags.add(name); + } else if (kind == Kind.END_ELEMENT && !openTags.isEmpty() + && openTags.getLast().equals(name)) { + openTags.removeLast(); + } } } return false; @@ -1257,6 +1265,7 @@ public ContentBuilder add(CharSequence text) { CommentHelper ch = utils.getCommentHelper(element); configuration.tagletManager.checkTags(element, trees); commentRemoved = false; + List openTags = new ArrayList<>(); for (ListIterator iterator = trees.listIterator(); iterator.hasNext();) { boolean isFirstNode = !iterator.hasPrevious(); @@ -1265,14 +1274,16 @@ public ContentBuilder add(CharSequence text) { if (context.isFirstSentence) { // Ignore block tags - if (ignoreNonInlineTag(tag)) + if (ignoreNonInlineTag(tag, openTags)) { continue; + } // Ignore any trailing whitespace OR whitespace after removed html comment if ((isLastNode || commentRemoved) && tag.getKind() == TEXT - && ((tag instanceof TextTree tt) && tt.getBody().isBlank())) + && ((tag instanceof TextTree tt) && tt.getBody().isBlank())) { continue; + } // Ignore any leading html comments if ((isFirstNode || commentRemoved) && tag.getKind() == COMMENT) { @@ -1466,6 +1477,10 @@ protected Boolean defaultAction(DocTree node, Content content) { if (allDone) break; } + // Close any open inline tags + while (!openTags.isEmpty()) { + result.add(RawHtml.endElement(openTags.removeLast())); + } return result; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java index f2acb86f19e..87a842890a4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java @@ -25,6 +25,7 @@ package jdk.javadoc.internal.doclets.formats.html; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; @@ -96,28 +97,40 @@ public Content getLink(HtmlLinkInfo linkInfo) { // handles primitives, no types and error types @Override protected Content defaultAction(TypeMirror type, HtmlLinkInfo linkInfo) { - link.add(utils.getTypeName(type, false)); + link.add(getTypeAnnotationLinks(linkInfo)); + link.add(utils.getTypeSignature(type, false, false)); return link; } - int currentDepth = 0; @Override public Content visitArray(ArrayType type, HtmlLinkInfo linkInfo) { - // keep track of the dimension depth and replace the last dimension - // specifier with varargs, when the stack is fully unwound. - currentDepth++; - var componentType = type.getComponentType(); - visit(componentType, linkInfo.forType(componentType)); - currentDepth--; - if (utils.isAnnotated(type)) { - link.add(" "); - link.add(getTypeAnnotationLinks(linkInfo)); + // int @A [] @B [] has @A on int[][] and @B on int[], + // encounter order is @A @B so print in FIFO order + var deque = new ArrayDeque(1); + while (true) { + deque.add(type); + var component = type.getComponentType(); + if (component instanceof ArrayType arrayType) { + type = arrayType; + } else { + visit(component, linkInfo.forType(component)); + break; + } } - // use vararg if required - if (linkInfo.isVarArg() && currentDepth == 0) { - link.add("..."); - } else { - link.add("[]"); + + while (!deque.isEmpty()) { + var currentType = deque.remove(); + if (utils.isAnnotated(currentType)) { + link.add(" "); + link.add(getTypeAnnotationLinks(linkInfo.forType(currentType))); + } + + // use vararg if required + if (linkInfo.isVarArg() && deque.isEmpty()) { + link.add("..."); + } else { + link.add("[]"); + } } return link; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NewAPIListWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NewAPIListWriter.java index d035e0f1d95..a976ad21548 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NewAPIListWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NewAPIListWriter.java @@ -79,21 +79,17 @@ protected String getTitleKey() { @Override protected void addContentSelectors(Content content) { - List releases = configuration.newAPIPageBuilder.releases; + List releases = builder.releases; if (releases.size() > 1) { Content tabs = HtmlTree.DIV(HtmlStyle.checkboxes, contents.getContent("doclet.New_API_Checkbox_Label")); - for (int i = 0; i < releases.size(); i++) { - int releaseIndex = i + 1; - String release = releases.get(i); - HtmlId htmlId = HtmlId.of("release-" + releaseIndex); - tabs.add(Text.of(" ")).add(HtmlTree.LABEL(htmlId.name(), - HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, htmlId) - .put(HtmlAttr.CHECKED, "") - .put(HtmlAttr.ONCLICK, - "toggleGlobal(this, '" + releaseIndex + "', 3)")) - .add(HtmlTree.SPAN(Text.of(release)))); + // Table column ids are 1-based + int index = 1; + for (String release : releases) { + tabs.add(Text.of(" ")).add(getCheckbox(Text.of(release), String.valueOf(index++), "release-")); } + Content label = contents.getContent("doclet.New_API_Checkbox_All_Releases"); + tabs.add(Text.of(" ")).add(getCheckbox(label, ID_ALL, "release-")); content.add(tabs); } } @@ -104,7 +100,6 @@ protected void addTableTabs(Table table, String headingKey) { List releases = builder.releases; if (releases.size() > 1) { table.setDefaultTab(getTableCaption(headingKey)) - .setAlwaysShowDefaultTab(true) .setRenderTabs(false); for (String release : releases) { table.addTab( diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PreviewListWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PreviewListWriter.java index 0f14098a326..911df132de4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PreviewListWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PreviewListWriter.java @@ -33,8 +33,7 @@ import com.sun.source.doctree.DocTree; import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; +import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.Text; @@ -80,21 +79,17 @@ protected String getTitleKey() { protected void addContentSelectors(Content target) { Set jeps = builder.getJEPs(); if (!jeps.isEmpty()) { - int index = 0; + int index = 1; target.add(HtmlTree.P(contents.getContent("doclet.Preview_API_Checkbox_Label"))); - Content list = HtmlTree.UL(HtmlStyle.previewFeatureList); + Content list = HtmlTree.UL(HtmlStyle.previewFeatureList).addStyle(HtmlStyle.checkboxes); for (var jep : jeps) { - index++; - HtmlId htmlId = HtmlId.of("feature-" + index); String jepUrl = resources.getText("doclet.Preview_JEP_URL", jep.number()); - list.add(HtmlTree.LI(HtmlTree.LABEL(htmlId.name(), - HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, htmlId) - .put(HtmlAttr.CHECKED, "") - .put(HtmlAttr.ONCLICK, - "toggleGlobal(this, '" + index + "', 3)")) - .add(HtmlTree.SPAN(Text.of(jep.number() + ": ")) - .add(HtmlTree.A(jepUrl, Text.of(jep.title() + " (" + jep.status() + ")")))))); + Content label = new ContentBuilder(Text.of(jep.number() + ": ")) + .add(HtmlTree.A(jepUrl, Text.of(jep.title() + " (" + jep.status() + ")"))); + list.add(HtmlTree.LI(getCheckbox(label, String.valueOf(index++), "feature-"))); } + Content label = contents.getContent("doclet.Preview_API_Checkbox_Toggle_All"); + list.add(HtmlTree.LI(getCheckbox(label, ID_ALL, "feature-"))); target.add(list); } } @@ -113,7 +108,6 @@ protected void addComments(Element e, Content desc) { protected void addTableTabs(Table table, String headingKey) { table.setGridStyle(HtmlStyle.threeColumnSummary) .setDefaultTab(getTableCaption(headingKey)) - .setAlwaysShowDefaultTab(true) .setRenderTabs(false); for (PreviewAPIListBuilder.JEP jep : builder.getJEPs()) { table.addTab(Text.EMPTY, element -> jep == builder.getJEP(element)); @@ -122,7 +116,7 @@ protected void addTableTabs(Table table, String headingKey) { @Override protected Content getExtraContent(Element element) { - PreviewAPIListBuilder.JEP jep = configuration.previewAPIListBuilder.getJEP(element); + PreviewAPIListBuilder.JEP jep = builder.getJEP(element); return jep == null ? Text.EMPTY : Text.of(jep.title()); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SummaryListWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SummaryListWriter.java index c478907270c..ffe0350678d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SummaryListWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SummaryListWriter.java @@ -32,6 +32,7 @@ import javax.lang.model.element.PackageElement; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.Script; @@ -54,6 +55,9 @@ */ public abstract class SummaryListWriter extends SubWriterHolderWriter { + final protected String ID_OTHER = "other"; + final protected String ID_ALL = "all"; + protected String getHeadingKey(SummaryElementKind kind) { return switch (kind) { case MODULE -> "doclet.Modules"; @@ -294,6 +298,25 @@ protected Content getSummaryLink(Element e) { return writer.getSummaryLink(e); } + /** + * Create a checkbox input element and associated label for selecting content on + * a summary page. + * + * @param label The label + * @param id the id of the selected content + * @param htmlPrefix the prefix for the HTML id + * @return a content object containing the checkbox input + */ + protected Content getCheckbox(Content label, String id, String htmlPrefix) { + String htmlId = htmlPrefix + id; + return HtmlTree.LABEL(htmlId, + HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, HtmlId.of(htmlId)) + .put(HtmlAttr.CHECKED, "") + .put(HtmlAttr.ONCLICK, + "toggleGlobal(this, '" + id + "', 3)")) + .add(HtmlTree.SPAN(label)); + } + /** * Add an extra optional section to the content. * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java index cd401cbad95..339cfbf6f72 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java @@ -84,7 +84,6 @@ public class Table extends Content { private HtmlStyle gridStyle; private final List bodyRows; private HtmlId id; - private boolean alwaysShowDefaultTab = false; /** * A record containing the data for a table tab. @@ -147,16 +146,6 @@ public Table setDefaultTab(Content label) { return this; } - /** - * Sets whether to display the default tab even if tabs are empty or only contain a single tab. - * @param showDefaultTab true if default tab should always be shown - * @return this object - */ - public Table setAlwaysShowDefaultTab(boolean showDefaultTab) { - this.alwaysShowDefaultTab = showDefaultTab; - return this; - } - /** * Allows to set whether tabs should be rendered for this table. Some pages use their * own controls to select table categories, in which case the tabs are omitted. @@ -385,7 +374,7 @@ private Content toContent() { } var table = HtmlTree.DIV(tableStyle).addStyle(gridStyle); - if ((tabs == null || occurringTabs.size() == 1) && !alwaysShowDefaultTab) { + if ((tabs == null || occurringTabs.size() == 1) && renderTabs) { if (tabs == null) { main.add(caption); } else { @@ -401,15 +390,13 @@ private Content toContent() { HtmlId defaultTabId = HtmlIds.forTab(id, 0); if (renderTabs) { tablist.add(createTab(defaultTabId, HtmlStyle.activeTableTab, true, defaultTab)); - } else { - tablist.add(getCaption(defaultTab)); - } - if (renderTabs) { for (var tab : tabs) { if (occurringTabs.contains(tab)) { tablist.add(createTab(HtmlIds.forTab(id, tab.index()), HtmlStyle.tableTab, false, tab.label())); } } + } else { + tablist.add(getCaption(defaultTab)); } if (id == null) { throw new IllegalStateException("no id set for table"); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index e14a2ef34cb..ef09e6df90f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -97,20 +97,23 @@ function sortTable(header, columnIndex, columns) { // Toggles the visibility of a table category in all tables in a page function toggleGlobal(checkbox, selected, columns) { - var display = checkbox.checked ? '' : 'none'; - document.querySelectorAll("div.table-tabs").forEach(function(t) { - var id = t.parentElement.getAttribute("id"); - var selectedClass = id + "-tab" + selected; - // if selected is empty string it selects all uncategorized entries - var selectUncategorized = !Boolean(selected); + const display = checkbox.checked ? '' : 'none'; + const selectOther = selected === "other"; + const selectAll = selected === "all"; + if (selectAll) { + document.querySelectorAll('.checkboxes input[type="checkbox"]').forEach(c => { + c.checked = checkbox.checked; + }); + } + document.querySelectorAll("div.table-tabs").forEach(t => { + const id = t.parentElement.getAttribute("id"); + const selectedClass = id + "-tab" + (selectOther ? "" : selected); var visible = 0; - document.querySelectorAll('div.' + id) + t.parentElement.querySelectorAll('div.' + id) .forEach(function(elem) { - if (selectUncategorized) { - if (elem.className.indexOf(selectedClass) === -1) { - elem.style.display = display; - } - } else if (elem.classList.contains(selectedClass)) { + if (selectAll + || (!selectOther && elem.classList.contains(selectedClass)) + || (selectOther && elem.className.indexOf(selectedClass) < 0)) { elem.style.display = display; } if (elem.style.display === '') { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties index 23bf1f3c194..8e224cecb36 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties @@ -116,17 +116,20 @@ doclet.tag.invalid_input=invalid input: ''{0}'' doclet.tag.invalid=invalid @{0} doclet.Deprecated_API=Deprecated API doclet.Deprecated_API_Checkbox_Label=Show API deprecated in: +doclet.Deprecated_API_Checkbox_All_Releases=all doclet.Deprecated_API_Checkbox_Other_Releases=other doclet.Deprecated_Elements=Deprecated {0} doclet.Deprecated_Elements_Release_Column_Header=Deprecated in doclet.Deprecated_In_Release=Deprecated in {0} doclet.New_API=New API doclet.New_API_Checkbox_Label=Show API added in: +doclet.New_API_Checkbox_All_Releases=all doclet.New_Elements=New {0} doclet.New_Elements_Release_Column_Header=Added in doclet.New_Label=New doclet.Preview_API=Preview API doclet.Preview_API_Checkbox_Label=Show preview API for: +doclet.Preview_API_Checkbox_Toggle_All=Toggle all doclet.Preview_JEP_URL=https://openjdk.org/jeps/{0} doclet.Preview_Label=Preview doclet.Preview_Mark=PREVIEW diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java index 9a47111677f..fd1b97161c7 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java @@ -310,8 +310,8 @@ List ownedMonitorsAndFrames() * for which this thread is currently waiting. * The thread can be waiting for a monitor through entry into a * synchronized method, the synchronized statement, or - * {@link Object#wait}. The {@link #status} method can be used - * to differentiate between the first two cases and the third. + * {@link Object#wait} waiting to re-enter the monitor + * after being notified, interrupted, or timed-out. *

      * Not all target virtual machines support this operation. * Use {@link VirtualMachine#canGetCurrentContendedMonitor()} diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/ObjectReferenceImpl.c b/src/jdk.jdwp.agent/share/native/libjdwp/ObjectReferenceImpl.c index 71d9ea8c0ed..7b1ada77581 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/ObjectReferenceImpl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/ObjectReferenceImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, 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 @@ -219,14 +219,19 @@ monitorInfo(PacketInputStream *in, PacketOutputStream *out) int i; (void)outStream_writeObjectRef(env, out, info.owner); (void)outStream_writeInt(out, info.entry_count); - (void)outStream_writeInt(out, info.waiter_count); + (void)outStream_writeInt(out, info.waiter_count + info.notify_waiter_count); for (i = 0; i < info.waiter_count; i++) { (void)outStream_writeObjectRef(env, out, info.waiters[i]); } + for (i = 0; i < info.notify_waiter_count; i++) { + (void)outStream_writeObjectRef(env, out, info.notify_waiters[i]); + } } if (info.waiters != NULL ) jvmtiDeallocate(info.waiters); + if (info.notify_waiters != NULL ) + jvmtiDeallocate(info.notify_waiters); } END_WITH_LOCAL_REFS(env); diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 5628f8b44db..00c34844c98 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -1549,7 +1549,7 @@ threadControl_resumeAll(void) * resume any vthread with a suspendCount == 1, and we want to ignore * vthreads with a suspendCount > 0. Therefore we don't want * ResumeAllVirtualThreads resuming these vthreads. We must first - * build a list of them to pass to as the exclude list. + * build a list of them to pass as the exclude list. */ enumerateOverThreadList(env, &runningVThreads, excludeCountHelper, &excludeCnt); @@ -2117,28 +2117,25 @@ threadControl_onEventHandlerEntry(jbyte sessionID, EventInfo *evinfo, jobject cu } static void -doPendingTasks(JNIEnv *env, ThreadNode *node) +doPendingTasks(JNIEnv *env, jthread thread, int pendingInterrupt, jobject pendingStop) { /* - * Take care of any pending interrupts/stops, and clear out - * info on pending interrupts/stops. + * Take care of any pending interrupts/stops. */ - if (node->pendingInterrupt) { + if (pendingInterrupt) { JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread) - (gdata->jvmti, node->thread); + (gdata->jvmti, thread); /* * TO DO: Log error */ - node->pendingInterrupt = JNI_FALSE; } - if (node->pendingStop != NULL) { + if (pendingStop != NULL) { JVMTI_FUNC_PTR(gdata->jvmti,StopThread) - (gdata->jvmti, node->thread, node->pendingStop); + (gdata->jvmti, thread, pendingStop); /* * TO DO: Log error */ - tossGlobalRef(env, &(node->pendingStop)); } } @@ -2147,35 +2144,44 @@ threadControl_onEventHandlerExit(EventIndex ei, jthread thread, struct bag *eventBag) { ThreadNode *node; + JNIEnv *env = getEnv(); log_debugee_location("threadControl_onEventHandlerExit()", thread, NULL, 0); if (ei == EI_THREAD_END) { - eventHandler_lock(); /* for proper lock order */ - } - debugMonitorEnter(threadLock); - - node = findRunningThread(thread); - if (node == NULL) { - EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted"); - } else { - JNIEnv *env; - - env = getEnv(); - if (ei == EI_THREAD_END) { - removeThread(env, node); - node = NULL; /* has been freed */ - } else { - /* No point in doing this if the thread is about to die.*/ - doPendingTasks(env, node); - node->eventBag = eventBag; - node->current_ei = 0; + eventHandler_lock(); /* for proper lock order - see removeThread() call below */ + debugMonitorEnter(threadLock); + node = findRunningThread(thread); + if (node == NULL) { + EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted"); } - } - - debugMonitorExit(threadLock); - if (ei == EI_THREAD_END) { + removeThread(env, node); // Grabs handlerLock, thus the reason for first grabbing it above. + node = NULL; // We exiting the threadLock. No longer safe to access. + debugMonitorExit(threadLock); eventHandler_unlock(); + } else { + debugMonitorEnter(threadLock); + node = findRunningThread(thread); + if (node == NULL) { + EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted"); + } + /* No need to do the following if the thread is about to die.*/ + int pendingInterrupt = node->pendingInterrupt; + jobject pendingStop = node->pendingStop; + jthread thread = node->thread; + node->pendingInterrupt = JNI_FALSE; + node->pendingStop = NULL; + node->eventBag = eventBag; + node->current_ei = 0; + node = NULL; // We exiting the threadLock. No longer safe to access. + // doPendingTasks() may do an upcall to java, and we don't want to hold any + // locks when doing that. Thus we got all our node updates done first + // and can now exit the threadLock. + debugMonitorExit(threadLock); + doPendingTasks(env, thread, pendingInterrupt, pendingStop); + if (pendingStop != NULL) { + tossGlobalRef(env, &pendingStop); + } } } @@ -2219,29 +2225,9 @@ threadControl_applicationThreadStatus(jthread thread, jvmtiError threadControl_interrupt(jthread thread) { - ThreadNode *node; - jvmtiError error; - - error = JVMTI_ERROR_NONE; - log_debugee_location("threadControl_interrupt()", thread, NULL, 0); - debugMonitorEnter(threadLock); - - node = findThread(&runningThreads, thread); - if ((node == NULL) || !HANDLING_EVENT(node)) { - error = JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread) - (gdata->jvmti, thread); - } else { - /* - * Hold any interrupts until after the event is processed. - */ - node->pendingInterrupt = JNI_TRUE; - } - - debugMonitorExit(threadLock); - - return error; + return JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)(gdata->jvmti, thread); } void @@ -2308,26 +2294,20 @@ threadControl_saveCLEInfo(JNIEnv *env, jthread thread, EventIndex ei, debugMonitorExit(threadLock); } +/* + * Support for getting an interrupt in an application thread while doing + * a debugMonitorWait(). + */ void threadControl_setPendingInterrupt(jthread thread) { ThreadNode *node; - /* - * vmTestbase/nsk/jdb/kill/kill001/kill001.java seems to be the only code - * that triggers this function. Is uses ThreadReference.Stop. - * - * Since ThreadReference.Stop is not supported for vthreads, we should never - * get here with a vthread. - */ - JDI_ASSERT(!isVThread(thread)); - debugMonitorEnter(threadLock); - node = findThread(&runningThreads, thread); - if (node != NULL) { - node->pendingInterrupt = JNI_TRUE; - } + node = findRunningThread(thread); + JDI_ASSERT(node != NULL); + node->pendingInterrupt = JNI_TRUE; debugMonitorExit(threadLock); } @@ -2512,23 +2492,13 @@ threadControl_setEventMode(jvmtiEventMode mode, EventIndex ei, jthread thread) } /* - * Returns the current thread, if the thread has generated at least - * one event, and has not generated a thread end event. + * Returns the current thread. */ jthread threadControl_currentThread(void) { - jthread thread; - - debugMonitorEnter(threadLock); - { - ThreadNode *node; - - node = findThread(&runningThreads, NULL); - thread = (node == NULL) ? NULL : node->thread; - } - debugMonitorExit(threadLock); - + jthread thread = NULL; + jvmtiError error = JVMTI_FUNC_PTR(gdata->jvmti,GetCurrentThread)(gdata->jvmti, &thread); return thread; } @@ -2670,6 +2640,7 @@ dumpThread(ThreadNode *node) { tty_message("\tthreadState: 0x%x", getThreadState(node)); tty_message("\ttoBeResumed: %d", node->toBeResumed); tty_message("\tis_vthread: %d", node->is_vthread); + tty_message("\tpendingInterrupt: %d", node->pendingInterrupt); tty_message("\tcurrentInvoke.pending: %d", node->currentInvoke.pending); tty_message("\tcurrentInvoke.started: %d", node->currentInvoke.started); tty_message("\tcurrentInvoke.available: %d", node->currentInvoke.available); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Function.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Function.java index 2cd1fd82825..9540834b87a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Function.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Function.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -275,9 +275,6 @@ public void add(Object value) { @Override public Object result() { - if (maximum == null) { - System.out.println("Why"); - } return maximum; } } diff --git a/src/jdk.jpackage/macosx/native/applauncher/MacLauncher.cpp b/src/jdk.jpackage/macosx/native/applauncher/MacLauncher.cpp index 1d315b9f02e..5c9ca8e9a04 100644 --- a/src/jdk.jpackage/macosx/native/applauncher/MacLauncher.cpp +++ b/src/jdk.jpackage/macosx/native/applauncher/MacLauncher.cpp @@ -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 @@ -23,13 +23,14 @@ * questions. */ -#include "AppLauncher.h" #include "app.h" +#include "AppLauncher.h" +#include "ErrorHandling.h" #include "FileUtils.h" +#include "jni.h" +#include "JvmLauncher.h" #include "PackageFile.h" #include "UnixSysInfo.h" -#include "JvmLauncher.h" -#include "ErrorHandling.h" namespace { @@ -89,7 +90,7 @@ void initJvmLauncher() { } // namespace -int main(int argc, char *argv[]) { +JNIEXPORT int main(int argc, char *argv[]) { if (jvmLauncher) { // This is the call from the thread spawned by JVM. // Skip initialization phase as we have done this already in the first diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 990845c1ce7..55d30349ee5 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -957,7 +957,7 @@ TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_largepages) { #ifdef AIX // On Aix, we should fail attach attempts not aligned to segment boundaries (256m) TEST_VM(os, aix_reserve_at_non_shmlba_aligned_address) { - if (Use64KPages && Use64KPagesThreshold == 0) { + if (Use64KPages) { char* p = os::attempt_reserve_memory_at((char*)0x1f00000, M); ASSERT_EQ(p, nullptr); // should have failed p = os::attempt_reserve_memory_at((char*)((64 * G) + M), M); diff --git a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp index a6e1ed1f239..aad6acc095a 100644 --- a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp +++ b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. All rights reserved. - * 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 @@ -35,10 +35,6 @@ #include "testutils.hpp" #include "unittest.hpp" -// On AIX, these tests make no sense as long as JDK-8315321 remains unfixed since the attach -// addresses are not predictable. -#ifndef AIX - // Must be the same as in os::attempt_reserve_memory_between() struct ARMB_constants { static constexpr uintptr_t absolute_max = NOT_LP64(G * 3) LP64_ONLY(G * 128 * 1024); @@ -55,6 +51,17 @@ static void release_if_needed(char* p, size_t s) { } } +// 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 +static size_t allocation_granularity() { + return + AIX_ONLY(os::vm_page_size() == 4*K ? 4*K : 256*M) + NOT_AIX(os::vm_allocation_granularity()); +} + #define ERRINFO "addr: " << ((void*)addr) << " min: " << ((void*)min) << " max: " << ((void*)max) \ << " bytes: " << bytes << " alignment: " << alignment << " randomized: " << randomized @@ -62,7 +69,7 @@ static char* call_attempt_reserve_memory_between(char* min, char* max, size_t by char* const addr = os::attempt_reserve_memory_between(min, max, bytes, alignment, randomized); if (addr != nullptr) { EXPECT_TRUE(is_aligned(addr, alignment)) << ERRINFO; - EXPECT_TRUE(is_aligned(addr, os::vm_allocation_granularity())) << ERRINFO; + EXPECT_TRUE(is_aligned(addr, allocation_granularity())) << ERRINFO; EXPECT_LE(addr, max - bytes) << ERRINFO; EXPECT_LE(addr, (char*)ARMB_constants::absolute_max - bytes) << ERRINFO; EXPECT_GE(addr, min) << ERRINFO; @@ -178,7 +185,7 @@ struct SpaceWithHole { // Test that, when reserving in a range randomly, we get random results static void test_attempt_reserve_memory_between_random_distribution(unsigned num_possible_attach_points) { - const size_t ag = os::vm_allocation_granularity(); + const size_t ag = allocation_granularity(); // Create a space that is mostly a hole bordered by two small stripes of reserved memory, with // as many attach points as we need. @@ -257,7 +264,7 @@ TEST_VM(os, attempt_reserve_memory_randomization_threshold) { constexpr int threshold = ARMB_constants::min_random_value_range; const size_t ps = os::vm_page_size(); - const size_t ag = os::vm_allocation_granularity(); + const size_t ag = allocation_granularity(); SpaceWithHole space(ag * (threshold + 2), ag, ag * threshold); if (!space.reserve()) { @@ -275,12 +282,12 @@ TEST_VM(os, attempt_reserve_memory_randomization_threshold) { // Test all possible combos TEST_VM(os, attempt_reserve_memory_between_combos) { const size_t large_end = NOT_LP64(G) LP64_ONLY(64 * G); - for (size_t range_size = os::vm_allocation_granularity(); range_size <= large_end; range_size *= 2) { + for (size_t range_size = allocation_granularity(); range_size <= large_end; range_size *= 2) { for (size_t start_offset = 0; start_offset <= large_end; start_offset += (large_end / 2)) { char* const min = (char*)(uintptr_t)start_offset; char* const max = min + range_size; for (size_t bytes = os::vm_page_size(); bytes < large_end; bytes *= 2) { - for (size_t alignment = os::vm_allocation_granularity(); alignment < large_end; alignment *= 2) { + for (size_t alignment = allocation_granularity(); alignment < large_end; alignment *= 2) { test_attempt_reserve_memory_between(min, max, bytes, alignment, true, Expect::dontcare(), __LINE__); test_attempt_reserve_memory_between(min, max, bytes, alignment, false, Expect::dontcare(), __LINE__); } @@ -291,7 +298,7 @@ TEST_VM(os, attempt_reserve_memory_between_combos) { TEST_VM(os, attempt_reserve_memory_randomization_cornercases) { const size_t ps = os::vm_page_size(); - const size_t ag = os::vm_allocation_granularity(); + const size_t ag = allocation_granularity(); constexpr size_t quarter_address_space = NOT_LP64(nth_bit(30)) LP64_ONLY(nth_bit(62)); // Zero-sized range @@ -331,7 +338,7 @@ TEST_VM(os, attempt_reserve_memory_randomization_cornercases) { // as long as the range size is smaller than the number of probe attempts TEST_VM(os, attempt_reserve_memory_between_small_range_fill_hole) { const size_t ps = os::vm_page_size(); - const size_t ag = os::vm_allocation_granularity(); + const size_t ag = allocation_granularity(); constexpr int num = ARMB_constants::max_attempts; for (int i = 0; i < num; i ++) { SpaceWithHole space(ag * (num + 2), ag * (i + 1), ag); @@ -342,5 +349,3 @@ TEST_VM(os, attempt_reserve_memory_between_small_range_fill_hole) { } } } - -#endif // AIX diff --git a/test/hotspot/gtest/utilities/test_bitMap.cpp b/test/hotspot/gtest/utilities/test_bitMap.cpp index 7d18d66f45d..aeb41693286 100644 --- a/test/hotspot/gtest/utilities/test_bitMap.cpp +++ b/test/hotspot/gtest/utilities/test_bitMap.cpp @@ -114,6 +114,165 @@ class BitMapTest { #endif }; +class BitMapTruncateTest { + + public: + const static BitMap::idx_t BITMAP_SIZE = 128; + + template + static void fillBitMap(ResizableBitMapClass& map, BitMap::idx_t size) { + BitMap::idx_t set_bits[] = {0, 31, 63, 64, 95, 127}; + for (BitMap::idx_t bit : set_bits) { + if (bit < size) { + map.set_bit(bit); + } + } + } + + template + static void testTruncateOneWord() { + ResourceMark rm; + + ResizableBitMapClass map(64); + map.set_bit(0); + map.set_bit(1); + map.set_bit(2); + map.set_bit(3); + + ResizableBitMapClass result(2); + result.set_bit(0); + result.set_bit(1); + + map.truncate(1, 3); + + EXPECT_TRUE(map.is_same(result)); + } + + template + static void testTruncateSame() { + // Resulting map should be the same as the original + ResourceMark rm; + ResizableBitMapClass expected(BITMAP_SIZE); + fillBitMap(expected, BITMAP_SIZE); + + ResizableBitMapClass map(BITMAP_SIZE); + fillBitMap(map, BITMAP_SIZE); + map.truncate(0, BITMAP_SIZE); + + EXPECT_TRUE(map.is_same(expected)); + } + + template + static void testTruncateStart() { + // Resulting map should start at the beginning of the original + ResourceMark rm; + ResizableBitMapClass expected(64); + fillBitMap(expected, 64); + + ResizableBitMapClass map(BITMAP_SIZE); + fillBitMap(map, BITMAP_SIZE); + map.truncate(0, 64); + + EXPECT_TRUE(map.is_same(expected)); + } + + template + static void testTruncateEnd() { + // Resulting map should end at the end of the original + ResourceMark rm; + ResizableBitMapClass expected(64); + expected.set_bit(0); + expected.set_bit(31); + expected.set_bit(63); + + ResizableBitMapClass map(BITMAP_SIZE); + fillBitMap(map, BITMAP_SIZE); + map.truncate(64, 128); + + EXPECT_TRUE(map.is_same(expected)); + } + + template + static void testTruncateMiddle() { + // Resulting map should end at the end of the original + ResourceMark rm; + ResizableBitMapClass expected(64); + expected.set_bit(31); + expected.set_bit(32); + expected.set_bit(63); + + ResizableBitMapClass map(BITMAP_SIZE); + fillBitMap(map, BITMAP_SIZE); + map.truncate(32, 96); + + EXPECT_TRUE(map.is_same(expected)); + } + + template + static void testTruncateStartUnaligned() { + // Resulting map should start at the beginning of the original + ResourceMark rm; + ResizableBitMapClass expected(96); + fillBitMap(expected, 96); + + ResizableBitMapClass map(BITMAP_SIZE); + fillBitMap(map, BITMAP_SIZE); + map.truncate(0, 96); + + EXPECT_TRUE(map.is_same(expected)); + } + + template + static void testTruncateEndUnaligned() { + // Resulting map should end at the end of the original + ResourceMark rm; + ResizableBitMapClass expected(97); + expected.set_bit(0); + expected.set_bit(32); + expected.set_bit(33); + expected.set_bit(64); + expected.set_bit(96); + + ResizableBitMapClass map(BITMAP_SIZE); + fillBitMap(map, BITMAP_SIZE); + map.truncate(31, 128); + + EXPECT_TRUE(map.is_same(expected)); + } + + template + static void testRandom() { + for (int i = 0; i < 100; i++) { + ResourceMark rm; + + const size_t max_size = 1024; + const size_t size = os::random() % max_size + 1; + const size_t truncate_size = os::random() % size + 1; + const size_t truncate_start = size == truncate_size ? 0 : os::random() % (size - truncate_size); + + ResizableBitMapClass map(size); + ResizableBitMapClass result(truncate_size); + + for (BitMap::idx_t idx = 0; idx < truncate_start; idx++) { + if (os::random() % 2 == 0) { + map.set_bit(idx); + } + } + + for (BitMap::idx_t idx = 0; idx < truncate_size; idx++) { + if (os::random() % 2 == 0) { + map.set_bit(truncate_start + idx); + result.set_bit(idx); + } + } + + map.truncate(truncate_start, truncate_start + truncate_size); + + EXPECT_TRUE(map.is_same(result)); + } + } +}; + // TestArenaBitMap is the shorthand combination of Arena and ArenaBitMap. // Multiple inheritance guarantees to construct Arena first. class TestArenaBitMap : private Arena, public ArenaBitMap { @@ -204,3 +363,75 @@ TEST_VM(BitMap, print_on) { } #endif + +TEST_VM(BitMap, truncate_same) { + BitMapTruncateTest::testTruncateSame(); + EXPECT_FALSE(HasFailure()) << "Failed on type ResourceBitMap"; + BitMapTruncateTest::testTruncateSame(); + EXPECT_FALSE(HasFailure()) << "Failed on type CHeapBitMap"; + BitMapTruncateTest::testTruncateSame(); + EXPECT_FALSE(HasFailure()) << "Failed on type ArenaBitMap"; +} + +TEST_VM(BitMap, truncate_start) { + BitMapTruncateTest::testTruncateStart(); + EXPECT_FALSE(HasFailure()) << "Failed on type ResourceBitMap"; + BitMapTruncateTest::testTruncateStart(); + EXPECT_FALSE(HasFailure()) << "Failed on type CHeapBitMap"; + BitMapTruncateTest::testTruncateStart(); + EXPECT_FALSE(HasFailure()) << "Failed on type ArenaBitMap"; +} + +TEST_VM(BitMap, truncate_end) { + BitMapTruncateTest::testTruncateEnd(); + EXPECT_FALSE(HasFailure()) << "Failed on type ResourceBitMap"; + BitMapTruncateTest::testTruncateEnd(); + EXPECT_FALSE(HasFailure()) << "Failed on type CHeapBitMap"; + BitMapTruncateTest::testTruncateEnd(); + EXPECT_FALSE(HasFailure()) << "Failed on type ArenaBitMap"; +} + +TEST_VM(BitMap, truncate_middle) { + BitMapTruncateTest::testTruncateMiddle(); + EXPECT_FALSE(HasFailure()) << "Failed on type ResourceBitMap"; + BitMapTruncateTest::testTruncateMiddle(); + EXPECT_FALSE(HasFailure()) << "Failed on type CHeapBitMap"; + BitMapTruncateTest::testTruncateMiddle(); + EXPECT_FALSE(HasFailure()) << "Failed on type ArenaBitMap"; +} + +TEST_VM(BitMap, truncate_start_unaligned) { + BitMapTruncateTest::testTruncateStartUnaligned(); + EXPECT_FALSE(HasFailure()) << "Failed on type ResourceBitMap"; + BitMapTruncateTest::testTruncateStartUnaligned(); + EXPECT_FALSE(HasFailure()) << "Failed on type CHeapBitMap"; + BitMapTruncateTest::testTruncateStartUnaligned(); + EXPECT_FALSE(HasFailure()) << "Failed on type ArenaBitMap"; +} + +TEST_VM(BitMap, truncate_end_unaligned) { + BitMapTruncateTest::testTruncateEndUnaligned(); + EXPECT_FALSE(HasFailure()) << "Failed on type ResourceBitMap"; + BitMapTruncateTest::testTruncateEndUnaligned(); + EXPECT_FALSE(HasFailure()) << "Failed on type CHeapBitMap"; + BitMapTruncateTest::testTruncateEndUnaligned(); + EXPECT_FALSE(HasFailure()) << "Failed on type ArenaBitMap"; +} + +TEST_VM(BitMap, truncate_one_word) { + BitMapTruncateTest::testTruncateOneWord(); + EXPECT_FALSE(HasFailure()) << "Failed on type ResourceBitMap"; + BitMapTruncateTest::testTruncateOneWord(); + EXPECT_FALSE(HasFailure()) << "Failed on type CHeapBitMap"; + BitMapTruncateTest::testTruncateOneWord(); + EXPECT_FALSE(HasFailure()) << "Failed on type ArenaBitMap"; +} + +TEST_VM(BitMap, truncate_random) { + BitMapTruncateTest::testRandom(); + EXPECT_FALSE(HasFailure()) << "Failed on type ResourceBitMap"; + BitMapTruncateTest::testRandom(); + EXPECT_FALSE(HasFailure()) << "Failed on type CHeapBitMap"; + BitMapTruncateTest::testRandom(); + EXPECT_FALSE(HasFailure()) << "Failed on type ArenaBitMap"; +} diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index b818359a628..4684d8359bc 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -34,7 +34,7 @@ serviceability/sa/ClhsdbJstackWithConcurrentLock.java 8276539 generic- serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java 8276539 generic-all serviceability/sa/ClhsdbFindPC.java#xcomp-core 8284045 generic-all -serviceability/sa/TestJmapCore.java 8268283,8270202 linux-aarch64,linux-x64,macosx-aarch64 +serviceability/sa/TestJmapCore.java 8268283,8270202 generic-all serviceability/sa/TestJmapCoreMetaspace.java 8268636 generic-all serviceability/sa/TestJhsdbJstackMixed.java 8248912 generic-all diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 87d3f130ca6..1045460394e 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -108,7 +108,6 @@ runtime/os/TestTracePageSizes.java#G1 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Parallel 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Serial 8267460 linux-aarch64 runtime/ErrorHandling/CreateCoredumpOnCrash.java 8267433 macosx-x64 -runtime/CompressedOops/CompressedClassPointers.java 8322943 aix-ppc64 runtime/StackGuardPages/TestStackGuardPagesNative.java 8303612 linux-all runtime/ErrorHandling/TestDwarf.java#checkDecoder 8305489 linux-all runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 0edbf591b3e..7ca956ef478 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -431,7 +431,8 @@ tier1_runtime = \ -runtime/Unsafe/RangeCheck.java \ sanity/ \ -:tier1_runtime_appcds_exclude \ - -runtime/signal + -runtime/signal \ + -runtime/stack tier1_runtime_no_valhalla = \ :tier1_runtime \ diff --git a/test/hotspot/jtreg/TEST.quick-groups b/test/hotspot/jtreg/TEST.quick-groups index fa8f22b07a8..fa1f7f5634e 100644 --- a/test/hotspot/jtreg/TEST.quick-groups +++ b/test/hotspot/jtreg/TEST.quick-groups @@ -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 @@ -969,7 +969,6 @@ vmTestbase_nsk_jvmti_quick = \ vmTestbase/nsk/jvmti/GetMethodName/methname003/TestDescription.java \ vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001/TestDescription.java \ vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage002/TestDescription.java \ - vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003/TestDescription.java \ vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004/TestDescription.java \ vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage005/TestDescription.java \ vmTestbase/nsk/jvmti/GetObjectSize/objsize001/TestDescription.java \ diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16Conversion.java b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16Conversion.java index ab4d8ff8bb7..cd0f0b636a7 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16Conversion.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16Conversion.java @@ -26,7 +26,7 @@ * @bug 8289551 8302976 * @summary Verify conversion between float and the binary16 format * @requires (vm.cpu.features ~= ".*avx512vl.*" | vm.cpu.features ~= ".*f16c.*") | os.arch=="aarch64" - * | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh,.*") + * | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh.*") * @requires vm.compiler1.enabled & vm.compiler2.enabled * @requires vm.compMode != "Xcomp" * @comment default run diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN.java b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN.java index f549c1ae670..8aa83544f9f 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/Binary16ConversionNaN.java @@ -26,7 +26,7 @@ * @bug 8289551 8302976 * @summary Verify NaN sign and significand bits are preserved across conversions * @requires (vm.cpu.features ~= ".*avx512vl.*" | vm.cpu.features ~= ".*f16c.*") | os.arch=="aarch64" - * | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh,.*") + * | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh.*") * @requires vm.compiler1.enabled & vm.compiler2.enabled * @requires vm.compMode != "Xcomp" * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/TestAllFloat16ToFloat.java b/test/hotspot/jtreg/compiler/intrinsics/float16/TestAllFloat16ToFloat.java index 937e17f8fca..acf5b3c4aea 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/TestAllFloat16ToFloat.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/TestAllFloat16ToFloat.java @@ -26,7 +26,7 @@ * @bug 8302976 * @summary Verify conversion between float and the binary16 format * @requires (vm.cpu.features ~= ".*avx512vl.*" | vm.cpu.features ~= ".*f16c.*") | os.arch == "aarch64" - * | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh,.*") + * | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh.*") * @requires vm.compiler1.enabled & vm.compiler2.enabled * @requires vm.compMode != "Xcomp" * @comment default run: diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/TestConstFloat16ToFloat.java b/test/hotspot/jtreg/compiler/intrinsics/float16/TestConstFloat16ToFloat.java index f58cf618c1c..af89d353ab2 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/TestConstFloat16ToFloat.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/TestConstFloat16ToFloat.java @@ -26,7 +26,7 @@ * @bug 8302976 * @summary Verify conversion cons between float and the binary16 format * @requires (vm.cpu.features ~= ".*avx512vl.*" | vm.cpu.features ~= ".*f16c.*") | os.arch=="aarch64" - * | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh,.*") + * | (os.arch == "riscv64" & vm.cpu.features ~= ".*zfh.*") * @requires vm.compiler1.enabled & vm.compiler2.enabled * @requires vm.compMode != "Xcomp" * @comment default run: diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java index e32da89b8cd..3cb0152659c 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java @@ -41,14 +41,18 @@ public class TestMulAddS2I { static short[] sArr1 = new short[RANGE]; static short[] sArr2 = new short[RANGE]; - static final int[] GOLDEN; + static final int[] GOLDEN_A; + static final int[] GOLDEN_B; + static final int[] GOLDEN_C; static { for (int i = 0; i < RANGE; i++) { sArr1[i] = (short)(AbstractInfo.getRandom().nextInt()); sArr2[i] = (short)(AbstractInfo.getRandom().nextInt()); } - GOLDEN = test(); + GOLDEN_A = testa(); + GOLDEN_B = testb(); + GOLDEN_C = testc(); } @@ -61,15 +65,17 @@ public static void main(String[] args) { } } - @Run(test = "test") + @Run(test = {"testa", "testb", "testc"}) @Warmup(0) public static void run() { - compare(test()); + compare(testa(), GOLDEN_A, "testa"); + compare(testb(), GOLDEN_B, "testb"); + compare(testb(), GOLDEN_C, "testc"); } - public static void compare(int[] out) { + public static void compare(int[] out, int[] golden, String name) { for (int i = 0; i < ITER; i++) { - Asserts.assertEQ(out[i], GOLDEN[i], "wrong result for out[" + i + "]"); + Asserts.assertEQ(out[i], golden[i], "wrong result for '" + name + "' out[" + i + "]"); } } @@ -82,7 +88,7 @@ public static void compare(int[] out) { counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI, "> 0"}) @IR(applyIfCPUFeature = {"avx512_vnni", "true"}, counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI_VNNI, "> 0"}) - public static int[] test() { + public static int[] testa() { int[] out = new int[ITER]; int[] out2 = new int[ITER]; for (int i = 0; i < ITER; i++) { @@ -91,4 +97,40 @@ public static int[] test() { } return out; } + + @Test + @IR(applyIfCPUFeature = {"sse2", "true"}, + applyIfPlatform = {"64-bit", "true"}, + counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI, "> 0"}) + @IR(applyIfCPUFeature = {"asimd", "true"}, + applyIf = {"MaxVectorSize", "16"}, // AD file requires vector_length = 16 + counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI, "> 0"}) + @IR(applyIfCPUFeature = {"avx512_vnni", "true"}, + counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI_VNNI, "> 0"}) + public static int[] testb() { + int[] out = new int[ITER]; + int[] out2 = new int[ITER]; + for (int i = 0; i < ITER; i++) { + out[i] += ((sArr1[2*i] * sArr2[2*i]) + (sArr1[2*i+1] * sArr2[2*i+1])); + out2[i] += out[i]; + } + return out; + } + + @Test + @IR(applyIfCPUFeature = {"sse2", "true"}, + applyIfPlatform = {"64-bit", "true"}, + counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI, "> 0"}) + @IR(applyIfCPUFeature = {"asimd", "true"}, + applyIf = {"MaxVectorSize", "16"}, // AD file requires vector_length = 16 + counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI, "> 0"}) + @IR(applyIfCPUFeature = {"avx512_vnni", "true"}, + counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI_VNNI, "> 0"}) + public static int[] testc() { + int[] out = new int[ITER]; + for (int i = 0; i < ITER; i++) { + out[i] += ((sArr1[2*i] * sArr2[2*i]) + (sArr1[2*i+1] * sArr2[2*i+1])); + } + return out; + } } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java new file mode 100644 index 00000000000..4bc18e9abdb --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java @@ -0,0 +1,766 @@ +/* + * 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. + * + * 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 compiler.loopopts.superword; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; +import jdk.test.whitebox.WhiteBox; +import java.lang.reflect.Array; +import java.util.Map; +import java.util.HashMap; +import java.util.Random; +import java.nio.ByteOrder; + +/* + * @test + * @bug 8326139 + * @summary Test splitting packs in SuperWord + * @library /test/lib / + * @requires vm.compiler2.enabled + * @run driver compiler.loopopts.superword.TestSplitPacks + */ + +public class TestSplitPacks { + static int RANGE = 1024*8; + static int RANGE_FINAL = 1024*8; + private static final Random RANDOM = Utils.getRandomInstance(); + + // Inputs + byte[] aB; + byte[] bB; + byte mB = (byte)31; + short[] aS; + short[] bS; + short mS = (short)0xF0F0; + int[] aI; + int[] bI; + int mI = 0xF0F0F0F0; + long[] aL; + long[] bL; + long mL = 0xF0F0F0F0F0F0F0F0L; + + // List of tests + Map tests = new HashMap(); + + // List of gold, the results from the first run before compilation + Map golds = new HashMap(); + + interface TestFunction { + Object[] run(); + } + + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:LoopUnrollLimit=1000"); + } + + public TestSplitPacks() { + // Generate input once + aB = generateB(); + bB = generateB(); + aS = generateS(); + bS = generateS(); + aI = generateI(); + bI = generateI(); + aL = generateL(); + bL = generateL(); + + // Add all tests to list + tests.put("test0", () -> { return test0(aI.clone(), bI.clone(), mI); }); + tests.put("test1a", () -> { return test1a(aI.clone(), bI.clone(), mI); }); + tests.put("test1b", () -> { return test1b(aI.clone(), bI.clone(), mI); }); + tests.put("test1c", () -> { return test1c(aI.clone(), bI.clone(), mI); }); + tests.put("test1d", () -> { return test1d(aI.clone(), bI.clone(), mI); }); + tests.put("test2a", () -> { return test2a(aI.clone(), bI.clone(), mI); }); + tests.put("test2b", () -> { return test2b(aI.clone(), bI.clone(), mI); }); + tests.put("test2c", () -> { return test2c(aI.clone(), bI.clone(), mI); }); + tests.put("test2d", () -> { return test2d(aI.clone(), bI.clone(), mI); }); + tests.put("test3a", () -> { return test3a(aS.clone(), bS.clone(), mS); }); + tests.put("test4a", () -> { return test4a(aS.clone(), bS.clone()); }); + tests.put("test4b", () -> { return test4b(aS.clone(), bS.clone()); }); + tests.put("test4c", () -> { return test4c(aS.clone(), bS.clone()); }); + tests.put("test4d", () -> { return test4d(aS.clone(), bS.clone()); }); + tests.put("test4e", () -> { return test4e(aS.clone(), bS.clone()); }); + tests.put("test4f", () -> { return test4f(aS.clone(), bS.clone()); }); + tests.put("test4g", () -> { return test4g(aS.clone(), bS.clone()); }); + tests.put("test5a", () -> { return test5a(aS.clone(), bS.clone(), mS); }); + tests.put("test6a", () -> { return test6a(aI.clone(), bI.clone()); }); + tests.put("test7a", () -> { return test7a(aI.clone(), bI.clone()); }); + + // Compute gold value for all test methods before compilation + for (Map.Entry entry : tests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + Object[] gold = test.run(); + golds.put(name, gold); + } + } + + @Warmup(100) + @Run(test = {"test0", + "test1a", + "test1b", + "test1c", + "test1d", + "test2a", + "test2b", + "test2c", + "test2d", + "test3a", + "test4a", + "test4b", + "test4c", + "test4d", + "test4e", + "test4f", + "test4g", + "test5a", + "test6a", + "test7a"}) + public void runTests() { + for (Map.Entry entry : tests.entrySet()) { + String name = entry.getKey(); + TestFunction test = entry.getValue(); + // Recall gold value from before compilation + Object[] gold = golds.get(name); + // Compute new result + Object[] result = test.run(); + // Compare gold and new result + verify(name, gold, result); + } + } + + static byte[] generateB() { + byte[] a = new byte[RANGE]; + for (int i = 0; i < a.length; i++) { + a[i] = (byte)RANDOM.nextInt(); + } + return a; + } + + static short[] generateS() { + short[] a = new short[RANGE]; + for (int i = 0; i < a.length; i++) { + a[i] = (short)RANDOM.nextInt(); + } + return a; + } + + static int[] generateI() { + int[] a = new int[RANGE]; + for (int i = 0; i < a.length; i++) { + a[i] = RANDOM.nextInt(); + } + return a; + } + + static long[] generateL() { + long[] a = new long[RANGE]; + for (int i = 0; i < a.length; i++) { + a[i] = RANDOM.nextLong(); + } + return a; + } + + static void verify(String name, Object[] gold, Object[] result) { + if (gold.length != result.length) { + throw new RuntimeException("verify " + name + ": not the same number of outputs: gold.length = " + + gold.length + ", result.length = " + result.length); + } + for (int i = 0; i < gold.length; i++) { + Object g = gold[i]; + Object r = result[i]; + if (g.getClass() != r.getClass() || !g.getClass().isArray() || !r.getClass().isArray()) { + throw new RuntimeException("verify " + name + ": must both be array of same type:" + + " gold[" + i + "].getClass() = " + g.getClass().getSimpleName() + + " result[" + i + "].getClass() = " + r.getClass().getSimpleName()); + } + if (g == r) { + throw new RuntimeException("verify " + name + ": should be two separate arrays (with identical content):" + + " gold[" + i + "] == result[" + i + "]"); + } + if (Array.getLength(g) != Array.getLength(r)) { + throw new RuntimeException("verify " + name + ": arrays must have same length:" + + " gold[" + i + "].length = " + Array.getLength(g) + + " result[" + i + "].length = " + Array.getLength(r)); + } + Class c = g.getClass().getComponentType(); + if (c == byte.class) { + verifyB(name, i, (byte[])g, (byte[])r); + } else if (c == short.class) { + verifyS(name, i, (short[])g, (short[])r); + } else if (c == int.class) { + verifyI(name, i, (int[])g, (int[])r); + } else if (c == long.class) { + verifyL(name, i, (long[])g, (long[])r); + } else { + throw new RuntimeException("verify " + name + ": array type not supported for verify:" + + " gold[" + i + "].getClass() = " + g.getClass().getSimpleName() + + " result[" + i + "].getClass() = " + r.getClass().getSimpleName()); + } + } + } + + static void verifyB(String name, int i, byte[] g, byte[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verify " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyS(String name, int i, short[] g, short[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verify " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyI(String name, int i, int[] g, int[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verify " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + static void verifyL(String name, int i, long[] g, long[] r) { + for (int j = 0; j < g.length; j++) { + if (g[j] != r[j]) { + throw new RuntimeException("verify " + name + ": arrays must have same content:" + + " gold[" + i + "][" + j + "] = " + g[j] + + " result[" + i + "][" + j + "] = " + r[j]); + } + } + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VI, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.AND_VI, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Load and store are already split + // + // 0 1 - - 4 5 6 7 + // | | | | | | + // 0 1 - - 4 5 6 7 + static Object[] test0(int[] a, int[] b, int mask) { + for (int i = 0; i < RANGE; i+=8) { + int b0 = a[i+0] & mask; + int b1 = a[i+1] & mask; + + int b4 = a[i+4] & mask; + int b5 = a[i+5] & mask; + int b6 = a[i+6] & mask; + int b7 = a[i+7] & mask; + + b[i+0] = b0; + b[i+1] = b1; + + b[i+4] = b4; + b[i+5] = b5; + b[i+6] = b6; + b[i+7] = b7; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.MUL_VI, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Adjacent Load and Store, but split by Add/Mul + static Object[] test1a(int[] a, int[] b, int mask) { + for (int i = 0; i < RANGE; i+=8) { + b[i+0] = a[i+0] + mask; // Add + b[i+1] = a[i+1] + mask; + b[i+2] = a[i+2] + mask; + b[i+3] = a[i+3] + mask; + + b[i+4] = a[i+4] * mask; // Mul + b[i+5] = a[i+5] * mask; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.MUL_VI, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Adjacent Load and Store, but split by Add/Mul + static Object[] test1b(int[] a, int[] b, int mask) { + for (int i = 0; i < RANGE; i+=8) { + b[i+0] = a[i+0] * mask; // Mul + b[i+1] = a[i+1] * mask; + b[i+2] = a[i+2] * mask; + b[i+3] = a[i+3] * mask; + + b[i+4] = a[i+4] + mask; // Add + b[i+5] = a[i+5] + mask; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.MUL_VI, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + // Adjacent Load and Store, but split by Add/Mul + static Object[] test1c(int[] a, int[] b, int mask) { + for (int i = 0; i < RANGE; i+=8) { + b[i+0] = a[i+0] + mask; // Add + b[i+1] = a[i+1] + mask; + + b[i+2] = a[i+2] * mask; // Mul + b[i+3] = a[i+3] * mask; + b[i+4] = a[i+4] * mask; + b[i+5] = a[i+5] * mask; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.MUL_VI, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + // Adjacent Load and Store, but split by Add/Mul + static Object[] test1d(int[] a, int[] b, int mask) { + for (int i = 0; i < RANGE; i+=8) { + b[i+0] = a[i+0] * mask; // Mul + b[i+1] = a[i+1] * mask; + + b[i+2] = a[i+2] + mask; // Add + b[i+3] = a[i+3] + mask; + b[i+4] = a[i+4] + mask; + b[i+5] = a[i+5] + mask; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "= 0", + IRNode.AND_VI, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.AND_VI, IRNode.VECTOR_SIZE_4, "= 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Split the load + // + // 0 1 2 3 4 5 - - + // | | \ \ \ \ + // | | \ \ \ \ + // | | \ \ \ \ + // 0 1 - - 4 5 6 7 + // + // The 4-pack does not vectorize. This is a technical limitation that + // we can hopefully soon remove. Load and store offsets are different. + static Object[] test2a(int[] a, int[] b, int mask) { + for (int i = 0; i < RANGE; i+=8) { + int b0 = a[i+0] & mask; + int b1 = a[i+1] & mask; + int b2 = a[i+2] & mask; + int b3 = a[i+3] & mask; + int b4 = a[i+4] & mask; + int b5 = a[i+5] & mask; + + b[i+0] = b0; + b[i+1] = b1; + + b[i+4] = b2; + b[i+5] = b3; + b[i+6] = b4; + b[i+7] = b5; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "= 0", + IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VI, IRNode.VECTOR_SIZE_2, "= 0", + IRNode.AND_VI, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Split the load + // + // 0 1 2 3 4 5 - - + // | | | | \ \ + // | | | | \ \ + // | | | | \ \ + // 0 1 2 3 -- 6 7 + // + // The 2-pack does not vectorize. This is a technical limitation that + // we can hopefully soon remove. Load and store offsets are different. + static Object[] test2b(int[] a, int[] b, int mask) { + for (int i = 0; i < RANGE; i+=8) { + int b0 = a[i+0] & mask; + int b1 = a[i+1] & mask; + int b2 = a[i+2] & mask; + int b3 = a[i+3] & mask; + int b4 = a[i+4] & mask; + int b5 = a[i+5] & mask; + + b[i+0] = b0; + b[i+1] = b1; + b[i+2] = b2; + b[i+3] = b3; + + b[i+6] = b4; + b[i+7] = b5; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "= 0", + IRNode.AND_VI, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.AND_VI, IRNode.VECTOR_SIZE_4, "= 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Split the load + // + // 0 1 - - 4 5 6 7 + // | | / / / / + // | | / / / / + // | | / / / / + // 0 1 2 3 4 5 - - + // + // The 4-pack does not vectorize. This is a technical limitation that + // we can hopefully soon remove. Load and store offsets are different. + static Object[] test2c(int[] a, int[] b, int mask) { + for (int i = 0; i < RANGE; i+=8) { + int b0 = a[i+0] & mask; + int b1 = a[i+1] & mask; + + int b4 = a[i+4] & mask; + int b5 = a[i+5] & mask; + int b6 = a[i+6] & mask; + int b7 = a[i+7] & mask; + + b[i+0] = b0; + b[i+1] = b1; + b[i+2] = b4; + b[i+3] = b5; + b[i+4] = b6; + b[i+5] = b7; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_2, "= 0", + IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VI, IRNode.VECTOR_SIZE_2, "= 0", + IRNode.AND_VI, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Split the load + // + // 0 1 2 3 - - 6 7 + // | | | | / / + // | | | | / / + // | | | | / / + // 0 1 2 3 4 5 - - + // + // The 2-pack does not vectorize. This is a technical limitation that + // we can hopefully soon remove. Load and store offsets are different. + static Object[] test2d(int[] a, int[] b, int mask) { + for (int i = 0; i < RANGE; i+=8) { + int b0 = a[i+0] & mask; + int b1 = a[i+1] & mask; + int b2 = a[i+2] & mask; + int b3 = a[i+3] & mask; + + int b6 = a[i+6] & mask; + int b7 = a[i+7] & mask; + + b[i+0] = b0; + b[i+1] = b1; + b[i+2] = b2; + b[i+3] = b3; + b[i+4] = b6; + b[i+5] = b7; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // 0 1 2 3 4 5 6 7 - + // | | | | | | | | + // | + + + | | | | + // | | | | | + // | v | | | | v + // | | | | | | | + // 1 - - 3 4 5 6 7 8 + static Object[] test3a(short[] a, short[] b, short val) { + int sum = 0; + for (int i = 0; i < RANGE; i+=16) { + short a0 = a[i+0]; // required for alignment / offsets, technical limitation. + + short a1 = a[i+1]; // adjacent to 4-pack, but need to be split off + short a2 = a[i+2]; + short a3 = a[i+3]; + + short a4 = a[i+4]; // 4-pack + short a5 = a[i+5]; + short a6 = a[i+6]; + short a7 = a[i+7]; + + + b[i+0] = a0; // required for alignment / offsets, technical limitation. + + sum += a1 + a2 + a3; // not packed + + b[i+3] = val; // adjacent to 4-pack but needs to be split off + + b[i+4] = a4; // 4-pack + b[i+5] = a5; + b[i+6] = a6; + b[i+7] = a7; + + b[i+8] = val; // adjacent to 4-pack but needs to be split off + } + return new Object[]{ a, b, new int[]{ sum } }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Cyclic dependency with distance 2 -> split into 2-packs + static Object[] test4a(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+2] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true"}) + // Cyclic dependency with distance 3 -> split into 2-packs + static Object[] test4b(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+3] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=8"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Cyclic dependency with distance 4 -> split into 4-packs + static Object[] test4c(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+4] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Cyclic dependency with distance 5 -> split into 4-packs + static Object[] test4d(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+5] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Cyclic dependency with distance 6 -> split into 4-packs + static Object[] test4e(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+6] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"MaxVectorSize", ">=8", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Cyclic dependency with distance 7 -> split into 4-packs + static Object[] test4f(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+7] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Cyclic dependency with distance 8 -> split into 8-packs + static Object[] test4g(short[] a, short[] b) { + for (int i = 0; i < RANGE-64; i++) { + b[i+8] = a[i+0]; + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.LOAD_VECTOR_S, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.ADD_VS, IRNode.VECTOR_SIZE_2, "> 0", + IRNode.ADD_VS, IRNode.VECTOR_SIZE_8, "> 0", + IRNode.ADD_VS, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIfAnd = {"MaxVectorSize", ">=32", "AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Split pack into power-of-2 sizes + static Object[] test5a(short[] a, short[] b, short val) { + for (int i = 0; i < RANGE; i+=16) { + b[i+ 0] = (short)(a[i+ 0] + val); // 8 pack + b[i+ 1] = (short)(a[i+ 1] + val); + b[i+ 2] = (short)(a[i+ 2] + val); + b[i+ 3] = (short)(a[i+ 3] + val); + b[i+ 4] = (short)(a[i+ 4] + val); + b[i+ 5] = (short)(a[i+ 5] + val); + b[i+ 6] = (short)(a[i+ 6] + val); + b[i+ 7] = (short)(a[i+ 7] + val); + + b[i+ 8] = (short)(a[i+ 8] + val); // 4-pack + b[i+ 9] = (short)(a[i+ 9] + val); + b[i+10] = (short)(a[i+10] + val); + b[i+11] = (short)(a[i+11] + val); + + b[i+12] = (short)(a[i+12] + val); // 2-pack + b[i+13] = (short)(a[i+13] + val); + + b[i+14] = (short)(a[i+14] + val); + } + return new Object[]{ a, b }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.MUL_VI, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.AND_VI, IRNode.VECTOR_SIZE_4, "> 0", + IRNode.ADD_VI, IRNode.VECTOR_SIZE_4, "> 0", // reduction moved out of loop + IRNode.ADD_REDUCTION_V, "> 0"}, + applyIf = {"MaxVectorSize", ">=32"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + // Split packs including reductions + static Object[] test6a(int[] a, int[] b) { + int s = 0; + for (int i = 0; i < RANGE; i+=8) { + s += a[i+0] * b[i+0]; + s += a[i+1] * b[i+1]; + s += a[i+2] * b[i+2]; + s += a[i+3] * b[i+3]; + + s += a[i+4] & b[i+4]; + s += a[i+5] & b[i+5]; + s += a[i+6] & b[i+6]; + s += a[i+7] & b[i+7]; + } + return new Object[]{ a, b, new int[]{ s } }; + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0", + IRNode.MUL_VI, "> 0", + IRNode.POPULATE_INDEX, "> 0"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + // Index Populate: + // There can be an issue when all the (iv + 1), (iv + 2), ... + // get packed, but not (iv). Then we have a pack that is one element + // too short, and we start splitting everything in a bad way. + static Object[] test7a(int[] a, int[] b) { + for (int i = 0; i < RANGE; i++) { + a[i] = b[i] * i; + } + return new Object[]{ a, b }; + } +} diff --git a/test/hotspot/jtreg/compiler/stable/TestUnstableStable.java b/test/hotspot/jtreg/compiler/stable/TestUnstableStable.java index 140933daa34..8327c5ecd2c 100644 --- a/test/hotspot/jtreg/compiler/stable/TestUnstableStable.java +++ b/test/hotspot/jtreg/compiler/stable/TestUnstableStable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -89,9 +89,9 @@ public void run() { stableArray1[0][0] = null; stableArray1[0][0] = 42; stableArray1[0][0] = 43; - U.putObject(TestUnstableStable.class, FIELD_OFFSET, null); - U.putObject(TestUnstableStable.class, FIELD_OFFSET, 42); - U.putObject(TestUnstableStable.class, FIELD_OFFSET, 43); + U.putReference(TestUnstableStable.class, FIELD_OFFSET, null); + U.putReference(TestUnstableStable.class, FIELD_OFFSET, 42); + U.putReference(TestUnstableStable.class, FIELD_OFFSET, 43); } } } diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java index 49035332fa4..96324c62c32 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, 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 @@ -26,7 +26,9 @@ * @bug 8294588 * @summary Auto-vectorize Float.floatToFloat16, Float.float16ToFloat APIs * @requires vm.compiler2.enabled - * @requires (os.simpleArch == "x64" & (vm.cpu.features ~= ".*avx512f.*" | vm.cpu.features ~= ".*f16c.*")) | os.arch == "aarch64" + * @requires (os.simpleArch == "x64" & (vm.cpu.features ~= ".*avx512f.*" | vm.cpu.features ~= ".*f16c.*")) | + * os.arch == "aarch64" | + * (os.arch == "riscv64" & vm.cpu.features ~= ".*zvfh.*") * @library /test/lib / * @run driver compiler.vectorization.TestFloatConversionsVector */ diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVectorNaN.java b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVectorNaN.java new file mode 100644 index 00000000000..26e42b92bad --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloatConversionsVectorNaN.java @@ -0,0 +1,202 @@ +/* + * 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. + * + * 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. + */ + +/** + * @test + * @bug 8320646 + * @summary Auto-vectorize Float.floatToFloat16, Float.float16ToFloat APIs, with NaN + * @requires vm.compiler2.enabled + * @requires (os.arch == "riscv64" & vm.cpu.features ~= ".*zvfh.*") + * @library /test/lib / + * @run driver compiler.vectorization.TestFloatConversionsVectorNaN + */ + +package compiler.vectorization; + +import java.util.HexFormat; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +public class TestFloatConversionsVectorNaN { + private static final int ARRLEN = 1024; + private static final int ITERS = 11000; + private static float [] finp; + private static short [] sout; + private static short [] sinp; + private static float [] fout; + + public static void main(String args[]) { + TestFramework.runWithFlags("-XX:-TieredCompilation", + "-XX:CompileThresholdScaling=0.3"); + System.out.println("PASSED"); + } + + @Test + @IR(counts = {IRNode.VECTOR_CAST_F2HF, IRNode.VECTOR_SIZE + "min(max_float, max_short)", "> 0"}) + public void test_float_float16(short[] sout, float[] finp) { + for (int i = 0; i < finp.length; i++) { + sout[i] = Float.floatToFloat16(finp[i]); + } + } + + @Run(test = {"test_float_float16"}, mode = RunMode.STANDALONE) + public void kernel_test_float_float16() { + int errno = 0; + finp = new float[ARRLEN]; + sout = new short[ARRLEN]; + + // Setup + for (int i = 0; i < ARRLEN; i++) { + if (i%39 == 0) { + int x = 0x7f800000 + ((i/39) << 13); + x = (i%2 == 0) ? x : (x | 0x80000000); + finp[i] = Float.intBitsToFloat(x); + } else { + finp[i] = (float) i * 1.4f; + } + } + int ranges[][] = { + {128, 64}, + {256, 19}, + {384-19, 19}, + {512-19, 17}, + {640+19, 19}, + {768+19, 32}, + {896-19, 32} + }; + for (int range[] : ranges) { + int start = range[0]; + int offset = range[1]; + for (int i = start; i < start+offset; i++) { + int x = 0x7f800000 + (i << 13); + finp[i] = Float.intBitsToFloat(x); + } + } + + // Test + for (int i = 0; i < ITERS; i++) { + test_float_float16(sout, finp); + } + + // Verifying the result + for (int i = 0; i < ARRLEN; i++) { + errno += assertEquals(i, finp[i], Float.floatToFloat16(finp[i]), sout[i]); + } + + if (errno > 0) { + throw new RuntimeException("errors occur"); + } + } + + static int assertEquals(int idx, float f, short expected, short actual) { + HexFormat hf = HexFormat.of(); + String msg = "floatToFloat16 wrong result: idx: " + idx + ", \t" + f + + ",\t expected: " + hf.toHexDigits(expected) + + ",\t actual: " + hf.toHexDigits(actual); + if ((expected & 0x7c00) != 0x7c00) { + if (expected != actual) { + System.err.println(msg); + return 1; + } + } else if ((expected & 0x3ff) != 0) { + if (((actual & 0x7c00) != 0x7c00) || (actual & 0x3ff) == 0) { + System.err.println(msg); + return 1; + } + } + return 0; + } + + @Test + @IR(counts = {IRNode.VECTOR_CAST_HF2F, IRNode.VECTOR_SIZE + "min(max_float, max_short)", "> 0"}) + public void test_float16_float(float[] fout, short[] sinp) { + for (int i = 0; i < sinp.length; i++) { + fout[i] = Float.float16ToFloat(sinp[i]); + } + } + + @Run(test = {"test_float16_float"}, mode = RunMode.STANDALONE) + public void kernel_test_float16_float() { + int errno = 0; + sinp = new short[ARRLEN]; + fout = new float[ARRLEN]; + + // Setup + for (int i = 0; i < ARRLEN; i++) { + if (i%39 == 0) { + int x = 0x7c00 + i; + x = (i%2 == 0) ? x : (x | 0x8000); + sinp[i] = (short)x; + } else { + sinp[i] = (short)i; + } + } + + int ranges[][] = { + {128, 64}, + {256, 19}, + {384-19, 19}, + {512-19, 17}, + {640+19, 19}, + {768+19, 32}, + {896-19, 32} + }; + for (int range[] : ranges) { + int start = range[0]; + int offset = range[1]; + for (int i = start; i < start+offset; i++) { + int x = 0x7c00 + i; + x = (i%2 == 0) ? x : (x | 0x8000); + sinp[i] = (short)x; + } + } + + // Test + for (int i = 0; i < ITERS; i++) { + test_float16_float(fout, sinp); + } + + // Verifying the result + for (int i = 0; i < ARRLEN; i++) { + errno += assertEquals(i, sinp[i], Float.float16ToFloat(sinp[i]), fout[i]); + } + + if (errno > 0) { + throw new RuntimeException("errors occur"); + } + } + + static int assertEquals(int idx, short s, float expected, float actual) { + String msg = "float16ToFloat wrong result: idx: " + idx + ", \t" + s + + ",\t expected: " + expected + ",\t" + Integer.toHexString(Float.floatToIntBits(expected)) + + ",\t actual: " + actual + ",\t" + Integer.toHexString(Float.floatToIntBits(actual)); + if (!Float.isNaN(expected) || !Float.isNaN(actual)) { + if (expected != actual) { + System.err.println(msg); + return 1; + } + } + return 0; + } +} diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java index e06bbb05098..8df1e03e3f4 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/LoopArrayIndexComputeTest.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022, 2023, Arm Limited. All rights reserved. - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -290,7 +290,8 @@ public short[] shortArrayWithDependenceNeg() { // No true dependency in read-forward case. @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, applyIf = {"AlignVector", "false"}, - counts = {IRNode.STORE_VECTOR, ">0"}) + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.MUL_VS, ">0"}) // expect maximum size public char[] charArrayWithDependencePos() { char[] res = new char[SIZE]; System.arraycopy(chars, 0, res, 0, SIZE); @@ -301,8 +302,10 @@ public char[] charArrayWithDependencePos() { } @Test - // Note that this case cannot be vectorized due to data dependence. - @IR(failOn = {IRNode.STORE_VECTOR}) + // Data dependency at distance 2: restrict vector size to 2 + @IR(applyIfCPUFeatureOr = {"sse2", "true"}, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.MUL_VS, IRNode.VECTOR_SIZE_2, ">0"}) // size 2 only public char[] charArrayWithDependenceNeg() { char[] res = new char[SIZE]; System.arraycopy(chars, 0, res, 0, SIZE); @@ -354,8 +357,10 @@ public boolean[] booleanArrayWithDependencePos() { } @Test - // Note that this case cannot be vectorized due to data dependence. - @IR(failOn = {IRNode.STORE_VECTOR}) + // Data dependency at distance 4: restrict vector size to 4 + @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + counts = {IRNode.STORE_VECTOR, ">0", + IRNode.OR_VB, IRNode.VECTOR_SIZE_4, ">0"}) // size 4 only public boolean[] booleanArrayWithDependenceNeg() { boolean[] res = new boolean[SIZE]; System.arraycopy(booleans, 0, res, 0, SIZE); diff --git a/test/hotspot/jtreg/gc/shenandoah/compiler/TestUnsafeLoadStoreMergedHeapStableTests.java b/test/hotspot/jtreg/gc/shenandoah/compiler/TestUnsafeLoadStoreMergedHeapStableTests.java index e7f9c777ef8..77af9963830 100644 --- a/test/hotspot/jtreg/gc/shenandoah/compiler/TestUnsafeLoadStoreMergedHeapStableTests.java +++ b/test/hotspot/jtreg/gc/shenandoah/compiler/TestUnsafeLoadStoreMergedHeapStableTests.java @@ -55,7 +55,7 @@ static class A { static Object testHelper(boolean flag, Object o, long offset, Object x) { if (flag) { - return UNSAFE.getAndSetObject(o, offset, x); + return UNSAFE.getAndSetReference(o, offset, x); } return null; } @@ -68,7 +68,7 @@ static Object test1(boolean flag, Object o, long offset) { } static Object test2(Object o, long offset) { - return UNSAFE.getAndSetObject(o, offset, field); + return UNSAFE.getAndSetReference(o, offset, field); } static public void main(String[] args) { diff --git a/test/hotspot/jtreg/gc/shenandoah/compiler/libLinkToNativeRBP.c b/test/hotspot/jtreg/gc/shenandoah/compiler/libLinkToNativeRBP.c index e57a86caa60..0f54c4c2402 100644 --- a/test/hotspot/jtreg/gc/shenandoah/compiler/libLinkToNativeRBP.c +++ b/test/hotspot/jtreg/gc/shenandoah/compiler/libLinkToNativeRBP.c @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT int foo() { return 0; diff --git a/test/hotspot/jtreg/runtime/ClassUnload/ConstantPoolDependsTest.java b/test/hotspot/jtreg/runtime/ClassUnload/ConstantPoolDependsTest.java index a61c8cf4f2f..db490bd760a 100644 --- a/test/hotspot/jtreg/runtime/ClassUnload/ConstantPoolDependsTest.java +++ b/test/hotspot/jtreg/runtime/ClassUnload/ConstantPoolDependsTest.java @@ -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 @@ -39,6 +39,8 @@ import jdk.test.lib.classloader.ClassUnloadCommon; import java.lang.ref.Reference; +import java.util.List; +import java.util.Set; public class ConstantPoolDependsTest { public static WhiteBox wb = WhiteBox.getWhiteBox(); public static final String MY_TEST = "ConstantPoolDependsTest$c1c"; @@ -78,10 +80,7 @@ static void test() throws Throwable { public static void main(String args[]) throws Throwable { test(); - ClassUnloadCommon.triggerUnloading(); // should unload - System.gc(); - System.out.println("Should unload p2.c2 just now"); - ClassUnloadCommon.failIf(wb.isClassAlive(MY_TEST), "should be unloaded"); - ClassUnloadCommon.failIf(wb.isClassAlive("p2.c2"), "should be unloaded"); + Set aliveClasses = ClassUnloadCommon.triggerUnloading(List.of(MY_TEST, "p2.c2")); + ClassUnloadCommon.failIf(!aliveClasses.isEmpty(), "should be unloaded: " + aliveClasses); } } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java b/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java index 2ae46a36229..8c0c23e2a8b 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java @@ -125,7 +125,7 @@ private static void test() throws Exception { new DwarfConstraint(1, "Java_TestDwarf_crashNativeMultipleMethods", "libTestDwarf.c", 70)); } runAndCheck(new Flags(TestDwarf.class.getCanonicalName(), "nativeDereferenceNull"), - new DwarfConstraint(0, "dereference_null", "libTestDwarfHelper.h", 44)); + new DwarfConstraint(0, "dereference_null", "libTestDwarfHelper.h", 46)); } // The full pattern accepts lines like: diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/libTestDwarfHelper.h b/test/hotspot/jtreg/runtime/ErrorHandling/libTestDwarfHelper.h index 3a162560b89..1da05c1c3d3 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/libTestDwarfHelper.h +++ b/test/hotspot/jtreg/runtime/ErrorHandling/libTestDwarfHelper.h @@ -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 @@ -21,9 +21,11 @@ * questions. */ -#include "jni.h" #include +#include "export.h" +#include "jni.h" + void unused1() { } @@ -39,7 +41,7 @@ void unused4() { void unused5() { } -void dereference_null() { +EXPORT void dereference_null() { int* x = (int*)0; *x = 34; // Crash } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/CDSMHTest_generate.sh b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/CDSMHTest_generate.sh index be4fab7794d..9c1ceec9119 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/CDSMHTest_generate.sh +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/CDSMHTest_generate.sh @@ -1,5 +1,5 @@ #!/bin/bash -# 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 @@ -31,7 +31,7 @@ do fname="$i$name_suffix" cat << EOF > $fname /* - * 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 @@ -81,6 +81,7 @@ import org.junit.Test; import java.io.File; import java.nio.file.Path; import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; public class $i extends DynamicArchiveTestBase { @Test @@ -98,6 +99,12 @@ public class $i extends DynamicArchiveTestBase { private static final String lambdaLoadedFromArchive = ".class.load. test.java.lang.invoke.$i[$][$]Lambda.*/0x.*source:.*shared.*objects.*file.*(top)"; + static void checkError(OutputAnalyzer output) throws Exception { + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Was the base archive generated with an outdated classlist?"); + } + } + static void testImpl() throws Exception { String topArchiveName = getNewArchiveName(); String appJar = JarBuilder.build("MH", new File(classDir), null); @@ -111,6 +118,7 @@ public class $i extends DynamicArchiveTestBase { String className = testPackageName + "." + testClassName; dump(topArchiveName, loggingOpts, "-cp", jars, verifyOpt, mainClass, className) + .assertNormalExit(output -> checkError(output)) .assertNormalExit(output -> { output.shouldContain("Written dynamic archive 0x"); }); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesAsCollectorTest.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesAsCollectorTest.java index 5971e3d1f2e..0abb20a5ad6 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesAsCollectorTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesAsCollectorTest.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 @@ -21,7 +21,7 @@ * questions. * */ -// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually. +// this file is auto-generated by CDSMHTest_generate.sh. Do not edit manually. /* * @test @@ -49,6 +49,7 @@ import java.io.File; import java.nio.file.Path; import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; public class MethodHandlesAsCollectorTest extends DynamicArchiveTestBase { @Test @@ -66,6 +67,12 @@ public void test() throws Exception { private static final String lambdaLoadedFromArchive = ".class.load. test.java.lang.invoke.MethodHandlesAsCollectorTest[$][$]Lambda.*/0x.*source:.*shared.*objects.*file.*(top)"; + static void checkError(OutputAnalyzer output) throws Exception { + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Was the base archive generated with an outdated classlist?"); + } + } + static void testImpl() throws Exception { String topArchiveName = getNewArchiveName(); String appJar = JarBuilder.build("MH", new File(classDir), null); @@ -79,6 +86,7 @@ static void testImpl() throws Exception { String className = testPackageName + "." + testClassName; dump(topArchiveName, loggingOpts, "-cp", jars, verifyOpt, mainClass, className) + .assertNormalExit(output -> checkError(output)) .assertNormalExit(output -> { output.shouldContain("Written dynamic archive 0x"); }); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesCastFailureTest.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesCastFailureTest.java index 085bc8b3392..bbc230f04d0 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesCastFailureTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesCastFailureTest.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 @@ -21,7 +21,7 @@ * questions. * */ -// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually. +// this file is auto-generated by CDSMHTest_generate.sh. Do not edit manually. /* * @test @@ -49,6 +49,7 @@ import java.io.File; import java.nio.file.Path; import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; public class MethodHandlesCastFailureTest extends DynamicArchiveTestBase { @Test @@ -66,6 +67,12 @@ public void test() throws Exception { private static final String lambdaLoadedFromArchive = ".class.load. test.java.lang.invoke.MethodHandlesCastFailureTest[$][$]Lambda.*/0x.*source:.*shared.*objects.*file.*(top)"; + static void checkError(OutputAnalyzer output) throws Exception { + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Was the base archive generated with an outdated classlist?"); + } + } + static void testImpl() throws Exception { String topArchiveName = getNewArchiveName(); String appJar = JarBuilder.build("MH", new File(classDir), null); @@ -79,6 +86,7 @@ static void testImpl() throws Exception { String className = testPackageName + "." + testClassName; dump(topArchiveName, loggingOpts, "-cp", jars, verifyOpt, mainClass, className) + .assertNormalExit(output -> checkError(output)) .assertNormalExit(output -> { output.shouldContain("Written dynamic archive 0x"); }); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesGeneralTest.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesGeneralTest.java index f833f8f6d54..f20dd67baf2 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesGeneralTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesGeneralTest.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 @@ -21,7 +21,7 @@ * questions. * */ -// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually. +// this file is auto-generated by CDSMHTest_generate.sh. Do not edit manually. /* * @test @@ -49,6 +49,7 @@ import java.io.File; import java.nio.file.Path; import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; public class MethodHandlesGeneralTest extends DynamicArchiveTestBase { @Test @@ -66,6 +67,12 @@ public void test() throws Exception { private static final String lambdaLoadedFromArchive = ".class.load. test.java.lang.invoke.MethodHandlesGeneralTest[$][$]Lambda.*/0x.*source:.*shared.*objects.*file.*(top)"; + static void checkError(OutputAnalyzer output) throws Exception { + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Was the base archive generated with an outdated classlist?"); + } + } + static void testImpl() throws Exception { String topArchiveName = getNewArchiveName(); String appJar = JarBuilder.build("MH", new File(classDir), null); @@ -79,6 +86,7 @@ static void testImpl() throws Exception { String className = testPackageName + "." + testClassName; dump(topArchiveName, loggingOpts, "-cp", jars, verifyOpt, mainClass, className) + .assertNormalExit(output -> checkError(output)) .assertNormalExit(output -> { output.shouldContain("Written dynamic archive 0x"); }); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesInvokersTest.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesInvokersTest.java index 06116753ec6..2adf0736156 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesInvokersTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesInvokersTest.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 @@ -21,7 +21,7 @@ * questions. * */ -// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually. +// this file is auto-generated by CDSMHTest_generate.sh. Do not edit manually. /* * @test @@ -49,6 +49,7 @@ import java.io.File; import java.nio.file.Path; import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; public class MethodHandlesInvokersTest extends DynamicArchiveTestBase { @Test @@ -66,6 +67,12 @@ public void test() throws Exception { private static final String lambdaLoadedFromArchive = ".class.load. test.java.lang.invoke.MethodHandlesInvokersTest[$][$]Lambda.*/0x.*source:.*shared.*objects.*file.*(top)"; + static void checkError(OutputAnalyzer output) throws Exception { + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Was the base archive generated with an outdated classlist?"); + } + } + static void testImpl() throws Exception { String topArchiveName = getNewArchiveName(); String appJar = JarBuilder.build("MH", new File(classDir), null); @@ -79,6 +86,7 @@ static void testImpl() throws Exception { String className = testPackageName + "." + testClassName; dump(topArchiveName, loggingOpts, "-cp", jars, verifyOpt, mainClass, className) + .assertNormalExit(output -> checkError(output)) .assertNormalExit(output -> { output.shouldContain("Written dynamic archive 0x"); }); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesPermuteArgumentsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesPermuteArgumentsTest.java index 19db0f1e1a8..92054fe615c 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesPermuteArgumentsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesPermuteArgumentsTest.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 @@ -21,7 +21,7 @@ * questions. * */ -// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually. +// this file is auto-generated by CDSMHTest_generate.sh. Do not edit manually. /* * @test @@ -49,6 +49,7 @@ import java.io.File; import java.nio.file.Path; import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; public class MethodHandlesPermuteArgumentsTest extends DynamicArchiveTestBase { @Test @@ -66,6 +67,12 @@ public void test() throws Exception { private static final String lambdaLoadedFromArchive = ".class.load. test.java.lang.invoke.MethodHandlesPermuteArgumentsTest[$][$]Lambda.*/0x.*source:.*shared.*objects.*file.*(top)"; + static void checkError(OutputAnalyzer output) throws Exception { + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Was the base archive generated with an outdated classlist?"); + } + } + static void testImpl() throws Exception { String topArchiveName = getNewArchiveName(); String appJar = JarBuilder.build("MH", new File(classDir), null); @@ -79,6 +86,7 @@ static void testImpl() throws Exception { String className = testPackageName + "." + testClassName; dump(topArchiveName, loggingOpts, "-cp", jars, verifyOpt, mainClass, className) + .assertNormalExit(output -> checkError(output)) .assertNormalExit(output -> { output.shouldContain("Written dynamic archive 0x"); }); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesSpreadArgumentsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesSpreadArgumentsTest.java index ae67716a852..0d7d3f84f41 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesSpreadArgumentsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/methodHandles/MethodHandlesSpreadArgumentsTest.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 @@ -21,7 +21,7 @@ * questions. * */ -// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually. +// this file is auto-generated by CDSMHTest_generate.sh. Do not edit manually. /* * @test @@ -49,6 +49,7 @@ import java.io.File; import java.nio.file.Path; import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; public class MethodHandlesSpreadArgumentsTest extends DynamicArchiveTestBase { @Test @@ -66,6 +67,12 @@ public void test() throws Exception { private static final String lambdaLoadedFromArchive = ".class.load. test.java.lang.invoke.MethodHandlesSpreadArgumentsTest[$][$]Lambda.*/0x.*source:.*shared.*objects.*file.*(top)"; + static void checkError(OutputAnalyzer output) throws Exception { + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Was the base archive generated with an outdated classlist?"); + } + } + static void testImpl() throws Exception { String topArchiveName = getNewArchiveName(); String appJar = JarBuilder.build("MH", new File(classDir), null); @@ -79,6 +86,7 @@ static void testImpl() throws Exception { String className = testPackageName + "." + testClassName; dump(topArchiveName, loggingOpts, "-cp", jars, verifyOpt, mainClass, className) + .assertNormalExit(output -> checkError(output)) .assertNormalExit(output -> { output.shouldContain("Written dynamic archive 0x"); }); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/CDSMHTest_generate.sh b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/CDSMHTest_generate.sh index a593fcffc03..562d9ef0ef5 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/CDSMHTest_generate.sh +++ b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/CDSMHTest_generate.sh @@ -1,5 +1,5 @@ #!/bin/bash -# 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 @@ -31,7 +31,7 @@ do fname="$i$name_suffix" cat << EOF > $fname /* - * 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 @@ -121,7 +121,10 @@ public class $i { "-cp", jars, "-Xlog:class+load,cds") .setArchiveName(archiveName); - CDSTestUtils.createArchiveAndCheck(opts); + OutputAnalyzer output = CDSTestUtils.createArchiveAndCheck(opts); + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Is your classlist out of date?"); + } // run with archive CDSOptions runOpts = (new CDSOptions()) @@ -129,7 +132,7 @@ public class $i { .setArchiveName(archiveName) .setUseVersion(false) .addSuffix(mainClass, testPackageName + "." + testClassName); - OutputAnalyzer output = CDSTestUtils.runWithArchive(runOpts); + output = CDSTestUtils.runWithArchive(runOpts); output.shouldMatch(".class.load. test.java.lang.invoke.$i[$][$]Lambda.*/0x.*source:.*shared.*objects.*file") .shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesAsCollectorTest.java b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesAsCollectorTest.java index 605f0d4c72b..dbfa2d56e6a 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesAsCollectorTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesAsCollectorTest.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 @@ -21,7 +21,7 @@ * questions. * */ -// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually. +// this file is auto-generated by CDSMHTest_generate.sh. Do not edit manually. /* * @test @@ -89,7 +89,10 @@ static void testImpl() throws Exception { "-cp", jars, "-Xlog:class+load,cds") .setArchiveName(archiveName); - CDSTestUtils.createArchiveAndCheck(opts); + OutputAnalyzer output = CDSTestUtils.createArchiveAndCheck(opts); + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Is your classlist out of date?"); + } // run with archive CDSOptions runOpts = (new CDSOptions()) @@ -97,7 +100,7 @@ static void testImpl() throws Exception { .setArchiveName(archiveName) .setUseVersion(false) .addSuffix(mainClass, testPackageName + "." + testClassName); - OutputAnalyzer output = CDSTestUtils.runWithArchive(runOpts); + output = CDSTestUtils.runWithArchive(runOpts); output.shouldMatch(".class.load. test.java.lang.invoke.MethodHandlesAsCollectorTest[$][$]Lambda.*/0x.*source:.*shared.*objects.*file") .shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesCastFailureTest.java b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesCastFailureTest.java index f46fa10dc04..bccc787709b 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesCastFailureTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesCastFailureTest.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 @@ -21,7 +21,7 @@ * questions. * */ -// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually. +// this file is auto-generated by CDSMHTest_generate.sh. Do not edit manually. /* * @test @@ -89,7 +89,10 @@ static void testImpl() throws Exception { "-cp", jars, "-Xlog:class+load,cds") .setArchiveName(archiveName); - CDSTestUtils.createArchiveAndCheck(opts); + OutputAnalyzer output = CDSTestUtils.createArchiveAndCheck(opts); + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Is your classlist out of date?"); + } // run with archive CDSOptions runOpts = (new CDSOptions()) @@ -97,7 +100,7 @@ static void testImpl() throws Exception { .setArchiveName(archiveName) .setUseVersion(false) .addSuffix(mainClass, testPackageName + "." + testClassName); - OutputAnalyzer output = CDSTestUtils.runWithArchive(runOpts); + output = CDSTestUtils.runWithArchive(runOpts); output.shouldMatch(".class.load. test.java.lang.invoke.MethodHandlesCastFailureTest[$][$]Lambda.*/0x.*source:.*shared.*objects.*file") .shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesGeneralTest.java b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesGeneralTest.java index fdd0257df37..3577d07f307 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesGeneralTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesGeneralTest.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 @@ -21,7 +21,7 @@ * questions. * */ -// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually. +// this file is auto-generated by CDSMHTest_generate.sh. Do not edit manually. /* * @test @@ -89,7 +89,10 @@ static void testImpl() throws Exception { "-cp", jars, "-Xlog:class+load,cds") .setArchiveName(archiveName); - CDSTestUtils.createArchiveAndCheck(opts); + OutputAnalyzer output = CDSTestUtils.createArchiveAndCheck(opts); + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Is your classlist out of date?"); + } // run with archive CDSOptions runOpts = (new CDSOptions()) @@ -97,7 +100,7 @@ static void testImpl() throws Exception { .setArchiveName(archiveName) .setUseVersion(false) .addSuffix(mainClass, testPackageName + "." + testClassName); - OutputAnalyzer output = CDSTestUtils.runWithArchive(runOpts); + output = CDSTestUtils.runWithArchive(runOpts); output.shouldMatch(".class.load. test.java.lang.invoke.MethodHandlesGeneralTest[$][$]Lambda.*/0x.*source:.*shared.*objects.*file") .shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesInvokersTest.java b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesInvokersTest.java index bb31ff1f66f..f500b568f50 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesInvokersTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesInvokersTest.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 @@ -21,7 +21,7 @@ * questions. * */ -// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually. +// this file is auto-generated by CDSMHTest_generate.sh. Do not edit manually. /* * @test @@ -89,7 +89,10 @@ static void testImpl() throws Exception { "-cp", jars, "-Xlog:class+load,cds") .setArchiveName(archiveName); - CDSTestUtils.createArchiveAndCheck(opts); + OutputAnalyzer output = CDSTestUtils.createArchiveAndCheck(opts); + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Is your classlist out of date?"); + } // run with archive CDSOptions runOpts = (new CDSOptions()) @@ -97,7 +100,7 @@ static void testImpl() throws Exception { .setArchiveName(archiveName) .setUseVersion(false) .addSuffix(mainClass, testPackageName + "." + testClassName); - OutputAnalyzer output = CDSTestUtils.runWithArchive(runOpts); + output = CDSTestUtils.runWithArchive(runOpts); output.shouldMatch(".class.load. test.java.lang.invoke.MethodHandlesInvokersTest[$][$]Lambda.*/0x.*source:.*shared.*objects.*file") .shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesPermuteArgumentsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesPermuteArgumentsTest.java index 1ca3f2882f0..b2e2a834c36 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesPermuteArgumentsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesPermuteArgumentsTest.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 @@ -21,7 +21,7 @@ * questions. * */ -// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually. +// this file is auto-generated by CDSMHTest_generate.sh. Do not edit manually. /* * @test @@ -89,7 +89,10 @@ static void testImpl() throws Exception { "-cp", jars, "-Xlog:class+load,cds") .setArchiveName(archiveName); - CDSTestUtils.createArchiveAndCheck(opts); + OutputAnalyzer output = CDSTestUtils.createArchiveAndCheck(opts); + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Is your classlist out of date?"); + } // run with archive CDSOptions runOpts = (new CDSOptions()) @@ -97,7 +100,7 @@ static void testImpl() throws Exception { .setArchiveName(archiveName) .setUseVersion(false) .addSuffix(mainClass, testPackageName + "." + testClassName); - OutputAnalyzer output = CDSTestUtils.runWithArchive(runOpts); + output = CDSTestUtils.runWithArchive(runOpts); output.shouldMatch(".class.load. test.java.lang.invoke.MethodHandlesPermuteArgumentsTest[$][$]Lambda.*/0x.*source:.*shared.*objects.*file") .shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesSpreadArgumentsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesSpreadArgumentsTest.java index 514e118e95d..a0d7d0f9949 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesSpreadArgumentsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/MethodHandlesSpreadArgumentsTest.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 @@ -21,7 +21,7 @@ * questions. * */ -// this file is auto-generated by ./CDSMHTest_generate.sh. Do not edit manually. +// this file is auto-generated by CDSMHTest_generate.sh. Do not edit manually. /* * @test @@ -89,7 +89,10 @@ static void testImpl() throws Exception { "-cp", jars, "-Xlog:class+load,cds") .setArchiveName(archiveName); - CDSTestUtils.createArchiveAndCheck(opts); + OutputAnalyzer output = CDSTestUtils.createArchiveAndCheck(opts); + if (testClassName.equals("MethodHandlesInvokersTest")) { + output.shouldNotContain("Failed to generate LambdaForm holder classes. Is your classlist out of date?"); + } // run with archive CDSOptions runOpts = (new CDSOptions()) @@ -97,7 +100,7 @@ static void testImpl() throws Exception { .setArchiveName(archiveName) .setUseVersion(false) .addSuffix(mainClass, testPackageName + "." + testClassName); - OutputAnalyzer output = CDSTestUtils.runWithArchive(runOpts); + output = CDSTestUtils.runWithArchive(runOpts); output.shouldMatch(".class.load. test.java.lang.invoke.MethodHandlesSpreadArgumentsTest[$][$]Lambda.*/0x.*source:.*shared.*objects.*file") .shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.java b/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.java index 4d59cfa89ab..7fd4726d9c6 100644 --- a/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.java +++ b/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.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 @@ -70,10 +70,13 @@ static void checkAbsent(OutputAnalyzer output, String... outputStrings) throws E // Use the same command-line heap size setting as ../ClassUnload/UnloadTest.java static OutputAnalyzer exec(String... args) throws Exception { + String classPath = System.getProperty("test.class.path", "."); + + // Sub-process does not get all the properties automatically, so the test class path needs to be passed explicitly List argsList = new ArrayList<>(); Collections.addAll(argsList, args); Collections.addAll(argsList, "-Xmn8m", "-Xbootclasspath/a:.", "-XX:+UnlockDiagnosticVMOptions", - "-XX:+WhiteBoxAPI", "-XX:+ClassUnloading", ClassUnloadTestMain.class.getName()); + "-XX:+WhiteBoxAPI", "-XX:+ClassUnloading", "-Dtest.class.path=" + classPath, ClassUnloadTestMain.class.getName()); ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(argsList); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); @@ -86,7 +89,7 @@ public static void main(String... args) throws Exception { // -Xlog:class+unload=info output = exec("-Xlog:class+unload=info"); - checkFor(output, "[class,unload]", "unloading class"); + checkFor(output, "[class,unload]", "unloading class test.Empty"); // -Xlog:class+unload=off output = exec("-Xlog:class+unload=off"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack001.java b/test/hotspot/jtreg/runtime/stack/Stack001.java similarity index 79% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack001.java rename to test/hotspot/jtreg/runtime/stack/Stack001.java index 3ded4d236a3..b344e177499 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack001.java +++ b/test/hotspot/jtreg/runtime/stack/Stack001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -52,25 +52,14 @@ * 4302288 the second stack overflow causes Classic VM to exit on win32 * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack001 + * @run main/othervm/timeout=900 Stack001 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack001 { +public class Stack001 { public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { - stack001 test = new stack001(); + Stack001 test = new Stack001(); test.recurse(0); - out.println("Maximal depth: " + test.maxdepth); - return 0; + System.out.println("Maximal depth: " + test.maxdepth); } private int maxdepth; @@ -79,13 +68,10 @@ private void recurse(int depth) { maxdepth = depth; try { recurse(depth + 1); - } catch (Error error) { - if (!(error instanceof StackOverflowError) && - !(error instanceof OutOfMemoryError)) - throw error; - - if (maxdepth == depth) + } catch (StackOverflowError | OutOfMemoryError e) { + if (maxdepth == depth) { recurse(depth + 1); + } } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack002.java b/test/hotspot/jtreg/runtime/stack/Stack002.java similarity index 80% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack002.java rename to test/hotspot/jtreg/runtime/stack/Stack002.java index 3844c88a322..320e74512fa 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack002.java +++ b/test/hotspot/jtreg/runtime/stack/Stack002.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 @@ -53,24 +53,14 @@ * 4302288 the second stack overflow causes Classic VM to exit on win32 * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack002 + * @run main/othervm/timeout=900 Stack002 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack002 { +public class Stack002 { static final long timeout = 10000; // 10 seconds public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { - Tester tester = new Tester(out); + Tester tester = new Tester(); Timer timer = new Timer(tester); timer.start(); tester.start(); @@ -78,21 +68,18 @@ public static int run(String args[], PrintStream out) { try { timer.join(); } catch (InterruptedException e) { - e.printStackTrace(out); - return 2; + e.printStackTrace(); + throw new RuntimeException(e); } } - out.println("Maximal depth: " + tester.maxdepth); - return 0; + System.out.println("Maximal depth: " + tester.maxdepth); } private static class Tester extends Thread { int maxdepth; - PrintStream out; public volatile boolean stop; - public Tester(PrintStream out) { - this.out = out; + public Tester() { maxdepth = 0; stop = false; } @@ -108,10 +95,7 @@ void recurse(int depth) { return; } recurse(depth + 1); - } catch (Error error) { - if (!(error instanceof StackOverflowError) && - !(error instanceof OutOfMemoryError)) - throw error; + } catch (StackOverflowError | OutOfMemoryError e) { recurse(depth + 1); } } @@ -129,9 +113,9 @@ public void run() { started = System.currentTimeMillis(); while (System.currentTimeMillis() - started < timeout) { try { - this.sleep(1000); + Thread.sleep(1000); } catch (InterruptedException e) { - e.printStackTrace(tester.out); + e.printStackTrace(); return; }; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack003.java b/test/hotspot/jtreg/runtime/stack/Stack003.java similarity index 75% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack003.java rename to test/hotspot/jtreg/runtime/stack/Stack003.java index f8a122c2b67..260344456c9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack003.java +++ b/test/hotspot/jtreg/runtime/stack/Stack003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -47,48 +47,37 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack003 + * @run main/othervm/timeout=900 Stack003 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack003 { +public class Stack003 { final static int ITERATIONS = 100; final static int INCREMENT = 100; public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - public static int run(String args[], PrintStream out) { int depth; - for (depth = 1; ; depth += INCREMENT) + for (depth = 1; ; depth += INCREMENT) { try { recurse(depth); - } catch (StackOverflowError soe) { - break; - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError err) { break; } - out.println("Max. depth: " + depth); - for (int i = 0; i < ITERATIONS; i++) + } + System.out.println("Max. depth: " + depth); + for (int i = 0; i < ITERATIONS; i++) { try { recurse(2 * depth); - out.println("?"); - } catch (StackOverflowError soe) { + System.out.println("?"); + } catch (StackOverflowError | OutOfMemoryError err) { // OK. - } catch (OutOfMemoryError oome) { - // Also OK. } - return 0; + } } static void recurse(int depth) { - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack004.java b/test/hotspot/jtreg/runtime/stack/Stack004.java similarity index 73% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack004.java rename to test/hotspot/jtreg/runtime/stack/Stack004.java index b7bff2aedb5..fb9b594421b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack004.java +++ b/test/hotspot/jtreg/runtime/stack/Stack004.java @@ -47,51 +47,38 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack004 + * @run main/othervm/timeout=900 Stack004 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack004 { +public class Stack004 { public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); + Stack004 test = new Stack004(); + test.doRun(); } - public static int run(String args[], PrintStream out) { - stack004 test = new stack004(); - int exitCode = test.doRun(args, out); - return exitCode; - } - - public int doRun(String args[], PrintStream out) { + public void doRun() { int depth; - for (depth = 100; ; depth += 100) + for (depth = 100; ; depth += 100) { try { recurse(depth); - } catch (StackOverflowError soe) { - break; - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError err) { break; } - out.println("Max. depth: " + depth); - for (int i = 0; i < 100; i++) + } + System.out.println("Max. depth: " + depth); + for (int i = 0; i < 100; i++) { try { recurse(2 * depth); - out.println("?"); - } catch (StackOverflowError soe) { + System.out.println("?"); + } catch (StackOverflowError | OutOfMemoryError err) { // OK. - } catch (OutOfMemoryError oome) { - // Also OK. } - return 0; + } } final static void recurse(int depth) { - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack005.java b/test/hotspot/jtreg/runtime/stack/Stack005.java similarity index 74% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack005.java rename to test/hotspot/jtreg/runtime/stack/Stack005.java index a5bd10595fc..35963e03bc8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack005.java +++ b/test/hotspot/jtreg/runtime/stack/Stack005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -47,46 +47,34 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack005 + * @run main/othervm/timeout=900 Stack005 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack005 { +public class Stack005 { public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { - stack005 test = new stack005(); + Stack005 test = new Stack005(); int depth; - for (depth = 100; ; depth += 100) + for (depth = 100; ; depth += 100) { try { test.recurse(depth); - } catch (StackOverflowError soe) { - break; - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError soe) { break; } - out.println("Max. depth: " + depth); - for (int i = 0; i < 100; i++) + } + System.out.println("Max. depth: " + depth); + for (int i = 0; i < 100; i++) { try { test.recurse(2 * depth); - out.println("?"); - } catch (StackOverflowError soe) { + System.out.println("?"); + } catch (StackOverflowError | OutOfMemoryError err) { // OK. - } catch (OutOfMemoryError oome) { - // Also OK. } - return 0; + } } final void recurse(int depth) { - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack006.java b/test/hotspot/jtreg/runtime/stack/Stack006.java similarity index 74% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack006.java rename to test/hotspot/jtreg/runtime/stack/Stack006.java index 2b8754dd2ae..313fdd02c6a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack006.java +++ b/test/hotspot/jtreg/runtime/stack/Stack006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -47,50 +47,38 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack006 + * @run main/othervm/timeout=900 Stack006 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack006 implements stack006i { +public class Stack006 implements Stack006i { public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { - stack006i test = new stack006(); + Stack006i test = new Stack006(); int depth; - for (depth = 100; ; depth += 100) + for (depth = 100; ; depth += 100) { try { test.recurse(depth); - } catch (StackOverflowError soe) { - break; - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError err) { break; } - out.println("Max. depth: " + depth); - for (int i = 0; i < 100; i++) + } + System.out.println("Max. depth: " + depth); + for (int i = 0; i < 100; i++) { try { test.recurse(2 * depth); - out.println("?"); - } catch (StackOverflowError soe) { + System.out.println("?"); + } catch (StackOverflowError | OutOfMemoryError err) { // OK. - } catch (OutOfMemoryError oome) { - // Also OK. } - return 0; + } } public void recurse(int depth) { - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } } -interface stack006i { +interface Stack006i { void recurse(int depth); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack007.java b/test/hotspot/jtreg/runtime/stack/Stack007.java similarity index 74% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack007.java rename to test/hotspot/jtreg/runtime/stack/Stack007.java index 1a9b7f0d392..d8849dd847c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack007.java +++ b/test/hotspot/jtreg/runtime/stack/Stack007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -46,53 +46,41 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack007 + * @run main/othervm/timeout=900 Stack007 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack007 implements stack007i { +public class Stack007 implements Stack007i { final static int ITERATIONS = 1000; final static int INCREMENT = 100; public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { - stack007i test = new stack007(); + Stack007i test = new Stack007(); int depth; - for (depth = 100; ; depth += INCREMENT) + for (depth = 100; ; depth += INCREMENT) { try { test.recurse(depth); - } catch (StackOverflowError soe) { - break; - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError err) { break; } - out.println("Max. depth: " + depth); - for (int i = 0; i < ITERATIONS; i++) + } + System.out.println("Max. depth: " + depth); + for (int i = 0; i < ITERATIONS; i++) { try { test.recurse(10 * depth); - out.println("?"); - } catch (StackOverflowError soe) { + System.out.println("?"); + } catch (StackOverflowError | OutOfMemoryError err) { // OK. - } catch (OutOfMemoryError oome) { - // Also OK. } - return 0; + } } public synchronized void recurse(int depth) { - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } } -interface stack007i { +interface Stack007i { void recurse(int depth); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack008.java b/test/hotspot/jtreg/runtime/stack/Stack008.java similarity index 80% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack008.java rename to test/hotspot/jtreg/runtime/stack/Stack008.java index a90f237aa76..e1776a0bcb7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack008.java +++ b/test/hotspot/jtreg/runtime/stack/Stack008.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -48,28 +48,19 @@ * Making it bigger could cause timeouts on other platform. * * @requires (vm.opt.DeoptimizeALot != true & vm.compMode != "Xcomp" & vm.pageSize == 4096) - * @run main/othervm/timeout=900 -Xss200K nsk.stress.stack.stack008 + * @run main/othervm/timeout=900 -Xss200K Stack008 */ -package nsk.stress.stack; - - -import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -public class stack008 { +public class Stack008 { public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { int depth; // // Measure maximal recursion depth until stack overflow: // - for (depth = 100; ; depth += 100) + for (depth = 100; ; depth += 100) { try { invokeRecurse(depth); } catch (Throwable exception) { @@ -77,30 +68,27 @@ public static int run(String args[], PrintStream out) { if ((target instanceof StackOverflowError) || (target instanceof OutOfMemoryError)) break; // OK. - target.printStackTrace(out); - if (target instanceof ThreadDeath) - throw (ThreadDeath) target; - return 2; + target.printStackTrace(); + throw new RuntimeException(exception); } - out.println("Max. depth: " + depth); + } + System.out.println("Max. depth: " + depth); // // Provoke stack overflow multiple times: // - for (int i = 0; i < 100; i++) + for (int i = 0; i < 100; i++) { try { invokeRecurse(2 * depth); -// out.println("?"); +// System.out.println("?"); } catch (Throwable exception) { Throwable target = getTargetException(exception); if ((target instanceof StackOverflowError) || (target instanceof OutOfMemoryError)) continue; // OK. - target.printStackTrace(out); - if (target instanceof ThreadDeath) - throw (ThreadDeath) target; - return 2; + target.printStackTrace(); + throw new RuntimeException(exception); } - return 0; + } } private static Throwable getTargetException(Throwable exception) { @@ -118,7 +106,7 @@ private static Throwable getTargetException(Throwable exception) { } static Method method = null; - static stack008 instance = null; + static Stack008 instance = null; static Object params[] = null; private static void invokeRecurse(int depth) throws Exception { @@ -126,8 +114,8 @@ private static void invokeRecurse(int depth) throws Exception { // // Optimization trick: allocate once, use everywhere. // - instance = new stack008(); - method = stack008.class.getMethod("recurse"); + instance = new Stack008(); + method = Stack008.class.getMethod("recurse"); params = new Object[]{}; } // @@ -140,10 +128,11 @@ private static void invokeRecurse(int depth) throws Exception { int depth = 0; public void recurse() throws Exception { - if (depth > 0) + if (depth > 0) { // // Self-invoke via reflection: // invokeRecurse(depth - 1); + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack009.java b/test/hotspot/jtreg/runtime/stack/Stack009.java similarity index 70% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack009.java rename to test/hotspot/jtreg/runtime/stack/Stack009.java index b8f52d0a3f2..f2cbb51b304 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack009.java +++ b/test/hotspot/jtreg/runtime/stack/Stack009.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -47,49 +47,32 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack009 + * @run main/othervm/timeout=900 Stack009 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack009 { +public class Stack009 { public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { - for (int depth = 100; ; depth += 100) + for (int depth = 100; ; depth += 100) { try { recurse(depth); - } catch (Error error1) { - if (!(error1 instanceof StackOverflowError) && - !(error1 instanceof OutOfMemoryError)) - throw error1; + } catch (StackOverflowError | OutOfMemoryError error1) { - out.println("Max. depth: " + depth); + System.out.println("Max. depth: " + depth); try { recurse(10 * depth); - out.println("?"); - } catch (Error error2) { - if (!(error2 instanceof StackOverflowError) && - !(error2 instanceof OutOfMemoryError)) - throw error2; - - // Stack overflow is OK here. + System.out.println("?"); + } catch (StackOverflowError | OutOfMemoryError error2) { + // ignore } - break; } - return 0; + } } static void recurse(int depth) { - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack010.java b/test/hotspot/jtreg/runtime/stack/Stack010.java similarity index 67% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack010.java rename to test/hotspot/jtreg/runtime/stack/Stack010.java index 6c4c159b58f..142c7ab6cb2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack010.java +++ b/test/hotspot/jtreg/runtime/stack/Stack010.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -47,99 +47,82 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack010 + * @run main/othervm/timeout=900 Stack010 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack010 extends Thread { - final static int THREADS = 10; - final static int CYCLES = 10; +public class Stack010 extends Thread { + final static int THREADS = 1; + final static int CYCLES = 1; public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { // // Measure maximal recursion depth until stack overflow: // int maxDepth = 0; - for (int depth = 10; ; depth += 10) + for (int depth = 10; ; depth += 10) { try { recurse(depth); maxDepth = depth; - } catch (StackOverflowError soe) { - break; - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError err) { break; } - out.println("Max. depth: " + maxDepth); + } + System.out.println("Max. depth: " + maxDepth); // // Execute multiple threads repeatedly provoking stack overflows: // - stack010 threads[] = new stack010[THREADS]; + Stack010 threads[] = new Stack010[THREADS]; for (int i = 0; i < threads.length; i++) { - threads[i] = new stack010(); - threads[i].depthToTry = 10 * maxDepth; + threads[i] = new Stack010(); + threads[i].depthToTry = 100 * maxDepth; threads[i].start(); } - for (int i = 0; i < threads.length; i++) - if (threads[i].isAlive()) + for (int i = 0; i < threads.length; i++) { + if (threads[i].isAlive()) { try { threads[i].join(); } catch (InterruptedException exception) { - exception.printStackTrace(out); - return 2; + throw new RuntimeException(exception); } - + } + } // // Check if unexpected exceptions were not thrown: // - int exitCode = 0; - for (int i = 0; i < threads.length; i++) + for (int i = 0; i < threads.length; i++) { if (threads[i].thrown != null) { - threads[i].thrown.printStackTrace(out); - exitCode = 2; + threads[i].thrown.printStackTrace(); + throw new RuntimeException("Exception in the thread " + threads[i], threads[i].thrown); } - - if (exitCode != 0) - out.println("# TEST FAILED"); - return exitCode; + } } int depthToTry = 0; Throwable thrown = null; public void run() { - for (int i = 0; i < CYCLES; i++) + for (int i = 0; i < CYCLES; i++) { try { + System.out.println("depth = " +depthToTry); recurse(depthToTry); throw new Exception( "TEST_RFE: no stack overflow thrown" + ", need to try deeper recursion?"); - } catch (StackOverflowError soe) { - // It's OK: stack overflow was expected. - } catch (OutOfMemoryError oome) { - // Also OK: out of memory may indacate stack overflow. - + } catch (StackOverflowError | OutOfMemoryError err) { + // It's OK } catch (Throwable throwable) { - if (throwable instanceof ThreadDeath) - throw (ThreadDeath) throwable; // It isn't OK! thrown = throwable; break; } + } } static void recurse(int depth) { - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack011.java b/test/hotspot/jtreg/runtime/stack/Stack011.java similarity index 70% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack011.java rename to test/hotspot/jtreg/runtime/stack/Stack011.java index 81e26f575d7..423e009c912 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack011.java +++ b/test/hotspot/jtreg/runtime/stack/Stack011.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -47,99 +47,81 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack011 + * @run main/othervm/timeout=900 Stack011 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack011 extends Thread { +public class Stack011 extends Thread { final static int THREADS = 10; final static int CYCLES = 10; public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { // // Measure maximal recursion depth until stack overflow: // int maxDepth = 0; - for (int depth = 10; ; depth += 10) + for (int depth = 10; ; depth += 10) { try { recurse(depth); maxDepth = depth; - } catch (StackOverflowError soe) { - break; - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError soe) { break; } - out.println("Max. depth: " + maxDepth); + } + System.out.println("Max. depth: " + maxDepth); // // Execute multiple threads repeatedly provoking stack overflows: // - stack011 threads[] = new stack011[THREADS]; + Stack011 threads[] = new Stack011[THREADS]; for (int i = 0; i < threads.length; i++) { - threads[i] = new stack011(); + threads[i] = new Stack011(); threads[i].depthToTry = 10 * maxDepth; threads[i].start(); } - for (int i = 0; i < threads.length; i++) - if (threads[i].isAlive()) + for (int i = 0; i < threads.length; i++) { + if (threads[i].isAlive()) { try { threads[i].join(); } catch (InterruptedException exception) { - exception.printStackTrace(out); - return 2; + throw new RuntimeException(exception); } - + } + } // // Check if unexpected exceptions were not thrown: // - int exitCode = 0; - for (int i = 0; i < threads.length; i++) + for (int i = 0; i < threads.length; i++) { if (threads[i].thrown != null) { - threads[i].thrown.printStackTrace(out); - exitCode = 2; + threads[i].thrown.printStackTrace(); + throw new RuntimeException("Exception in the thread " + threads[i], threads[i].thrown); } - - if (exitCode != 0) - out.println("# TEST FAILED"); - return exitCode; + } } int depthToTry = 0; Throwable thrown = null; public void run() { - for (int i = 0; i < CYCLES; i++) + for (int i = 0; i < CYCLES; i++) { try { recurse(depthToTry); throw new Exception( "TEST_RFE: no stack overflow thrown" + ", need to try deeper recursion?"); - } catch (StackOverflowError error) { - // It's OK: stack overflow was expected. - } catch (OutOfMemoryError oome) { - // Also OK: recursion may result in memory lack. - + } catch (StackOverflowError | OutOfMemoryError err) { + // It's OK } catch (Throwable throwable) { - if (throwable instanceof ThreadDeath) - throw (ThreadDeath) throwable; // It isn't OK! thrown = throwable; break; } + } } final static void recurse(int depth) { - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack012.java b/test/hotspot/jtreg/runtime/stack/Stack012.java similarity index 70% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack012.java rename to test/hotspot/jtreg/runtime/stack/Stack012.java index 6dc33a83cc8..1edbe215043 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack012.java +++ b/test/hotspot/jtreg/runtime/stack/Stack012.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -48,100 +48,82 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack012 + * @run main/othervm/timeout=900 Stack012 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack012 extends Thread { +public class Stack012 extends Thread { final static int THREADS = 10; final static int CYCLES = 10; public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { - stack012 test = new stack012(); + Stack012 test = new Stack012(); // // Measure maximal recursion depth until stack overflow: // int maxDepth = 0; - for (int depth = 10; ; depth += 10) + for (int depth = 10; ; depth += 10) { try { test.recurse(depth); maxDepth = depth; - } catch (StackOverflowError soe) { - break; - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError err) { break; } - out.println("Max. depth: " + maxDepth); + } + System.out.println("Max. depth: " + maxDepth); // // Execute multiple threads repeatedly provoking stack overflows: // - stack012 threads[] = new stack012[THREADS]; + Stack012 threads[] = new Stack012[THREADS]; for (int i = 0; i < threads.length; i++) { - threads[i] = new stack012(); + threads[i] = new Stack012(); threads[i].depthToTry = 10 * maxDepth; threads[i].start(); } - for (int i = 0; i < threads.length; i++) - if (threads[i].isAlive()) + for (int i = 0; i < threads.length; i++) { + if (threads[i].isAlive()) { try { threads[i].join(); } catch (InterruptedException exception) { - exception.printStackTrace(out); - return 2; + throw new RuntimeException(exception); } - + } + } // // Check if unexpected exceptions were not thrown: // - int exitCode = 0; - for (int i = 0; i < threads.length; i++) + for (int i = 0; i < threads.length; i++) { if (threads[i].thrown != null) { - threads[i].thrown.printStackTrace(out); - exitCode = 2; + threads[i].thrown.printStackTrace(); + throw new RuntimeException("Exception in the thread " + threads[i], threads[i].thrown); } - - if (exitCode != 0) - out.println("# TEST FAILED"); - return exitCode; + } } int depthToTry = 0; Throwable thrown = null; public void run() { - for (int i = 0; i < CYCLES; i++) + for (int i = 0; i < CYCLES; i++) { try { this.recurse(depthToTry); throw new Exception( "TEST_RFE: no stack overflow thrown" + ", need to try deeper recursion?"); - } catch (StackOverflowError error) { - // It's OK: stack overflow was expected. - } catch (OutOfMemoryError oome) { - // Also OK: invocation may result in out of memory. - + } catch (StackOverflowError | OutOfMemoryError err) { + // It's OK } catch (Throwable throwable) { - if (throwable instanceof ThreadDeath) - throw (ThreadDeath) throwable; // It isn't OK! thrown = throwable; break; } + } } final void recurse(int depth) { - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack013.java b/test/hotspot/jtreg/runtime/stack/Stack013.java similarity index 70% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack013.java rename to test/hotspot/jtreg/runtime/stack/Stack013.java index 94a3ef622ef..6c17b780d0e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack013.java +++ b/test/hotspot/jtreg/runtime/stack/Stack013.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -47,81 +47,67 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack013 + * @run main/othervm/timeout=900 Stack013 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack013 extends stack013i { +public class Stack013 extends Stack013i { final static int THREADS = 10; final static int CYCLES = 10; public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { - stack013i test = new stack013(); + Stack013i test = new Stack013(); // // Measure maximal recursion depth until stack overflow: // int maxDepth = 0; - for (int depth = 10; ; depth += 10) + for (int depth = 10; ; depth += 10) { try { test.recurse(depth); maxDepth = depth; - } catch (StackOverflowError soe) { - break; - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError err) { break; } - out.println("Max. depth: " + maxDepth); + } + System.out.println("Max. depth: " + maxDepth); // // Execute multiple threads repeatedly provoking stack overflows: // - stack013i threads[] = new stack013i[THREADS]; + Stack013i threads[] = new Stack013i[THREADS]; for (int i = 0; i < threads.length; i++) { - threads[i] = new stack013(); + threads[i] = new Stack013(); threads[i].depthToTry = 10 * maxDepth; threads[i].cycles = CYCLES; threads[i].start(); } - for (int i = 0; i < threads.length; i++) - if (threads[i].isAlive()) + for (int i = 0; i < threads.length; i++) { + if (threads[i].isAlive()) { try { threads[i].join(); } catch (InterruptedException exception) { - exception.printStackTrace(out); - return 2; + throw new RuntimeException(exception); } - + } + } // // Check if unexpected exceptions were thrown: // - int exitCode = 0; - for (int i = 0; i < threads.length; i++) + for (int i = 0; i < threads.length; i++) { if (threads[i].thrown != null) { - threads[i].thrown.printStackTrace(out); - exitCode = 2; + threads[i].thrown.printStackTrace(); + throw new RuntimeException("Exception in the thread " + threads[i], threads[i].thrown); } - - if (exitCode != 0) - out.println("# TEST FAILED"); - return exitCode; + } } void recurse(int depth) { - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } } -abstract class stack013i extends Thread { +abstract class Stack013i extends Thread { // // Pure virtual method: // @@ -135,24 +121,20 @@ public void run() { // // Provoke multiple stack overflows: // - for (int i = 0; i < cycles; i++) + for (int i = 0; i < cycles; i++) { try { recurse(depthToTry); throw new Exception( "TEST_RFE: no stack overflow thrown" + ", need to try deeper recursion?"); - } catch (StackOverflowError error) { - // It's OK: stack overflow was expected. - } catch (OutOfMemoryError oome) { - // Also OK: out of memory is eligible here. - + } catch (StackOverflowError | OutOfMemoryError err) { + // It's OK } catch (Throwable throwable) { - if (throwable instanceof ThreadDeath) - throw (ThreadDeath) throwable; // It isn't OK! thrown = throwable; break; } + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack014.java b/test/hotspot/jtreg/runtime/stack/Stack014.java similarity index 71% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack014.java rename to test/hotspot/jtreg/runtime/stack/Stack014.java index 2f7f79331e2..972f386c1f1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack014.java +++ b/test/hotspot/jtreg/runtime/stack/Stack014.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -50,81 +50,67 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack014 + * @run main/othervm/timeout=900 Stack014 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack014 extends stack014i { +public class Stack014 extends Stack014i { final static int THREADS = 10; final static int CYCLES = 10; public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { - stack014i test = new stack014(); + Stack014i test = new Stack014(); // // Measure maximal recursion depth until stack overflow: // int maxDepth = 0; - for (int depth = 10; ; depth += 10) + for (int depth = 10; ; depth += 10) { try { test.recurse(depth); maxDepth = depth; - } catch (StackOverflowError soe) { - break; - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError err) { break; } - out.println("Max. depth: " + maxDepth); + } + System.out.println("Max. depth: " + maxDepth); // // Execute multiple threads repeatedly provoking stack overflows: // - stack014i threads[] = new stack014i[THREADS]; + Stack014i threads[] = new Stack014i[THREADS]; for (int i = 0; i < threads.length; i++) { - threads[i] = new stack014(); + threads[i] = new Stack014(); threads[i].depthToTry = 10 * maxDepth; threads[i].cycles = CYCLES; threads[i].start(); } - for (int i = 0; i < threads.length; i++) - if (threads[i].isAlive()) + for (int i = 0; i < threads.length; i++) { + if (threads[i].isAlive()) { try { threads[i].join(); } catch (InterruptedException exception) { - exception.printStackTrace(out); - return 2; + throw new RuntimeException(exception); } - + } + } // // Check if unexpected exceptions were thrown: // - int exitCode = 0; - for (int i = 0; i < threads.length; i++) + for (int i = 0; i < threads.length; i++) { if (threads[i].thrown != null) { - threads[i].thrown.printStackTrace(out); - exitCode = 2; + threads[i].thrown.printStackTrace(); + throw new RuntimeException("Exception in the thread " + threads[i], threads[i].thrown); } - - if (exitCode != 0) - out.println("# TEST FAILED"); - return exitCode; + } } synchronized void recurse(int depth) { - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } } -abstract class stack014i extends Thread { +abstract class Stack014i extends Thread { // // Pure virtual method: // @@ -138,24 +124,20 @@ public void run() { // // Provoke multiple stack overflows: // - for (int i = 0; i < cycles; i++) + for (int i = 0; i < cycles; i++) { try { recurse(depthToTry); throw new Exception( "TEST_RFE: no stack overflow thrown" + ", need to try deeper recursion?"); - } catch (StackOverflowError error) { - // It's OK: stack overflow was expected. - } catch (OutOfMemoryError oome) { - // Also OK: if there is no memory for stack expansion. - + } catch (StackOverflowError | OutOfMemoryError err) { + // It's OK } catch (Throwable throwable) { - if (throwable instanceof ThreadDeath) - throw (ThreadDeath) throwable; // It isn't OK! thrown = throwable; break; } + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack015.java b/test/hotspot/jtreg/runtime/stack/Stack015.java similarity index 70% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack015.java rename to test/hotspot/jtreg/runtime/stack/Stack015.java index 0a2d108af9d..3bceca2119b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack015.java +++ b/test/hotspot/jtreg/runtime/stack/Stack015.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -48,88 +48,74 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires vm.opt.DeoptimizeALot != true - * @run main/othervm/timeout=900 nsk.stress.stack.stack015 + * @run main/othervm/timeout=900 Stack015 */ -package nsk.stress.stack; - - -import java.io.PrintStream; - -public class stack015 extends stack015i { +public class Stack015 extends Stack015i { final static int THREADS = 10; final static int CYCLES = 10; final static int STEP = 10; final static int RESERVE = 10; public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { // - // The test will invoke the particular stack015.recurse() + // The test will invoke the particular Stack015.recurse() // method via abstract test.recurse() invocations. // - stack015i test = new stack015(); - stack015i.test = test; + Stack015i test = new Stack015(); + Stack015i.test = test; // // Measure maximal recursion depth until stack overflow: // int maxDepth = 0; - for (int depth = 0; ; depth += STEP) + for (int depth = 0; ; depth += STEP) { try { test.recurse(depth); maxDepth = depth; - } catch (StackOverflowError soe) { - break; - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError err) { break; } - out.println("Max. depth: " + maxDepth); + } + System.out.println("Max. depth: " + maxDepth); // // Execute multiple threads repeatedly provoking stack overflows: // - stack015i threads[] = new stack015i[THREADS]; + Stack015i threads[] = new Stack015i[THREADS]; for (int i = 0; i < threads.length; i++) { - threads[i] = new stack015(); + threads[i] = new Stack015(); threads[i].depthToTry = RESERVE * maxDepth; threads[i].start(); } - for (int i = 0; i < threads.length; i++) - if (threads[i].isAlive()) + for (int i = 0; i < threads.length; i++) { + if (threads[i].isAlive()) { try { threads[i].join(); } catch (InterruptedException exception) { - exception.printStackTrace(out); - return 2; + throw new RuntimeException(exception); } - + } + } // // Check if unexpected exceptions were thrown: // - int exitCode = 0; - for (int i = 0; i < threads.length; i++) + for (int i = 0; i < threads.length; i++) { if (threads[i].thrown != null) { - threads[i].thrown.printStackTrace(out); - exitCode = 2; + threads[i].thrown.printStackTrace(); + throw new RuntimeException("Exception in the thread " + threads[i], threads[i].thrown); } - - if (exitCode != 0) - out.println("# TEST FAILED"); - return exitCode; + } } synchronized void syncRecurse(int depth) { - if (depth > 0) + if (depth > 0) { syncRecurse(depth - 1); + } } } -abstract class stack015i extends Thread { +abstract class Stack015i extends Thread { // // Pure virtual method: // @@ -139,24 +125,25 @@ void recurse(int depth) { // // Stack overflow must occur here: // - syncRecurse(stack015.STEP); + syncRecurse(Stack015.STEP); // // If no stack overflow occured, try again with deeper stack: // - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } Throwable thrown = null; int depthToTry; - static stack015i test; + static Stack015i test; public void run() { // // Provoke multiple stack overflows: // - for (int i = 0; i < stack015.CYCLES; i++) + for (int i = 0; i < Stack015.CYCLES; i++) { try { // // All threads invoke the same synchronized method: @@ -167,17 +154,13 @@ public void run() { "TEST_RFE: no stack overflow thrown" + ", need to try deeper recursion?"); - } catch (StackOverflowError error) { - // It's OK: stack overflow was expected. - } catch (OutOfMemoryError oome) { - // Also OK: there may be no memory for stack expansion. - + } catch (StackOverflowError | OutOfMemoryError err) { + // It's OK } catch (Throwable throwable) { - if (throwable instanceof ThreadDeath) - throw (ThreadDeath) throwable; // It isn't OK! thrown = throwable; break; } + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack016.java b/test/hotspot/jtreg/runtime/stack/Stack016.java similarity index 67% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack016.java rename to test/hotspot/jtreg/runtime/stack/Stack016.java index dd33dd5e02c..dc2dbe7d105 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack016.java +++ b/test/hotspot/jtreg/runtime/stack/Stack016.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, 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 @@ -49,21 +49,12 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires (vm.opt.DeoptimizeALot != true & vm.compMode != "Xcomp") - * @library /vmTestbase - * @build nsk.share.Terminator - * @run main/othervm/timeout=900 -Xint -Xss448K nsk.stress.stack.stack016 -eager - * @run main/othervm/timeout=900 -Xcomp -Xss448K nsk.stress.stack.stack016 -eager - * @run main/othervm/timeout=900 -Xcomp -XX:-TieredCompilation -Xss448K nsk.stress.stack.stack016 -eager + * @run main/othervm/timeout=900 -Xint -Xss448K Stack016 + * @run main/othervm/timeout=900 -Xcomp -Xss448K Stack016 + * @run main/othervm/timeout=900 -Xcomp -XX:-TieredCompilation -Xss448K Stack016 */ -package nsk.stress.stack; - - -import nsk.share.Terminator; - -import java.io.PrintStream; - -public class stack016 extends Thread { +public class Stack016 extends Thread { private final static int THREADS = 10; private final static int CYCLES = 10; private final static int STEP = 10; @@ -71,37 +62,11 @@ public class stack016 extends Thread { private final static int PROBES = STEP * RESERVE; public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); + Stack016 test = new Stack016(); + test.doRun(); } - public static int run(String args[], PrintStream out) { - verbose = false; - boolean eager = false; - for (int i = 0; i < args.length; i++) - if (args[i].toLowerCase().equals("-verbose")) - verbose = true; - else if (args[i].toLowerCase().equals("-eager")) - eager = true; - if (!eager) - Terminator.appoint(Terminator.parseAppointment(args)); - stack016.out = out; - stack016 test = new stack016(); - return test.doRun(); - } - - private static boolean verbose; - private static PrintStream out; - - private void display(Object message) { - if (!verbose) - return; - synchronized (out) { - out.println(message.toString()); - } - } - - private int doRun() { + private void doRun() { // // Measure recursive depth before stack overflow: // @@ -114,14 +79,14 @@ private int doRun() { break; } } - out.println("Maximal recursion depth: " + maxDepth); + System.out.println("Maximal recursion depth: " + maxDepth); // // Run the tested threads: // - stack016 threads[] = new stack016[THREADS]; + Stack016 threads[] = new Stack016[THREADS]; for (int i = 0; i < threads.length; i++) { - threads[i] = new stack016(); + threads[i] = new Stack016(); threads[i].setName("Thread: " + (i + 1) + "/" + THREADS); threads[i].depthToTry = RESERVE * maxDepth; threads[i].start(); @@ -131,8 +96,7 @@ private int doRun() { try { threads[i].join(); } catch (InterruptedException exception) { - exception.printStackTrace(out); - return 2; + throw new RuntimeException(exception); } } } @@ -140,16 +104,12 @@ private int doRun() { // // Check if unexpected exceptions were thrown: // - int exitCode = 0; for (int i = 0; i < threads.length; i++) { if (threads[i].thrown != null) { - threads[i].thrown.printStackTrace(out); - exitCode = 2; + threads[i].thrown.printStackTrace(); + throw new RuntimeException("Exception in the thread " + threads[i], threads[i].thrown); } } - if (exitCode != 0) - out.println("# TEST FAILED"); - return exitCode; } private int stackTop = 0; @@ -161,11 +121,7 @@ private void trickyRecurse(int depth) { if (depth > 0) { try { trickyRecurse(depth - 1); - } catch (Error error) { - if (!(error instanceof StackOverflowError) && - !(error instanceof OutOfMemoryError)) - throw error; - + } catch (StackOverflowError | OutOfMemoryError error) { // // Provoke more stack overflow, // if current stack is deep enough: @@ -180,28 +136,24 @@ private void trickyRecurse(int depth) { } private static void recurse(int depth) { - if (depth > 0) + if (depth > 0) { recurse(depth - 1); + } } public void run() { String threadName = Thread.currentThread().getName(); for (int i = 1; i <= CYCLES; i++) { try { - display(threadName + ", iteration: " + i + "/" + CYCLES + + System.out.println(threadName + ", iteration: " + i + "/" + CYCLES + ", depthToTry: " + depthToTry); trickyRecurse(depthToTry); throw new Error( "TEST_BUG: trickyRecursion() must throw an error anyway!"); - } catch (StackOverflowError error) { - // It's OK: stack overflow was expected. - } catch (OutOfMemoryError oome) { - // Also OK, if there is no memory for stack expansion. - + } catch (StackOverflowError | OutOfMemoryError err) { + // It's OK } catch (Throwable throwable) { - if (throwable instanceof ThreadDeath) - throw (ThreadDeath) throwable; thrown = throwable; break; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack017.java b/test/hotspot/jtreg/runtime/stack/Stack017.java similarity index 61% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack017.java rename to test/hotspot/jtreg/runtime/stack/Stack017.java index fcb18ed216e..47db5886a00 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack017.java +++ b/test/hotspot/jtreg/runtime/stack/Stack017.java @@ -42,99 +42,59 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires (vm.opt.DeoptimizeALot != true & vm.compMode != "Xcomp" & vm.pageSize == 4096) - * @library /vmTestbase - * @build nsk.share.Terminator - * @run main/othervm/timeout=900 -Xss220K nsk.stress.stack.stack017 -eager + * @run main/othervm/timeout=900 -Xss220K Stack017 */ -package nsk.stress.stack; - - -import nsk.share.Terminator; - -import java.io.PrintStream; - -public class stack017 extends Thread { +public class Stack017 extends Thread { private final static int THREADS = 10; private final static int CYCLES = 10; private final static int PROBES = 100; public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { - verbose = false; - boolean eager = false; - for (int i = 0; i < args.length; i++) - if (args[i].toLowerCase().equals("-verbose")) - verbose = true; - else if (args[i].toLowerCase().equals("-eager")) - eager = true; - if (!eager) - Terminator.appoint(Terminator.parseAppointment(args)); - stack017.out = out; - stack017 test = new stack017(); - return test.doRun(); - } - - private static boolean verbose; - private static PrintStream out; - - private void display(Object message) { - if (!verbose) - return; - synchronized (out) { - out.println(message.toString()); - } + Stack017 test = new Stack017(); + test.doRun(); } private static int depthToTry; - private int doRun() { + private void doRun() { // // Measure recursive depth before stack overflow: // try { recurse(0); - } catch (StackOverflowError soe) { - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError err) { } - out.println("Maximal recursion depth: " + maxDepth); + System.out.println("Maximal recursion depth: " + maxDepth); depthToTry = maxDepth; // // Run the tested threads: // - stack017 threads[] = new stack017[THREADS]; + Stack017 threads[] = new Stack017[THREADS]; for (int i = 0; i < threads.length; i++) { - threads[i] = new stack017(); + threads[i] = new Stack017(); threads[i].setName("Thread: " + (i + 1) + "/" + THREADS); threads[i].start(); } - for (int i = 0; i < threads.length; i++) - if (threads[i].isAlive()) + for (int i = 0; i < threads.length; i++) { + if (threads[i].isAlive()) { try { threads[i].join(); } catch (InterruptedException exception) { - exception.printStackTrace(out); - return 2; + throw new RuntimeException(exception); } - + } + } // // Check if unexpected exceptions were thrown: // - int exitCode = 0; - for (int i = 0; i < threads.length; i++) + for (int i = 0; i < threads.length; i++) { if (threads[i].thrown != null) { - threads[i].thrown.printStackTrace(out); - exitCode = 2; + threads[i].thrown.printStackTrace(); + throw new RuntimeException("Exception in the thread " + threads[i], threads[i].thrown); } - - if (exitCode != 0) - out.println("# TEST FAILED"); - return exitCode; + } } private int maxDepth = 0; @@ -148,11 +108,7 @@ private void trickyRecurse(int depth) { try { maxDepth = depth; trickyRecurse(depth + 1); - } catch (Error error) { - if (!(error instanceof StackOverflowError) && - !(error instanceof OutOfMemoryError)) - throw error; - + } catch (StackOverflowError | OutOfMemoryError error) { // // Stack problem caught: provoke it again, // if current stack is enough deep: @@ -169,19 +125,14 @@ public void run() { String threadName = Thread.currentThread().getName(); for (int i = 1; i <= CYCLES; i++) try { - display(threadName + ", iteration: " + i + "/" + CYCLES); + System.out.println(threadName + ", iteration: " + i + "/" + CYCLES); trickyRecurse(0); throw new Exception( "TEST_BUG: stack overflow was expected!"); - } catch (StackOverflowError oome) { - // It's OK: stack overflow was expected. - } catch (OutOfMemoryError oome) { - // Also OK, if there is no memory for stack expansion. - + } catch (StackOverflowError | OutOfMemoryError err) { + // It's OK } catch (Throwable throwable) { - if (throwable instanceof ThreadDeath) - throw (ThreadDeath) throwable; // It isn't OK! thrown = throwable; break; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack018.java b/test/hotspot/jtreg/runtime/stack/Stack018.java similarity index 73% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack018.java rename to test/hotspot/jtreg/runtime/stack/Stack018.java index b60309cc98f..a54ffff6e6c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack018.java +++ b/test/hotspot/jtreg/runtime/stack/Stack018.java @@ -47,58 +47,24 @@ * 4366625 (P4/S4) multiple stack overflow causes HS crash * * @requires (vm.opt.DeoptimizeALot != true & vm.compMode != "Xcomp" & vm.pageSize == 4096) - * @library /vmTestbase - * @build nsk.share.Terminator - * @run main/othervm/timeout=900 -Xss220K nsk.stress.stack.stack018 -eager + * @run main/othervm/timeout=900 -Xss220K Stack018 */ -package nsk.stress.stack; - - -import nsk.share.Terminator; - -import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -public class stack018 extends Thread { +public class Stack018 extends Thread { private final static int THREADS = 10; private final static int CYCLES = 10; private final static int STEP = 100; private final static int RESERVE = 100; public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { - verbose = false; - boolean eager = false; - for (int i = 0; i < args.length; i++) - if (args[i].toLowerCase().equals("-verbose")) - verbose = true; - else if (args[i].toLowerCase().equals("-eager")) - eager = true; - if (!eager) - Terminator.appoint(Terminator.parseAppointment(args)); - stack018.out = out; - stack018 test = new stack018(); - return test.doRun(); - } - - private static boolean verbose; - private static PrintStream out; - - private void display(Object message) { - if (!verbose) - return; - synchronized (out) { - out.println(message.toString()); - } + Stack018 test = new Stack018(); + test.doRun(); } - private int doRun() { + private void doRun() { // // Measure maximal recursion depth until stack overflow: // @@ -112,10 +78,8 @@ private int doRun() { if ((target instanceof StackOverflowError) || (target instanceof OutOfMemoryError)) break; // OK. - target.printStackTrace(out); - if (target instanceof ThreadDeath) - throw (ThreadDeath) target; - return 2; + target.printStackTrace(); + throw new RuntimeException(exception); } } @@ -123,41 +87,38 @@ private int doRun() { // The depth STEP was enough to cause StackOverflowError or OutOfMemoryError. maxDepth = STEP; } - out.println("Maximal recursion depth: " + maxDepth); + System.out.println("Maximal recursion depth: " + maxDepth); // // Run the tested threads: // - stack018 threads[] = new stack018[THREADS]; + Stack018 threads[] = new Stack018[THREADS]; for (int i = 0; i < threads.length; i++) { - threads[i] = new stack018(); + threads[i] = new Stack018(); threads[i].setName("Thread: " + (i + 1) + "/" + THREADS); threads[i].depthToTry = RESERVE * maxDepth; threads[i].start(); } - for (int i = 0; i < threads.length; i++) - if (threads[i].isAlive()) + for (int i = 0; i < threads.length; i++) { + if (threads[i].isAlive()) { try { threads[i].join(); } catch (InterruptedException exception) { - exception.printStackTrace(out); - return 2; + throw new RuntimeException(exception); } - + } + } // // Check if unexpected exceptions were thrown: // int exitCode = 0; - for (int i = 0; i < threads.length; i++) + for (int i = 0; i < threads.length; i++) { if (threads[i].thrown != null) { - out.println("# " + threads[i].getName() + System.out.println("# " + threads[i].getName() + ": " + threads[i].thrown); - exitCode = 2; + throw new RuntimeException("Exception in the thread " + threads[i], threads[i].thrown); } - - if (exitCode != 0) - out.println("# TEST FAILED"); - return exitCode; + } } private int depthToTry = 0; @@ -167,7 +128,7 @@ public void run() { String threadName = Thread.currentThread().getName(); for (int i = 1; i <= CYCLES; i++) try { - display(threadName + ", iteration: " + i + "/" + CYCLES); + System.out.println(threadName + ", iteration: " + i + "/" + CYCLES); invokeRecurse(depthToTry); throw new Error("TEST_RFE: try deeper invocations!"); @@ -176,8 +137,6 @@ public void run() { if ((target instanceof StackOverflowError) || (target instanceof OutOfMemoryError)) continue; // OK. - if (target instanceof ThreadDeath) - throw (ThreadDeath) target; thrown = target; break; } @@ -205,7 +164,7 @@ private void invokeRecurse(int depth) throws Exception { // // Optimization trick: allocate once, use everywhere. // - method = stack018.class.getMethod("recurse"); + method = Stack018.class.getMethod("recurse"); params = new Object[]{}; } this.depth = depth; // actual parameter @@ -215,10 +174,11 @@ private void invokeRecurse(int depth) throws Exception { private int depth = 0; // actual parameter for recurse() public void recurse() throws Exception { - if (depth > 0) + if (depth > 0) { // // Self-invoke via reflection: // invokeRecurse(depth - 1); + } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack019.java b/test/hotspot/jtreg/runtime/stack/Stack019.java similarity index 65% rename from test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack019.java rename to test/hotspot/jtreg/runtime/stack/Stack019.java index c6c5efbb36f..7a20ae3e6a2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/stack019.java +++ b/test/hotspot/jtreg/runtime/stack/Stack019.java @@ -43,45 +43,22 @@ * * @requires (vm.opt.DeoptimizeALot != true & vm.compMode != "Xcomp" & vm.pageSize == 4096) * @requires os.family != "windows" - * @library /vmTestbase - * @build nsk.share.Terminator - * @run main/othervm/timeout=900 -Xss200K nsk.stress.stack.stack019 -eager + * @run main/othervm/timeout=900 -Xss200K Stack019 */ -package nsk.stress.stack; - - -import nsk.share.Terminator; - -import java.io.PrintStream; - -public class stack019 { +public class Stack019 { private final static int CYCLES = 50; private final static int PROBES = 50; public static void main(String[] args) { - int exitCode = run(args, System.out); - System.exit(exitCode + 95); - } - - public static int run(String args[], PrintStream out) { - boolean verbose = false, eager = false; - for (int i = 0; i < args.length; i++) - if (args[i].toLowerCase().equals("-verbose")) - verbose = true; - else if (args[i].toLowerCase().equals("-eager")) - eager = true; - if (!eager) - Terminator.appoint(Terminator.parseAppointment(args)); // // Measure recursive depth before stack overflow: // try { recurse(0); - } catch (StackOverflowError soe) { - } catch (OutOfMemoryError oome) { + } catch (StackOverflowError | OutOfMemoryError err) { } - out.println("Maximal recursion depth: " + maxDepth); + System.out.println("Maximal recursion depth: " + maxDepth); depthToTry = maxDepth; // @@ -89,23 +66,15 @@ else if (args[i].toLowerCase().equals("-eager")) // for (int i = 0; i < CYCLES; i++) { try { - out.println("Iteration: " + i + "/" + CYCLES); + System.out.println("Iteration: " + i + "/" + CYCLES); trickyRecurse(0); - out.println("# TEST_BUG: stack overflow was expected!"); - return 2; - - } catch (StackOverflowError error) { - } catch (OutOfMemoryError oome) { - // It's OK: stack overflow was expected. - + throw new RuntimeException("# TEST_BUG: stack overflow was expected!"); + } catch (StackOverflowError | OutOfMemoryError error) { + // It's OK } catch (Throwable throwable) { - if (throwable instanceof ThreadDeath) - throw (ThreadDeath) throwable; - throwable.printStackTrace(out); - return 2; + throw new RuntimeException(throwable); } } - return 0; } private static int maxDepth; @@ -120,17 +89,14 @@ private static void trickyRecurse(int depth) { try { maxDepth = depth; trickyRecurse(depth + 1); - } catch (Error error) { - if (!(error instanceof StackOverflowError) && - !(error instanceof OutOfMemoryError)) - throw error; - + } catch (StackOverflowError | OutOfMemoryError error){ // // Stack problem caught: provoke it again, // if current stack is enough deep: // - if (depth < depthToTry - PROBES) + if (depth < depthToTry - PROBES) { throw error; + } recurse(depth + 1); } } diff --git a/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java b/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java new file mode 100644 index 00000000000..891306a0c11 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java @@ -0,0 +1,338 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 8247972 + * + * @summary converted from VM Testbase nsk/jvmti/GetObjectMonitorUsage/objmonusage003 + * DESCRIPTION + * The test checks if the JVMTI function GetObjectMonitorUsage returns + * the expected values for the owner, entry_count, waiter_count + * fields of JVMTI_monitor_info. + * The testcases are the following: + * - unowned object without any threads waiting + * - unowned object with threads waiting to be notified + * - owned object without any threads waiting + * - owned object with N threads waiting to enter the monitor + * - owned object with N threads waiting to be notified + * - owned object with N threads waiting to enter, from 0 to N threads + * waiting to re-enter, from N to 0 threads waiting to be notified + * - all the above scenarios are executed with platform and virtual threads + * @requires vm.jvmti + * @run main/othervm/native + * -Djdk.virtualThreadScheduler.parallelism=10 + * -agentlib:ObjectMonitorUsage ObjectMonitorUsage + */ + +public class ObjectMonitorUsage { + final static int NUMBER_OF_ENTERING_THREADS = 4; + final static int NUMBER_OF_WAITING_THREADS = 4; + final static int NUMBER_OF_THREADS = NUMBER_OF_ENTERING_THREADS + NUMBER_OF_WAITING_THREADS; + + static Object lockCheck = new Object(); + + native static int getRes(); + native static int waitsToEnter(); + native static int waitsToBeNotified(); + native static int setTestedMonitor(Object monitor); + native static void check(Object obj, Thread owner, + int entryCount, int waiterCount, int notifyWaiterCount); + + static void log(String msg) { + System.out.println(msg); + } + + static String vtag(boolean isVirtual) { + return isVirtual ? "virtual" : "platform"; + } + + static void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + // ignore + } + } + + static Thread startTask(int idx, TestTask task, boolean isVirtual, String kind) { + Thread thread = isVirtual ? Thread.ofVirtual().name(kind + "VT" + idx).start(task) + : Thread.ofPlatform().name(kind + "PT" + idx).start(task); + task.setName(thread.getName()); + task.waitReady(); + return thread; + } + + static Thread[] startWaitingThreads(boolean isVirtual) { + Thread[] threads = new Thread[NUMBER_OF_WAITING_THREADS]; + for (int i = 0; i < NUMBER_OF_WAITING_THREADS; i++) { + // the WaitingTask has to wait to be notified in lockCheck.wait() + threads[i] = startTask(i, new WaitingTask(), isVirtual, "Waiting"); + } + while (waitsToBeNotified() < NUMBER_OF_WAITING_THREADS) { + sleep(1); + } + return threads; + } + + static Thread[] startEnteringThreads(boolean isVirtual) { + Thread[] threads = new Thread[NUMBER_OF_ENTERING_THREADS]; + for (int i = 0; i < NUMBER_OF_ENTERING_THREADS; i++) { + // the EnteringTask has to be blocked at the lockCheck enter + threads[i] = startTask(i, new EnteringTask(), isVirtual, "Entering"); + } + while (waitsToEnter() < NUMBER_OF_ENTERING_THREADS) { + sleep(1); + } + return threads; + } + + static void joinThreads(Thread[] threads) { + try { + for (Thread t : threads) { + t.join(); + } + } catch (InterruptedException e) { + throw new Error("Unexpected " + e); + } + } + + /* Scenario #0: + * - owning: 0 + * - entering: 0 + * - re-entering: 0 + * - to be notified: N + */ + static void test0(boolean isVirtual) { + String vtag = vtag(isVirtual); + log("\n### test0: started " + vtag); + + setTestedMonitor(lockCheck); + Thread[] wThreads = startWaitingThreads(isVirtual); + + // entry count: 0 + // count of threads waiting to enter: 0 + // count of threads waiting to re-enter: 0 + // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS + check(lockCheck, null, 0, // no owner thread + 0, // count of threads waiting to enter: 0 + NUMBER_OF_WAITING_THREADS); + + synchronized (lockCheck) { + lockCheck.notifyAll(); + } + joinThreads(wThreads); + setTestedMonitor(null); + log("### test0: finished " + vtag); + } + + /* Scenario #1: + * - owning: 1 + * - entering: N + * - re-entering: 0 + * - to be notified: 0 + */ + static void test1(boolean isVirtual) { + String vtag = vtag(isVirtual); + log("\n### test1: started " + vtag); + + setTestedMonitor(lockCheck); + Thread[] eThreads = null; + + synchronized (lockCheck) { + // entry count: 1 + // count of threads waiting to enter: 0 + // count of threads waiting to re-enter: 0 + // count of threads waiting to be notified: 0 + check(lockCheck, Thread.currentThread(), 1, 0, 0); + + eThreads = startEnteringThreads(isVirtual); + + // entry count: 1 + // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS + // count of threads waiting to re-enter: 0 + // count of threads waiting to be notified: 0 + check(lockCheck, Thread.currentThread(), 1, + NUMBER_OF_ENTERING_THREADS, + 0 /* count of threads waiting to be notified: 0 */); + + } + joinThreads(eThreads); + setTestedMonitor(null); + log("### test1: finished " + vtag); + } + + /* Scenario #2: + * - owning: 1 + * - entering: N + * - re-entering: 0 + * - to be notified: N + */ + static void test2(boolean isVirtual) throws Error { + String vtag = vtag(isVirtual); + log("\n### test2: started " + vtag); + + setTestedMonitor(lockCheck); + Thread[] wThreads = startWaitingThreads(isVirtual); + Thread[] eThreads = null; + + synchronized (lockCheck) { + eThreads = startEnteringThreads(isVirtual); + + // entry count: 1 + // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS + // count of threads waiting to re-enter: 0 + // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS + check(lockCheck, Thread.currentThread(), 1, + NUMBER_OF_ENTERING_THREADS, + NUMBER_OF_WAITING_THREADS); + + lockCheck.notifyAll(); + } + joinThreads(wThreads); + joinThreads(eThreads); + setTestedMonitor(null); + log("### test2: finished " + vtag); + } + + /* Scenario #3: + * Initially we have: + * - owning: 1 + * - entering: 0 + * - re-entering: 0 + * - to be notified: N + * + * The threads waiting to be notified are being notified one-by-one + * until all threads are blocked on re-entering the monitor. + * The numbers of entering/re-entering and waiting threads are checked + * for correctness after each notification. + */ + static void test3(boolean isVirtual) throws Error { + String vtag = vtag(isVirtual); + log("\n### test3: started " + vtag); + + setTestedMonitor(lockCheck); + Thread[] wThreads = startWaitingThreads(isVirtual); + Thread[] eThreads = null; + + synchronized (lockCheck) { + // entry count: 1 + // count of threads waiting to enter: 0 + // count of threads waiting to re-enter: 0 + // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS + check(lockCheck, Thread.currentThread(), 1, + 0, // number of threads waiting to enter or re-enter + NUMBER_OF_WAITING_THREADS); + + eThreads = startEnteringThreads(isVirtual); + + // entry count: 1 + // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS + // count of threads waiting to re-enter: 0 + // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS + check(lockCheck, Thread.currentThread(), 1, + NUMBER_OF_ENTERING_THREADS, + NUMBER_OF_WAITING_THREADS); + + for (int i = 0; i < NUMBER_OF_WAITING_THREADS; i++) { + lockCheck.notify(); // notify waiting threads one by one + // now the notified WaitingTask has to be blocked on the lockCheck re-enter + + // entry count: 1 + // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS + // count of threads waiting to re-enter: i + 1 + // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS - i - 1 + check(lockCheck, Thread.currentThread(), 1, + NUMBER_OF_ENTERING_THREADS + i + 1, + NUMBER_OF_WAITING_THREADS - i - 1); + } + } + joinThreads(wThreads); + joinThreads(eThreads); + setTestedMonitor(null); + log("### test3: finished " + vtag); + } + + static void test(boolean isVirtual) { + test0(isVirtual); + test1(isVirtual); + test2(isVirtual); + test3(isVirtual); + } + + public static void main(String args[]) { + log("\n### main: started\n"); + check(lockCheck, null, 0, 0, 0); + + test(false); // test platform threads + test(true); // test virtual threads + + check(lockCheck, null, 0, 0, 0); + if (getRes() > 0) { + throw new RuntimeException("Failed status returned from the agent"); + } + log("\n### main: finished\n"); + } + + static abstract class TestTask implements Runnable { + volatile boolean ready = false; + String name; + + public abstract void run(); + + String getName() { return name; } + void setName(String name) { this.name = name; } + + void waitReady() { + try { + while (!ready) { + Thread.sleep(10); + } + } catch (InterruptedException e) { + throw new Error("Unexpected " + e); + } + } + } + + static class EnteringTask extends TestTask { + public void run() { + ready = true; + synchronized (lockCheck) { + } + } + } + + static class WaitingTask extends TestTask { + public void run() { + synchronized (lockCheck) { + try { + ready = true; + // no protection against spurious wakeups here + lockCheck.wait(); + } catch (InterruptedException e) { + throw new Error("Unexpected " + e); + } + } + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/libObjectMonitorUsage.cpp b/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/libObjectMonitorUsage.cpp new file mode 100644 index 00000000000..015f64452e8 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/libObjectMonitorUsage.cpp @@ -0,0 +1,261 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include "jvmti.h" +#include "jvmti_common.hpp" + +extern "C" { + +#define PASSED 0 +#define STATUS_FAILED 2 + +static jvmtiEnv *jvmti = nullptr; +static jrawMonitorID event_lock = nullptr; +static jint result = PASSED; +static int check_idx = 0; +static int waits_to_enter = 0; +static int waits_to_be_notified = 0; +static jobject tested_monitor = nullptr; + +static bool is_tested_monitor(JNIEnv *jni, jobject monitor) { + if (tested_monitor == nullptr) { + return false; // tested_monitor was not set yet + } + return jni->IsSameObject(monitor, tested_monitor) == JNI_TRUE; +} + +static void log_event(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, + const char* title, int counter) { + char* tname = get_thread_name(jvmti, jni, thread); + LOG(">>> %s event: %s counter: %d\n", title, tname, counter); + deallocate(jvmti, jni, (void*)tname); +} + +JNIEXPORT void JNICALL +MonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jobject monitor) { + RawMonitorLocker rml(jvmti, jni, event_lock); + if (is_tested_monitor(jni, monitor)) { + waits_to_enter++; + log_event(jvmti, jni, thread, "MonitorContendedEnter", waits_to_enter); + } +} + +JNIEXPORT void JNICALL +MonitorContendedEntered(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jobject monitor) { + RawMonitorLocker rml(jvmti, jni, event_lock); + if (is_tested_monitor(jni, monitor)) { + waits_to_enter--; + log_event(jvmti, jni, thread, "MonitorContendedEntered", waits_to_enter); + } +} + +JNIEXPORT void JNICALL +MonitorWait(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jobject monitor, jlong timeout) { + RawMonitorLocker rml(jvmti, jni, event_lock); + if (is_tested_monitor(jni, monitor)) { + waits_to_be_notified++; + log_event(jvmti, jni, thread, "MonitorWait", waits_to_be_notified); + } +} + +JNIEXPORT void JNICALL +MonitorWaited(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jobject monitor, jboolean timed_out) { + RawMonitorLocker rml(jvmti, jni, event_lock); + if (is_tested_monitor(jni, monitor)) { + waits_to_be_notified--; + log_event(jvmti, jni, thread, "MonitorWaited", waits_to_be_notified); + } +} + +jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { + jint res; + jvmtiError err; + jvmtiCapabilities caps; + jvmtiEventCallbacks callbacks; + + res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); + if (res != JNI_OK || jvmti == nullptr) { + LOG("Wrong result of a valid call to GetEnv !\n"); + return JNI_ERR; + } + err = jvmti->GetPotentialCapabilities(&caps); + check_jvmti_error(err, "Agent_Initialize: error in JVMTI GetPotentialCapabilities"); + + err = jvmti->AddCapabilities(&caps); + check_jvmti_error(err, "Agent_Initialize: error in JVMTI AddCapabilities"); + + err = jvmti->GetCapabilities(&caps); + check_jvmti_error(err, "Agent_Initialize: error in JVMTI GetCapabilities"); + + if (!caps.can_get_monitor_info) { + LOG("Warning: GetObjectMonitorUsage is not implemented\n"); + } + if (!caps.can_generate_monitor_events) { + LOG("Warning: Monitor events are not implemented\n"); + return JNI_ERR; + } + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.MonitorContendedEnter = &MonitorContendedEnter; + callbacks.MonitorContendedEntered = &MonitorContendedEntered; + callbacks.MonitorWait = &MonitorWait; + callbacks.MonitorWaited = &MonitorWaited; + + err = jvmti->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks)); + check_jvmti_error(err, "Agent_Initialize: error in JVMTI SetEventCallbacks"); + + event_lock = create_raw_monitor(jvmti, "Events Monitor"); + + return JNI_OK; +} + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} + +JNIEXPORT jint JNICALL +Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} + +static void print_monitor_info(JNIEnv *jni, jvmtiMonitorUsage &inf) { + jvmtiError err; + jvmtiThreadInfo tinf; + + LOG(">>> [%d]\n", check_idx); + if (inf.owner == nullptr) { + LOG(">>> owner: none (0x0)\n"); + } else { + err = jvmti->GetThreadInfo(inf.owner, &tinf); + check_jvmti_status(jni, err, "error in JVMTI GetThreadInfo"); + LOG(">>> owner: %s (0x%p)\n", + tinf.name, inf.owner); + deallocate(jvmti, jni, tinf.name); + } + LOG(">>> entry_count: %d\n", inf.entry_count); + LOG(">>> waiter_count: %d\n", inf.waiter_count); + LOG(">>> notify_waiter_count: %d\n", inf.notify_waiter_count); + + if (inf.waiter_count > 0) { + LOG(">>> waiters:\n"); + for (int j = 0; j < inf.waiter_count; j++) { + err = jvmti->GetThreadInfo(inf.waiters[j], &tinf); + check_jvmti_status(jni, err, "error in JVMTI GetThreadInfo"); + LOG(">>> %2d: %s (0x%p)\n", + j, tinf.name, inf.waiters[j]); + deallocate(jvmti, jni, tinf.name); + } + } + if (inf.notify_waiter_count > 0) { + LOG(">>> notify_waiters:\n"); + for (int j = 0; j < inf.notify_waiter_count; j++) { + err = jvmti->GetThreadInfo(inf.notify_waiters[j], &tinf); + check_jvmti_status(jni, err, "error in JVMTI GetThreadInfo"); + LOG(">>> %2d: %s (0x%p)\n", + j, tinf.name, inf.notify_waiters[j]); + deallocate(jvmti, jni, tinf.name); + } + } +} + +JNIEXPORT void JNICALL +Java_ObjectMonitorUsage_check(JNIEnv *jni, jclass cls, jobject obj, jthread owner, + jint entryCount, jint waiterCount, jint notifyWaiterCount) { + jvmtiError err; + jvmtiMonitorUsage inf; + + check_idx++; + + err = jvmti->GetObjectMonitorUsage(obj, &inf); + check_jvmti_status(jni, err, "error in JVMTI GetObjectMonitorUsage"); + + print_monitor_info(jni, inf); + + if (!jni->IsSameObject(owner, inf.owner)) { + LOG("FAILED: (%d) unexpected owner: 0x%p\n", check_idx, inf.owner); + result = STATUS_FAILED; + } + if (inf.entry_count != entryCount) { + LOG("FAILED: (%d) entry_count expected: %d, actually: %d\n", + check_idx, entryCount, inf.entry_count); + result = STATUS_FAILED; + } + if (inf.waiter_count != waiterCount) { + LOG("FAILED: (%d) waiter_count expected: %d, actually: %d\n", + check_idx, waiterCount, inf.waiter_count); + result = STATUS_FAILED; + } + if (inf.notify_waiter_count != notifyWaiterCount) { + LOG("FAILED: (%d) notify_waiter_count expected: %d, actually: %d\n", + check_idx, notifyWaiterCount, inf.notify_waiter_count); + result = STATUS_FAILED; + } +} + +JNIEXPORT void JNICALL +Java_ObjectMonitorUsage_setTestedMonitor(JNIEnv *jni, jclass cls, jobject monitor) { + jvmtiError err; + jvmtiEventMode event_mode = (monitor != nullptr) ? JVMTI_ENABLE : JVMTI_DISABLE; + + RawMonitorLocker rml(jvmti, jni, event_lock); + + if (tested_monitor != nullptr) { + jni->DeleteGlobalRef(tested_monitor); + } + tested_monitor = (monitor != nullptr) ? jni->NewGlobalRef(monitor) : nullptr; + waits_to_enter = 0; + waits_to_be_notified = 0; + + err = jvmti->SetEventNotificationMode(event_mode, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, nullptr); + check_jvmti_status(jni, err, "setTestedMonitor: error in JVMTI SetEventNotificationMode #1"); + + err = jvmti->SetEventNotificationMode(event_mode, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, nullptr); + check_jvmti_status(jni, err, "setTestedMonitor: error in JVMTI SetEventNotificationMode #2"); + + err = jvmti->SetEventNotificationMode(event_mode, JVMTI_EVENT_MONITOR_WAIT, nullptr); + check_jvmti_status(jni, err, "setTestedMonitor: error in JVMTI SetEventNotificationMode #3"); + + err = jvmti->SetEventNotificationMode(event_mode, JVMTI_EVENT_MONITOR_WAITED, nullptr); + check_jvmti_status(jni, err, "setTestedMonitor: error in JVMTI SetEventNotificationMode #4"); +} + +JNIEXPORT jint JNICALL +Java_ObjectMonitorUsage_waitsToEnter(JNIEnv *jni, jclass cls) { + RawMonitorLocker rml(jvmti, jni, event_lock); + return waits_to_enter; +} + +JNIEXPORT jint JNICALL +Java_ObjectMonitorUsage_waitsToBeNotified(JNIEnv *jni, jclass cls) { + RawMonitorLocker rml(jvmti, jni, event_lock); + return waits_to_be_notified; +} + +JNIEXPORT jint JNICALL +Java_ObjectMonitorUsage_getRes(JNIEnv *jni, jclass cls) { + return result; +} + +} // extern "C" diff --git a/test/hotspot/jtreg/testlibrary/jittester/Makefile b/test/hotspot/jtreg/testlibrary/jittester/Makefile index 32548e6cdba..16cb921304d 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/Makefile +++ b/test/hotspot/jtreg/testlibrary/jittester/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2021, 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 @@ -80,6 +80,7 @@ TESTLIBRARY_SRC_FILES = $(TESTLIBRARY_SRC_DIR)/Asserts.java \ $(TESTLIBRARY_SRC_DIR)/process/OutputBuffer.java \ $(TESTLIBRARY_SRC_DIR)/process/ProcessTools.java \ $(TESTLIBRARY_SRC_DIR)/process/StreamPumper.java \ + $(TESTLIBRARY_SRC_DIR)/util/FileUtils.java \ $(TESTLIBRARY_SRC_DIR)/util/Pair.java .PHONY: cleantmp diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/JavaCodeGenerator.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/JavaCodeGenerator.java index 02fb37d8072..7ca940fe531 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/JavaCodeGenerator.java +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/JavaCodeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 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 @@ -64,13 +64,13 @@ private void generateSources(IRNode mainClass, IRNode privateClasses) { } private void compileJavaFile(String mainClassName) { - String classPath = tmpDir.toString(); + String classPath = tmpDir.path.toString(); ProcessBuilder pb = new ProcessBuilder(JAVAC, "-d", classPath, "-cp", classPath, generatorDir.resolve(mainClassName + ".java").toString()); try { - int r = runProcess(pb, tmpDir.resolve(mainClassName + ".javac").toString()); + int r = runProcess(pb, tmpDir.path.resolve(mainClassName + ".javac").toString()); if (r != 0) { throw new Error("Can't compile sources, exit code = " + r); } diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/TempDir.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/TempDir.java new file mode 100644 index 00000000000..b166315a332 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/TempDir.java @@ -0,0 +1,62 @@ +/* + * 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. + * + * 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.test.lib.jittester; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import jdk.test.lib.util.FileUtils; + +/** + * A temporary directory wrapper. + * Makes sure that the directory gets deleted after usage. + */ +public class TempDir { + public final Path path; + + /** + * Creates a temporary directory with a given suffix. + * The directory is deep deleted on VM shutdown using a ShutdownHook. + */ + public TempDir(String suffix) { + try { + path = Files.createTempDirectory(suffix).toAbsolutePath(); + Runtime.getRuntime().addShutdownHook(new Thread(this::delete)); + } catch (IOException e) { + throw new Error("Can't create a tmp dir for " + suffix, e); + } + + System.out.println("DBG: Temp folder created: '" + path + "'"); + } + + private void delete() { + try { + FileUtils.deleteFileTreeWithRetry(path); + System.out.println("DBG: Temp folder deleted: '" + path + "'"); + } catch (IOException exc) { + throw new Error("Could not deep delete '" + path + "'", exc); + } + } +} diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/TestsGenerator.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/TestsGenerator.java index d8559398481..5d8ac107d6a 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/TestsGenerator.java +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/TestsGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, 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 @@ -42,7 +42,7 @@ public abstract class TestsGenerator implements BiConsumer { protected static final String JAVAC = Paths.get(JAVA_BIN, "javac").toString(); protected static final String JAVA = Paths.get(JAVA_BIN, "java").toString(); protected final Path generatorDir; - protected final Path tmpDir; + protected final TempDir tmpDir; protected final Function preRunActions; protected final String jtDriverOptions; private static final String DISABLE_WARNINGS = "-XX:-PrintWarnings"; @@ -54,17 +54,13 @@ protected TestsGenerator(String suffix) { protected TestsGenerator(String suffix, Function preRunActions, String jtDriverOptions) { generatorDir = getRoot().resolve(suffix).toAbsolutePath(); - try { - tmpDir = Files.createTempDirectory(suffix).toAbsolutePath(); - } catch (IOException e) { - throw new Error("Can't get a tmp dir for " + suffix, e); - } + tmpDir = new TempDir(suffix); this.preRunActions = preRunActions; this.jtDriverOptions = jtDriverOptions; } protected void generateGoldenOut(String mainClassName) { - String classPath = tmpDir.toString() + File.pathSeparator + String classPath = tmpDir.path.toString() + File.pathSeparator + generatorDir.toString(); ProcessBuilder pb = new ProcessBuilder(JAVA, "-Xint", DISABLE_WARNINGS, "-Xverify", "-cp", classPath, mainClassName); @@ -97,7 +93,7 @@ protected static int runProcess(ProcessBuilder pb, String name) protected void compilePrinter() { Path root = getRoot(); ProcessBuilder pbPrinter = new ProcessBuilder(JAVAC, - "-d", tmpDir.toString(), + "-d", tmpDir.path.toString(), root.resolve("jdk") .resolve("test") .resolve("lib") diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads004.java index 769a7de625b..311e20d2f10 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, 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 @@ -154,6 +154,7 @@ private static void execTest() { fieldName = "lockingObject"; display("CHECK2: checking waitingThreads method for ObjectReference of waitingthreads004a." + fieldName); objRef = (ObjectReference) debuggeeClass.getValue(debuggeeClass.fieldByName(fieldName)); + try { List waitingThreads = objRef.waitingThreads(); if (waitingThreads.size() != waitingthreads004a.threadCount) { @@ -161,6 +162,12 @@ private static void execTest() { complain("waitingThreads method returned list with unexpected size for " + fieldName + "\n\t expected value : " + waitingthreads004a.threadCount + "; got one : " + waitingThreads.size()); } else { + debuggee.VM().resume(); + debuggee.sendSignal(SIGNAL_GO); + debuggee.receiveExpectedSignal(SIGNAL_GO); + // tested thread must be blocked on re-entering monitor in lockingObject.wait() + debuggee.VM().suspend(); + // check waitingThreads list Iterator itr = waitingThreads.iterator(); while (itr.hasNext()) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads004/TestDescription.java index 647e0ab3cfd..7e332961ba9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads004/TestDescription.java @@ -32,11 +32,12 @@ * The test checks an following assertion of * com.sun.jdi.ObjectReference.waitingThreads method spec: * Returns a List containing a ThreadReference for each thread currently - * waiting for this object's monitor. + * waiting to re-enter this object's monitor. * There are two test cases: * - An object with no waiting threads. * A list with zero size is expected to be returned by the method. - * - An object with threads waiting in Object.wait(long) method. + * - An object with threads waiting to re-enter the monitor after being + * notified during execution of the Object.wait(long) method. * The debugger checks with expected results: * - a size of returned list of ThreadReferences, * - the names of thread references, diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads004a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads004a.java index 2b2e9a0ffda..efd83eee2f0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads004a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads004a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, 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 @@ -96,13 +96,17 @@ public static void main (String argv[]) { } pipe.println(waitingthreads004.SIGNAL_GO); - receiveSignal(waitingthreads004.SIGNAL_QUIT); + receiveSignal(waitingthreads004.SIGNAL_GO); } display("exited: synchronized (waitnotifyObj) {}"); synchronized (lockingObject) { display("entered and notifyAll: synchronized (lockingObject) {}"); lockingObject.notifyAll(); + + // tested thread must be blocked on re-entering monitor in lockingObject.wait() + pipe.println(waitingthreads004.SIGNAL_GO); + receiveSignal(waitingthreads004.SIGNAL_QUIT); } display("exited: synchronized (lockingObject) {}"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/CurrentContendedMonitor/curcontmonitor001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/CurrentContendedMonitor/curcontmonitor001/TestDescription.java index c1310a9c3fb..298363ade01 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/CurrentContendedMonitor/curcontmonitor001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/CurrentContendedMonitor/curcontmonitor001/TestDescription.java @@ -46,7 +46,8 @@ * Next, debugger obtains from debuggee classID for tested thread class * and threadID as the value of a class static field. Also debugger * suspends the thread before sending the tested command. The tested - * thread is waiting for the object at this moment. + * thread is waiting to re-enter the object monitor after being + * notified during execution of the Object.wait(long) method. * Then, debugger creates command packet for ThreadReference.CurrenContendedMonitor * command with the found threadID as an argument, writes packet to * the transport channel, and waits for a reply packet. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/CurrentContendedMonitor/curcontmonitor001a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/CurrentContendedMonitor/curcontmonitor001a.java index eb4ebeae8e2..1f20c1c7041 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/CurrentContendedMonitor/curcontmonitor001a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/CurrentContendedMonitor/curcontmonitor001a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, 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 @@ -61,6 +61,7 @@ public int runIt(String args[], PrintStream out) { argumentHandler = new ArgumentHandler(args); log = new Log(out, argumentHandler); long timeout = argumentHandler.getWaitTime() * 60 * 1000; // milliseconds + String signal = null; // make communication pipe to debugger log.display("Creating pipe"); @@ -84,21 +85,19 @@ public int runIt(String args[], PrintStream out) { // ensure that tested thread is waiting for monitor object synchronized (TestedClass.thread.monitor) { + TestedClass.thread.monitor.notifyAll(); + // send debugger signal READY log.display("Sending signal to debugger: " + curcontmonitor001.READY); pipe.println(curcontmonitor001.READY); + + // wait for signal QUIT from debugeer + log.display("Waiting for signal from debugger: " + curcontmonitor001.QUIT); + signal = pipe.readln(); + log.display("Received signal from debugger: " + signal); } } - // wait for signal QUIT from debugeer - log.display("Waiting for signal from debugger: " + curcontmonitor001.QUIT); - String signal = pipe.readln(); - log.display("Received signal from debugger: " + signal); - - // interrupt waiting thread - log.display("Interrupting tested thread being waited"); - TestedClass.thread.interrupt(); - // check received signal if (signal == null || !signal.equals(curcontmonitor001.QUIT)) { log.complain("Unexpected communication signal from debugee: " + signal diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java index 2dff7d1b74a..1ae3bf79e1c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, 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 @@ -28,6 +28,7 @@ public class objmonusage001 { final static int JCK_STATUS_BASE = 95; final static int NUMBER_OF_THREADS = 32; + final static boolean ADD_DELAYS_FOR_RACES = false; static { try { @@ -41,7 +42,9 @@ public class objmonusage001 { } native static int getResult(); - native static void check(int i, Object o, Thread owner, int ec, int wc); + native static void check(int index, Object syncObject, Thread owner, int entryCount, + Thread waiterThread, int waiterCount, + Thread notifyWaiterThread, int notifyWaiterCount); public static void main(String argv[]) { argv = nsk.share.jvmti.JVMTITest.commonInit(argv); @@ -50,12 +53,13 @@ public static void main(String argv[]) { } public static int run(String argv[], PrintStream out) { + Thread mainThread = Thread.currentThread(); Object syncObject[] = new Object[NUMBER_OF_THREADS]; objmonusage001a runn[] = new objmonusage001a[NUMBER_OF_THREADS]; for (int i = 0; i < NUMBER_OF_THREADS; i++) { syncObject[i] = new Object(); - runn[i] = new objmonusage001a(i, syncObject[i]); + runn[i] = new objmonusage001a(mainThread, i, syncObject[i]); } for (int i = 0; i < NUMBER_OF_THREADS; i++) { @@ -67,8 +71,53 @@ public static int run(String argv[], PrintStream out) { out.println(e); return 2; } + + // Check #2: + // - owner == main: + // main thread owns the monitor and worker thread + // is in wait() and is not notified + // - entry_count == 1: + // main thread reentered 1 time + // - waiter_count == 0: + // main thread has already reentered the monitor and worker thread + // is in wait() and is not notified so it is not waiting to reenter + // the monitor + // - waiter_thread == null: + // no thread is waiting to reenter the monitor + // - notify_waiter_count == 1: + // worker thread is in wait() and is not notified + // - notify_waiter_thread == runn[i]: + // worker thread is in wait() and is not notified + // + // This is a stable verification point because the worker thread is in wait() + // and is not notified and the main thread is doing the verification. + // + check(NUMBER_OF_THREADS + i, syncObject[i], mainThread, 1, + null, 0, runn[i], 1); } - check(NUMBER_OF_THREADS + i, syncObject[i], null, 0, 1); + + // Check #3: + // - owner == null: + // main thread does not own the monitor and worker thread is in + // wait() and is not notified so there is no owner + // - entry_count == 0: + // no owner so entry_count is 0 + // - waiter_count == 0: + // main thread is not trying to enter the monitor and worker thread + // is in wait() and is not notified so it is not waiting to reenter + // the monitor + // - waiter_thread == null: + // no thread is waiting to reenter the monitor + // - notify_waiter_count == 1: + // worker thread is in wait() and is not notified + // - notify_waiter_thread == runn[i]: + // worker thread is in wait() and is not notified + // + // This is a stable verification point because the worker thread is in wait() + // and is not notified and the main thread is doing the verification. + // + check((NUMBER_OF_THREADS * 2) + i, syncObject[i], null, 0, + null, 0, runn[i], 1); } for (int i = 0; i < NUMBER_OF_THREADS; i++) { @@ -87,20 +136,46 @@ public static int run(String argv[], PrintStream out) { } class objmonusage001a extends Thread { + Thread mainThread; Object syncObject; - int ind; + int index; - public objmonusage001a(int i, Object s) { - ind = i; + public objmonusage001a(Thread mt, int i, Object s) { + mainThread = mt; + index = i; syncObject = s; } public void run() { synchronized (syncObject) { - objmonusage001.check(ind, syncObject, this, 1, 1); + // Check #1: + // - owner == this_thread: + // this worker thread is owner + // - entry_count == 1: + // worker thread entered 1 time + // - waiter_count == 0: + // main thread is in wait() and is not notified so it is not + // waiting to reenter the monitor + // - waiter_thread == null: + // no thread is waiting to reenter the monitor + // - notify_waiter_count == 1: + // main thread is in wait() and is not notified + // - notify_waiter_thread == mainThread: + // main thread is in wait() and is not notified + // + // This is a stable verification point because the main thread is in wait() + // and is not notified and this worker thread is doing the verification. + // + objmonusage001.check(index, syncObject, this, 1, + null, 0, mainThread, 1); syncObject.notify(); + try { syncObject.wait(); + + if (objmonusage001.ADD_DELAYS_FOR_RACES) { + Thread.sleep(1000); + } } catch (InterruptedException e) { throw new Error("Unexpected " + e); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001/TestDescription.java index 6baae36c077..0896b9c84af 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, 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 @@ -29,7 +29,14 @@ * VM Testbase keywords: [quick, jpda, jvmti, noras] * VM Testbase readme: * DESCRIPTION - * The test exercises JVMTI function GetObjectMonitorUsage. + * The test exercises JVMTI function GetObjectMonitorUsage. The main + * thread uses a monitor to do coordinated launches of work threads. + * Each worker thread verifies expected GetObjectMonitorUsage values + * when it gets going and the main thread also verifies expected + * GetObjectMonitorUsage values once the worker thread returns + * control flow to the main thread. The test scenario is repeated + * for a fixed number of threads. + * * COMMENTS * Fixed according to 4669812 bug. * Ported from JVMDI test nsk/jvmdi/GetMonitorInfo/getmoninfo001. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001/objmonusage001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001/objmonusage001.cpp index bb9111d897f..b4540700c68 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001/objmonusage001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001/objmonusage001.cpp @@ -94,13 +94,15 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { JNIEXPORT void JNICALL Java_nsk_jvmti_GetObjectMonitorUsage_objmonusage001_check(JNIEnv *env, jclass cls, jint i, jobject obj, - jthread owner, jint entryCount, jint waiterCount) { + jthread owner, jint entryCount, + jthread waiterThread, jint waiterCount, + jthread notifyWaiterThread, jint notifyWaiterCount) { jvmtiError err; jvmtiMonitorUsage inf; jvmtiThreadInfo tinf; int j; - if (result == STATUS_FAILED) { + if (result == STATUS_FAILED && printdump != JNI_TRUE) { return; } @@ -152,16 +154,38 @@ Java_nsk_jvmti_GetObjectMonitorUsage_objmonusage001_check(JNIEnv *env, } if (inf.entry_count != entryCount) { - printf("(%d) entry_count expected: %d, actually: %d\n", + printf("FAILED: (%d) entry_count expected: %d, actually: %d\n", i, entryCount, inf.entry_count); result = STATUS_FAILED; } if (inf.waiter_count != waiterCount) { - printf("(%d) waiter_count expected: %d, actually: %d\n", + printf("FAILED: (%d) waiter_count expected: %d, actually: %d\n", i, waiterCount, inf.waiter_count); result = STATUS_FAILED; } + + if (inf.waiters != nullptr && + !env->IsSameObject(waiterThread, inf.waiters[0])) { + jvmti->GetThreadInfo(inf.waiters[0], &tinf); + printf("FAILED: (%d) unexpected waiterThread: %s (0x%p)\n", i, + tinf.name, inf.waiters[0]); + result = STATUS_FAILED; + } + + if (inf.notify_waiter_count != notifyWaiterCount) { + printf("FAILED: (%d) notify_waiter_count expected: %d, actually: %d\n", + i, notifyWaiterCount, inf.notify_waiter_count); + result = STATUS_FAILED; + } + + if (inf.notify_waiters != nullptr && + !env->IsSameObject(notifyWaiterThread, inf.notify_waiters[0])) { + jvmti->GetThreadInfo(inf.notify_waiters[0], &tinf); + printf("FAILED: (%d) unexpected waiterThread: %s (0x%p)\n", i, + tinf.name, inf.notify_waiters[0]); + result = STATUS_FAILED; + } } JNIEXPORT jint JNICALL diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003.java deleted file mode 100644 index 9b1fff4b212..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package nsk.jvmti.GetObjectMonitorUsage; - -import java.io.PrintStream; - -public class objmonusage003 { - - final static int JCK_STATUS_BASE = 95; - final static int NUMBER_OF_THREADS = 16; - final static int WAIT_TIME = 100; - volatile static boolean waiterInLockCheck = false; - - static { - try { - System.loadLibrary("objmonusage003"); - } catch (UnsatisfiedLinkError ule) { - System.err.println("Could not load objmonusage003 library"); - System.err.println("java.library.path:" - + System.getProperty("java.library.path")); - throw ule; - } - } - - static Object lockStart = new Object(); - static Object lockCheck = new Object(); - - native static int getRes(); - native static void check(Object obj, Thread owner, - int entryCount, int waiterCount); - - public static void main(String args[]) { - args = nsk.share.jvmti.JVMTITest.commonInit(args); - - // produce JCK-like exit status. - System.exit(run(args, System.out) + JCK_STATUS_BASE); - } - - public static int run(String args[], PrintStream out) { - check(lockCheck, null, 0, 0); - - synchronized (lockCheck) { - check(lockCheck, Thread.currentThread(), 1, 0); - } - - WaiterThread thr[] = new WaiterThread[NUMBER_OF_THREADS]; - for (int i = 0; i < NUMBER_OF_THREADS; i++) { - thr[i] = new WaiterThread(); - synchronized (lockStart) { - thr[i].start(); - try { - lockStart.wait(); - } catch (InterruptedException e) { - throw new Error("Unexpected " + e); - } - } - synchronized (lockCheck) { - while (!waiterInLockCheck) { - try { - lockCheck.wait(WAIT_TIME); - } catch (InterruptedException e) { - throw new Error("Unexpected " + e); - } - } - waiterInLockCheck = false; - } - check(lockCheck, null, 0, i + 1); - } - - synchronized (lockCheck) { - lockCheck.notifyAll(); - } - - for (int i = 0; i < NUMBER_OF_THREADS; i++) { - try { - thr[i].join(); - } catch (InterruptedException e) { - throw new Error("Unexpected " + e); - } - } - - check(lockCheck, null, 0, 0); - return getRes(); - } - - static class WaiterThread extends Thread { - public synchronized void run() { - synchronized (lockStart) { - lockStart.notify(); - } - synchronized (lockCheck) { - try { - waiterInLockCheck = true; - lockCheck.wait(); - } catch (InterruptedException e) { - throw new Error("Unexpected " + e); - } - } - } - } -} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003/objmonusage003.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003/objmonusage003.cpp deleted file mode 100644 index 6e0a7d3b155..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003/objmonusage003.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include -#include -#include "jvmti.h" -#include "agent_common.hpp" -#include "JVMTITools.hpp" - -extern "C" { - - -#define PASSED 0 -#define STATUS_FAILED 2 - -static jvmtiEnv *jvmti = nullptr; -static jvmtiCapabilities caps; -static jint result = PASSED; -static jboolean printdump = JNI_FALSE; -static int count = 0; - -#ifdef STATIC_BUILD -JNIEXPORT jint JNICALL Agent_OnLoad_objmonusage003(JavaVM *jvm, char *options, void *reserved) { - return Agent_Initialize(jvm, options, reserved); -} -JNIEXPORT jint JNICALL Agent_OnAttach_objmonusage003(JavaVM *jvm, char *options, void *reserved) { - return Agent_Initialize(jvm, options, reserved); -} -JNIEXPORT jint JNI_OnLoad_objmonusage003(JavaVM *jvm, char *options, void *reserved) { - return JNI_VERSION_1_8; -} -#endif -jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { - jint res; - jvmtiError err; - - if (options != nullptr && strcmp(options, "printdump") == 0) { - printdump = JNI_TRUE; - } - - res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); - if (res != JNI_OK || jvmti == nullptr) { - printf("Wrong result of a valid call to GetEnv !\n"); - return JNI_ERR; - } - - err = jvmti->GetPotentialCapabilities(&caps); - if (err != JVMTI_ERROR_NONE) { - printf("(GetPotentialCapabilities) unexpected error: %s (%d)\n", - TranslateError(err), err); - return JNI_ERR; - } - - err = jvmti->AddCapabilities(&caps); - if (err != JVMTI_ERROR_NONE) { - printf("(AddCapabilities) unexpected error: %s (%d)\n", - TranslateError(err), err); - return JNI_ERR; - } - - err = jvmti->GetCapabilities(&caps); - if (err != JVMTI_ERROR_NONE) { - printf("(GetCapabilities) unexpected error: %s (%d)\n", - TranslateError(err), err); - return JNI_ERR; - } - - if (!caps.can_get_monitor_info) { - printf("Warning: GetObjectMonitorUsage is not implemented\n"); - } - - return JNI_OK; -} - -JNIEXPORT void JNICALL -Java_nsk_jvmti_GetObjectMonitorUsage_objmonusage003_check(JNIEnv *env, - jclass cls, jobject obj, jthread owner, - jint entryCount, jint waiterCount) { - jvmtiError err; - jvmtiMonitorUsage inf; - jvmtiThreadInfo tinf; - int j; - - count++; - - err = jvmti->GetObjectMonitorUsage(obj, &inf); - if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY && - !caps.can_get_monitor_info) { - /* Ok, it's expected */ - return; - } else if (err != JVMTI_ERROR_NONE) { - printf("(GetMonitorInfo#%d) unexpected error: %s (%d)\n", - count, TranslateError(err), err); - result = STATUS_FAILED; - return; - } - - if (printdump == JNI_TRUE) { - if (inf.owner == nullptr) { - printf(">>> [%2d] owner: none (0x0)\n", count); - } else { - err = jvmti->GetThreadInfo(inf.owner, &tinf); - printf(">>> [%2d] owner: %s (0x%p)\n", - count, tinf.name, inf.owner); - } - printf(">>> entry_count: %d\n", inf.entry_count); - printf(">>> waiter_count: %d\n", inf.waiter_count); - if (inf.waiter_count > 0) { - printf(">>> waiters:\n"); - for (j = 0; j < inf.waiter_count; j++) { - err = jvmti->GetThreadInfo(inf.waiters[j], &tinf); - printf(">>> %2d: %s (0x%p)\n", - j, tinf.name, inf.waiters[j]); - } - } - } - - if (!env->IsSameObject(owner, inf.owner)) { - printf("(%d) unexpected owner: 0x%p\n", count, inf.owner); - result = STATUS_FAILED; - } - - if (inf.entry_count != entryCount) { - printf("(%d) entry_count expected: %d, actually: %d\n", - count, entryCount, inf.entry_count); - result = STATUS_FAILED; - } - - if (inf.waiter_count != waiterCount) { - printf("(%d) waiter_count expected: %d, actually: %d\n", - count, waiterCount, inf.waiter_count); - result = STATUS_FAILED; - } -} - -JNIEXPORT jint JNICALL -Java_nsk_jvmti_GetObjectMonitorUsage_objmonusage003_getRes(JNIEnv *env, jclass cls) { - return result; -} - -} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/README b/test/hotspot/jtreg/vmTestbase/nsk/share/README index d36f955659b..a696a90d516 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/README +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/README @@ -54,7 +54,7 @@ Short description of files: text processing: Grep.java, Paragrep.java timeouts handling: - Terminator.java, TimeoutHandler.java + TimeoutHandler.java tree structures support: Denotation.java, TreeNodesDenotation.java RAS mode support: diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Terminator.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Terminator.java deleted file mode 100644 index dbf26d5a8fd..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/Terminator.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 nsk.share; - -/** - * Terminator is used to terminate a stress test with PASS exit status - * before the test is terminated as timed out (and so failed). - * - *

      Terminator class holds a thread which sleeps for the given amount - * of time, and then wakes up and executes System.exit() - * with the given exit status. That thread is daemon, so it doesn't - * prevent application from exiting once all its threads finish - * before it's time for termination. Appointing terminator in zero - * delay implies immediate exit(). - * - *

      There is a limitation: you may appoint no more than one terminator - * per application. - */ -public class Terminator { - /** - * Use specific appoint() method to appoint terminator. - * - * @see #appoint(int) - * @see #appoint(int,int) - */ - protected Terminator() {} - - /** - * One terminator per application, or null (by default). - */ - private static Thread terminator = null; - - /** - *

      Return timeout (or waittime) value munus the margin - * value (which is assumed 1 minute by default). - * - *

      Treat args[0] as $TIMEOUT value, or seek for - * -waittime=$WAITTIME value. If both parameters - * (or either none of them) are assigned, throw an exception to - * report parameters inconsistency. - * - *

      Also, seek for -margin=... assignment, or assume margin - * is 1 minute. - * - * @param args Is usually obtained via the application's command-line. - * - * @throws IllegalArgumentException If args[] is inconsistent. - * - * @see #appoint(int) - * @see #appoint(int,int) - */ - public static int parseAppointment(String args[]) { - int timeout=-1, margin=1; - int timeouts=0, waittimes=0, margins=0; - for (int i=0; i 1) - throw new IllegalArgumentException( - "more than one -waittime=... is set"); - if (margins > 1) - throw new IllegalArgumentException( - "more than one -margin=... is set"); - - int result = timeout - margin; - if (result <= 0) - throw new IllegalArgumentException( - "delay appointment must be greater than "+margin+" minutes"); - return result; - } - - /** - * Appoint terminator after the given amount of minutes, - * so that exit status would be 95 (to simulate JCK-like PASS - * status). - * - * @throws IllegalStateException If terminator is already appointed. - * - * @see #appoint(int,int) - * @see #parseAppointment(String[]) - */ - public static void appoint(int minutes) { - appoint(minutes,95); // JCK-like PASS status - } - - /** - * Appoint Terminator for the given amount of minutes, - * so that the given status would be exited when time - * is over. - * - * @throws IllegalStateException If terminator is already appointed. - * - * @see #appoint(int) - * @see #parseAppointment(String[]) - */ - public static void appoint(int minutes, int status) { - if (terminator != null) - throw new IllegalStateException("Terminator is already appointed."); - - final long timeToExit = System.currentTimeMillis() + 60*1000L*minutes; - final int exitStatus = status; - - terminator = new Thread(Terminator.class.getName()) { - public void run() { - long timeToSleep = timeToExit - System.currentTimeMillis(); - if (timeToSleep > 0) - try { - // - // Use wait() instead of sleep(), because Java 2 - // specification doesn't guarantee the method - // sleep() to yield to other threads. - // - Object someDummyObject = new Object(); - synchronized (someDummyObject) { - someDummyObject.wait(timeToSleep); - } - } catch (InterruptedException exception) { - exception.printStackTrace(System.err); - return; - }; - // - // OK, lets do it now: - // - System.err.println( - "#\n# Terminator: prescheduled program termination.\n#"); - System.exit(exitStatus); // terminator to all threads - } - }; - - terminator.setPriority(Thread.MAX_PRIORITY); - terminator.setDaemon(true); - terminator.start(); - } -} diff --git a/test/jdk/ProblemList-Xcomp.txt b/test/jdk/ProblemList-Xcomp.txt index 5f7f4a912aa..6e8953c521e 100644 --- a/test/jdk/ProblemList-Xcomp.txt +++ b/test/jdk/ProblemList-Xcomp.txt @@ -27,5 +27,6 @@ # ############################################################################# -java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all +java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all java/lang/management/MemoryMXBean/CollectionUsageThreshold.java 8318668 generic-all +com/sun/jdi/InterruptHangTest.java 8306679,8043571 generic-all diff --git a/test/jdk/com/sun/jdi/InterruptHangTest.java b/test/jdk/com/sun/jdi/InterruptHangTest.java index e2c238eee49..a8062586d27 100644 --- a/test/jdk/com/sun/jdi/InterruptHangTest.java +++ b/test/jdk/com/sun/jdi/InterruptHangTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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,76 +28,175 @@ /** * @test * @bug 6459476 - * @summary Debuggee is blocked, looks like running + * @summary Test interrupting debuggee with single stepping enable * @author jjh * * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g InterruptHangTest.java - * @run driver InterruptHangTest + * @run driver InterruptHangTest precise + * @run driver InterruptHangTest aggressive + * @run driver InterruptHangTest remote */ /** - * Debuggee has two threads. Debugger keeps stepping in - * the first thread. The second thread keeps interrupting the first - * thread. If a long time goes by with the debugger not getting - * a step event, the test fails. + * The debuggee loops in the main thread while the debugger has single stepping + * enabled for the debuggee's main thread. The main thread is repeatedly + * interrupted while it is looping. If a long time goes by with the debugger + * not getting a single step event, the test fails. + * + * Interrupts are generated in 3 difference modes: + * precise - The debuggee creates a 2nd thread that repeatedly calls + * Thread.interrupt() on the main thread, but does so in a controlled + * fashion that allows to test to verify that every interrupt is + * received and handled. + * aggressive - The debuggee creates a 2nd thread that repeatedly calls + * Thread.interrupt() on the main thread, but does so at a high pace + * and without any coordination with the main thread. Because of + * this it is not possible to account for all the interrupts since some + * might be done before the previous interrupt is handled. + * remote - Much like the "aggressive" mode, except interrupts are remotely + * generated by the debugger using ThreadReference.interrupt(). There + * is no "precise" mode for remotely generated interrupts since it is + * difficult to coordinate between the debugger and debuggee in a + * reasonable way. */ + class InterruptHangTarg { - public static String sync = "sync"; + static String sync = "sync"; + static int interruptsSent; + static boolean remoteMode; + static boolean preciseMode; + static boolean aggressiveMode; + + private final static int INTERRUPTS_EXPECTED = 200; + public static void main(String[] args){ - int answer = 0; + int answer = 0; // number of interrupts answered + System.out.println("Howdy!"); - Thread interruptorThread = DebuggeeWrapper.newThread(new Interruptor(Thread.currentThread())); - synchronized(sync) { + remoteMode = "remote".equals(args[0]); + preciseMode = "precise".equals(args[0]); + aggressiveMode = "aggressive".equals(args[0]); + + if (!remoteMode && !preciseMode && !aggressiveMode) { + throw new RuntimeException("Invalid first arg for debuggee: " + args[0]); + } + + // Create the debuggee interruptor thread if needed. + Thread interruptorThread; + if (preciseMode) { + interruptorThread = + DebuggeeWrapper.newThread(new PreciseInterruptor(Thread.currentThread())); interruptorThread.start(); - try { - sync.wait(); - } catch (InterruptedException ee) { - System.out.println("Debuggee interruptee: interrupted before starting loop"); - } + } else if (aggressiveMode) { + interruptorThread = + DebuggeeWrapper.newThread(new AggressiveInterruptor(Thread.currentThread())); + interruptorThread.start(); + } else { + interruptorThread = null; // we are in "remote" interrupt mode } // Debugger will keep stepping thru this loop - for (int ii = 0; ii < 200; ii++) { - answer++; + for (int ii = 0; ii < INTERRUPTS_EXPECTED; ii++) { + boolean wasInterrupted = false; try { - // Give other thread a chance to run + // Give other thread a chance to interrupt Thread.sleep(100); } catch (InterruptedException ee) { - System.out.println("Debuggee interruptee: interrupted at iteration: " - + ii); + answer++; + wasInterrupted = true; + boolean isInterrupted = Thread.currentThread().isInterrupted(); + System.out.println("Debuggee interruptee(" + ii + "): isInterrupted(" + isInterrupted + ")"); + if (preciseMode) { + // When Thread.sleep() is interrupted, the interrupted status of the thread + // should remain cleared (since InterruptedException was thrown), and the + // the next interrupt won't come in until after the sync.notify() below. + // Note this is not true for the aggressive and remote modes since + // interrupts can come in at any time, even while we are handling + // an intrrupt. + if (isInterrupted) { + throw new RuntimeException("Thread should not have interrupted status set."); + } + synchronized(InterruptHangTarg.sync) { + // Let the interruptor thread know it can start interrupting again + sync.notify(); + } + } + } + // Every Thread.sleep() call should get interrupted + if (!wasInterrupted) { + throw new RuntimeException("Thread was never interrupted during sleep: " + ii); + } + } + + if (interruptorThread != null) { + synchronized(InterruptHangTarg.sync) { + // Kill the interrupter thread + interruptorThread.interrupt(); } } - // Kill the interrupter thread - interruptorThread.interrupt(); + + // Print how many times an interrupt was sent. When in remote mode, the RemoteInterruptor + // is in a different process, so interruptsSent is not updated, therefore we don't + // print it here. The RemoteInterruptor thread keeps its own count and prints + // it before it exits. + if (!remoteMode) { + System.out.println("interrupts sent: " + interruptsSent); + } + + // When in precise mode, make sure that every interrupt sent resulted in + // an InterruptedException. Note the interruptor always ends up sending + // one extra interrupt at the end. + if (preciseMode && interruptsSent != answer + 1) { + throw new RuntimeException("Too many interrupts sent. Sent: " + interruptsSent + + ". Expected to send: " + answer + 1); + } System.out.println("Goodbye from InterruptHangTarg!"); } -} -class Interruptor implements Runnable { - Thread interruptee; - Interruptor(Thread interruptee) { - this.interruptee = interruptee; + static class AggressiveInterruptor implements Runnable { + Thread interruptee; + AggressiveInterruptor(Thread interruptee) { + this.interruptee = interruptee; + } + + public void run() { + while (true) { + InterruptHangTarg.interruptsSent++; + interruptee.interrupt(); + try { + Thread.sleep(5); + } catch (InterruptedException ee) { + System.out.println("Debuggee Interruptor: finished after " + + InterruptHangTarg.interruptsSent + " iterrupts"); + break; + } + } + } } - public void run() { - synchronized(InterruptHangTarg.sync) { - InterruptHangTarg.sync.notify(); + static class PreciseInterruptor implements Runnable { + Thread interruptee; + PreciseInterruptor(Thread interruptee) { + this.interruptee = interruptee; } - int ii = 0; - while(true) { - ii++; - interruptee.interrupt(); - try { - Thread.sleep(10); - } catch (InterruptedException ee) { - System.out.println("Debuggee Interruptor: finished after " + - ii + " iterrupts"); - break; + public void run() { + synchronized(InterruptHangTarg.sync) { + while (true) { + InterruptHangTarg.interruptsSent++; + interruptee.interrupt(); + try { + // Wait until the interruptee has handled the interrupt + InterruptHangTarg.sync.wait(); + } catch (InterruptedException ee) { + System.out.println("Debuggee Interruptor: finished after " + + InterruptHangTarg.interruptsSent + " iterrupts"); + break; + } + } } - } } } @@ -105,16 +204,48 @@ public void run() { /********** test program **********/ public class InterruptHangTest extends TestScaffold { + class RemoteInterruptor extends Thread { + static int interruptsSent; + ThreadReference interruptee; + + RemoteInterruptor(ThreadReference interruptee) { + this.interruptee = interruptee; + } + + public void run() { + try { + while (true) { + interruptee.interrupt(); + interruptsSent++; + Thread.sleep(5); + } + } catch (InterruptedException ee) { + println("RemoteInterruptor thread: Unexpected Interrupt"); + throw new RuntimeException(ee); + } catch (IllegalThreadStateException | VMDisconnectedException ee) { + println("RemoteInterruptor thread: Got expected " + ee.getClass().getSimpleName() + + " after " + interruptsSent + " interrupts sent. Exiting."); + } catch (Throwable ee) { + println("RemoteInterruptor thread: Got unexpected exception after " + + interruptsSent + " interrupts sent. Exiting with exception."); + ee.printStackTrace(System.out); + throw new RuntimeException(ee); + } + } + } + ThreadReference mainThread; Thread timerThread; String sync = "sync"; static int nSteps = 0; + static boolean remoteMode; InterruptHangTest (String args[]) { super(args); } public static void main(String[] args) throws Exception { + remoteMode = "remote".equals(args[0]); new InterruptHangTest(args).startTests(); } @@ -174,11 +305,23 @@ public void run() { } }; + Thread remoteInterruptorThread = null; + if (remoteMode) { + // Create a thread to call ThreadReference.interrupt() on the + // debuggee main thread. + remoteInterruptorThread = new RemoteInterruptor(mainThread); + remoteInterruptorThread.setName("RemoteInterruptor"); + remoteInterruptorThread.setDaemon(true); + remoteInterruptorThread.start(); + } + /* * resume the target listening for events */ - listenUntilVMDisconnect(); + if (remoteInterruptorThread != null) { + remoteInterruptorThread.join(); + } timerThread.interrupt(); /* @@ -186,9 +329,9 @@ public void run() { * if anything has called failure("foo") testFailed will be true */ if (!testFailed) { - println("InterruptHangTest: passed"); + println("InterruptHangTest("+ args[0] + "): passed"); } else { - throw new Exception("InterruptHangTest: failed"); + throw new Exception("InterruptHangTest("+ args[0] + "): failed"); } } } diff --git a/test/jdk/com/sun/net/httpserver/HttpsParametersClientAuthTest.java b/test/jdk/com/sun/net/httpserver/HttpsParametersClientAuthTest.java new file mode 100644 index 00000000000..ded0474071b --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/HttpsParametersClientAuthTest.java @@ -0,0 +1,400 @@ +/* + * 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. + * + * 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. + */ + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.security.AccessController; +import java.security.KeyStore; +import java.security.PrivilegedExceptionAction; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.TrustManagerFactory; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsParameters; +import com.sun.net.httpserver.HttpsServer; +import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.net.URIBuilder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpClient.Version.HTTP_1_1; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +/* + * @test + * @bug 8326381 + * @summary verifies that the setNeedClientAuth() and setWantClientAuth() + * methods on HttpsParameters class work as expected + * @library /test/lib + * @build jdk.test.lib.net.SimpleSSLContext jdk.test.lib.net.URIBuilder + * @run junit HttpsParametersClientAuthTest + */ +public class HttpsParametersClientAuthTest { + + private static final AtomicInteger TID = new AtomicInteger(); + private static final ThreadFactory SRV_THREAD_FACTORY = (r) -> { + final Thread t = new Thread(r); + t.setDaemon(true); + t.setName("server-thread-" + TID.incrementAndGet()); + return t; + }; + + /** + * verifies default values of {@link HttpsParameters#setNeedClientAuth(boolean)} + * and {@link HttpsParameters#setWantClientAuth(boolean)} methods + */ + @Test + public void testDefaultClientAuth() throws Exception { + // test default values + HttpsParameters defaultParams = new Params(); + assertFalse(defaultParams.getNeedClientAuth(), + "needClientAuth was expected to be false but wasn't"); + assertFalse(defaultParams.getWantClientAuth(), + "wantClientAuth was expected to be false but wasn't"); + } + + /** + * sets {@link HttpsParameters#setNeedClientAuth(boolean)} and verifies + * that subsequent calls to {@link HttpsParameters#getNeedClientAuth()} returns + * the set value and {@link HttpsParameters#getWantClientAuth()} returns false + */ + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testNeedClientAuth(final boolean initialWantClientAuth) throws Exception { + HttpsParameters needClientAuthParams = new Params(); + // first set wantClientAuth to an initial value to verify that it later gets reset + needClientAuthParams.setWantClientAuth(initialWantClientAuth); + // needClientAuth = true and thus wantClientAuth = false + needClientAuthParams.setNeedClientAuth(true); + assertTrue(needClientAuthParams.getNeedClientAuth(), + "needClientAuth was expected to be true but wasn't"); + assertFalse(needClientAuthParams.getWantClientAuth(), + "wantClientAuth was expected to be false but wasn't"); + // now set needClientAuth = false and verify that both needClientAuth and wantClientAuth + // are now false + needClientAuthParams.setNeedClientAuth(false); + assertFalse(needClientAuthParams.getNeedClientAuth(), + "needClientAuth was expected to be false but wasn't"); + assertFalse(needClientAuthParams.getWantClientAuth(), + "wantClientAuth was expected to be false but wasn't"); + } + + /** + * sets {@link HttpsParameters#setWantClientAuth(boolean)} and verifies + * that subsequent calls to {@link HttpsParameters#getWantClientAuth()} returns + * the set value and {@link HttpsParameters#getNeedClientAuth()} returns false + */ + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testWantClientAuth(final boolean initialNeedClientAuth) throws Exception { + HttpsParameters wantClientAuthParams = new Params(); + // first set needClientAuth to an initial value to verify that it later gets reset + wantClientAuthParams.setNeedClientAuth(initialNeedClientAuth); + // wantClientAuth = true and thus needClientAuth = false + wantClientAuthParams.setWantClientAuth(true); + assertTrue(wantClientAuthParams.getWantClientAuth(), + "wantClientAuth was expected to be true but wasn't"); + assertFalse(wantClientAuthParams.getNeedClientAuth(), + "needClientAuth was expected to be false but wasn't"); + // now set wantClientAuth = false and verify that both wantClientAuth and needClientAuth + // are now false + wantClientAuthParams.setWantClientAuth(false); + assertFalse(wantClientAuthParams.getWantClientAuth(), + "wantClientAuth was expected to be false but wasn't"); + assertFalse(wantClientAuthParams.getNeedClientAuth(), + "needClientAuth was expected to be false but wasn't"); + } + + /** + * Starts a {@link HttpsServer} by + * {@linkplain HttpsParameters#setNeedClientAuth(boolean) setting needClientAuth} as + * {@code true}. The client is then configured either to present the client certificates + * during the TLS handshake or configured not to present them. In the case where the + * client presents the client certificates, the HTTP request issued by the client is + * expected to pass. In the other case where the client doesn't present the certificates, + * the test verifies that the HTTP request fails due to a connection error + * (caused by TLS handshake failure) + * + * @param presentClientCerts true if the client should present certificates + * during TLS handshake, false otherwise + */ + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testServerNeedClientAuth(final boolean presentClientCerts) throws Exception { + // SSLContext which contains both the key and the trust material and will be used + // by the server + final SSLContext serverSSLCtx = new SimpleSSLContext().get(); + assertNotNull(serverSSLCtx, "could not create SSLContext"); + final HttpsConfigurator configurator = new HttpsConfigurator(serverSSLCtx) { + @Override + public void configure(final HttpsParameters params) { + // we intentionally don't call params.setSSLParameters() + // and instead call params.setNeedClientAuth() + params.setNeedClientAuth(true); // "require" the client to present certs + } + }; + try (final ExecutorService executor = Executors.newCachedThreadPool(SRV_THREAD_FACTORY)) { + final HttpsServer server = createHttpsServer(executor, configurator); + server.start(); + System.out.println("started server at " + server.getAddress()); + try { + final HttpClient.Builder builder = createClientBuilder(); + // if the client is expected to present client certificates, then + // we construct a SSLContext which has both key and trust material. + // otherwise we construct a SSLContext that only has trust material + // and thus won't present certificates during TLS handshake + final SSLContext clientSSLCtx = presentClientCerts + ? serverSSLCtx : onlyTrustStoreContext(); + // construct the client using the SSLContext + try (final HttpClient client = builder.sslContext(clientSSLCtx) + .build()) { + // issue a request + final URI reqURI = URIBuilder.newBuilder() + .scheme("https") + .host(server.getAddress().getAddress()) + .port(server.getAddress().getPort()) + .path("/") + .build(); + System.out.println("issuing request to " + reqURI); + final HttpResponse resp; + try { + resp = client.send(HttpRequest.newBuilder(reqURI).build(), + BodyHandlers.discarding()); + if (!presentClientCerts) { + // request was expected to fail since the server was configured to force + // the client to present the client cert, but the client didn't + // present any + fail("request was expected to fail, but didn't"); + } + assertEquals(200, resp.statusCode(), "unexpected response code"); + // verify the client did present the certs + assertTrue(resp.sslSession().isPresent(), "missing SSLSession on response"); + assertNotNull(resp.sslSession().get().getLocalCertificates(), + "client was expected to present certs to the server, but didn't"); + } catch (IOException ioe) { + if (presentClientCerts) { + // wasn't expected to fail, just let the exception propagate + throw ioe; + } + // verify it failed due to right reason + Throwable cause = ioe; + while (cause != null) { + // either of SocketException or SSLHandshakeException are OK + if (cause instanceof SocketException se) { + final String msg = se.getMessage(); + assertTrue(msg != null && msg.contains("Connection reset"), + "unexpected message in SocketException: " + msg); + System.out.println("received the expected exception: " + se); + break; + } else if (cause instanceof SSLHandshakeException she) { + final String msg = she.getMessage(); + assertTrue(msg != null && msg.contains("certificate_required"), + "unexpected message in SSLHandshakeException: " + msg); + System.out.println("received the expected exception: " + she); + break; + } + cause = cause.getCause(); + } + if (cause == null) { + // didn't find expected exception, rethrow original exception + throw ioe; + } + } + } + } finally { + System.out.println("Stopping server at " + server.getAddress()); + server.stop(0 /* delay */); + } + } + } + + /** + * Starts a {@link HttpsServer} by + * {@linkplain HttpsParameters#setWantClientAuth(boolean) setting wantClientAuth} as + * {@code true}. The client is then configured to either present the client certificates + * during the TLS handshake or configured not to present them. In both these cases the + * HTTP request issued by the client is expected to pass. + * + * @param presentClientCerts true if the client should present certificates + * during TLS handshake, false otherwise + */ + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testServerWantClientAuth(final boolean presentClientCerts) throws Exception { + // SSLContext which contains both the key and the trust material and will be used + // by the server + final SSLContext serverSSLCtx = new SimpleSSLContext().get(); + assertNotNull(serverSSLCtx, "could not create SSLContext"); + final HttpsConfigurator configurator = new HttpsConfigurator(serverSSLCtx) { + @Override + public void configure(final HttpsParameters params) { + // we intentionally don't call params.setSSLParameters() + // and instead call params.setWantClientAuth() + params.setWantClientAuth(true); // "request" the client to present certs + } + }; + try (final ExecutorService executor = Executors.newCachedThreadPool(SRV_THREAD_FACTORY)) { + final HttpsServer server = createHttpsServer(executor, configurator); + server.start(); + System.out.println("started server at " + server.getAddress()); + try { + final HttpClient.Builder builder = createClientBuilder(); + // if the client is expected to present client certificates, then + // we construct a SSLContext which has both key and trust material. + // otherwise we construct a SSLContext that only has trust material + // and thus won't present certificates during TLS handshake + final SSLContext clientSSLCtx = presentClientCerts + ? serverSSLCtx : onlyTrustStoreContext(); + // construct the client using the SSLContext + try (final HttpClient client = builder.sslContext(clientSSLCtx) + .build()) { + // issue a request + final URI reqURI = URIBuilder.newBuilder() + .scheme("https") + .host(server.getAddress().getAddress()) + .port(server.getAddress().getPort()) + .path("/") + .build(); + System.out.println("issuing request to " + reqURI); + final HttpResponse resp = client.send( + HttpRequest.newBuilder(reqURI).build(), BodyHandlers.discarding()); + assertEquals(200, resp.statusCode(), "unexpected response code"); + if (presentClientCerts) { + // verify the client did present the certs + assertTrue(resp.sslSession().isPresent(), "missing SSLSession on response"); + assertNotNull(resp.sslSession().get().getLocalCertificates(), + "client was expected to present certs to the server, but didn't"); + } + } + } finally { + System.out.println("Stopping server at " + server.getAddress()); + server.stop(0 /* delay */); + } + } + } + + private static HttpsServer createHttpsServer(final Executor executor, + final HttpsConfigurator configurator) + throws IOException { + final InetAddress loopback = InetAddress.getLoopbackAddress(); + final HttpsServer server = HttpsServer.create( + new InetSocketAddress(loopback, 0), 0 /* backlog */); + server.setExecutor(executor); + server.setHttpsConfigurator(configurator); + server.createContext("/", new AllOKHandler()); + return server; + } + + private static HttpClient.Builder createClientBuilder() { + return HttpClient.newBuilder().version(HTTP_1_1) + .proxy(NO_PROXY); + } + + /** + * Creates and returns a {@link SSLContext} which only has trust material + * and doesn't have any test specific keys. + */ + private static SSLContext onlyTrustStoreContext() throws Exception { + final KeyStore keyStore = loadTestKeyStore(); + final TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(keyStore); + final SSLContext ctx = SSLContext.getInstance("TLS"); + // initialize with only trust managers + ctx.init(null, tmf.getTrustManagers(), null); + return ctx; + } + + private static KeyStore loadTestKeyStore() throws Exception { + return AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public KeyStore run() throws Exception { + final String testKeys = System.getProperty("test.src") + + "/" + + "../../../../../../test/lib/jdk/test/lib/net/testkeys"; + try (final FileInputStream fis = new FileInputStream(testKeys)) { + final char[] passphrase = "passphrase".toCharArray(); + final KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(fis, passphrase); + return ks; + } + } + }); + } + + // no-op implementations of the abstract methods of HttpsParameters + private static final class Params extends HttpsParameters { + + @Override + public HttpsConfigurator getHttpsConfigurator() { + // no-op + return null; + } + + @Override + public InetSocketAddress getClientAddress() { + // no-op + return null; + } + + @Override + public void setSSLParameters(SSLParameters params) { + // no-op + } + } + + // A HttpHandler which just returns 200 response code + private static final class AllOKHandler implements HttpHandler { + + private static final int NO_RESPONSE_BODY = -1; + + @Override + public void handle(final HttpExchange exchange) throws IOException { + System.out.println("responding to request: " + exchange.getRequestURI()); + exchange.sendResponseHeaders(200, NO_RESPONSE_BODY); + } + } +} diff --git a/test/jdk/java/awt/FileDialog/MultipleMode.java b/test/jdk/java/awt/FileDialog/MultipleMode.java new file mode 100644 index 00000000000..da26f4a20d9 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/MultipleMode.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2010, 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. + * + * 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. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; +import java.io.File; + +/* + * @test + * @bug 6467204 + * @summary Need to implement "extended" native FileDialog for JFileChooser + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultipleMode +*/ + +public class MultipleMode { + + private static final String INSTRUCTIONS = + """ + 1. Verify that the 'multiple' checkbox is off and press the 'open' button + 2. Verify that the file dialog doesn't allow the multiple file selection + 3. Select any file and close the file dialog + 4. The results will be displayed, verify the results + 5. Turn the 'multiple' checkbox on and press the 'open' button + 6. Verify that the file dialog allows the multiple file selection + 7. Select several files and close the file dialog + 8. The results will be displayed, verify the results. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame + .builder() + .title("MultipleMode test instructions") + .instructions(INSTRUCTIONS) + .rows(15) + .columns(40) + .position(PassFailJFrame.Position.TOP_LEFT_CORNER) + .testUI(MultipleMode::init) + .build() + .awaitAndCheck(); + } + + private static Frame init() { + Frame frame = new Frame("MultipleMode"); + TextArea sysout = new TextArea("", 20, 70); + sysout.setEditable(false); + + final Checkbox mode = new Checkbox("multiple", false); + + Button open = new Button("open"); + open.addActionListener(e -> { + FileDialog d = new FileDialog(frame); + d.setMultipleMode(mode.getState()); + d.setVisible(true); + + // print the results + sysout.append("DIR:\n"); + sysout.append(" %s\n".formatted(d.getDirectory())); + sysout.append("FILE:\n"); + sysout.append(" %s\n".formatted(d.getFile())); + sysout.append("FILES:\n"); + for (File f : d.getFiles()) { + sysout.append(" %s\n".formatted(f)); + } + }); + + Panel panel = new Panel(new FlowLayout()); + panel.add(mode); + panel.add(open); + + frame.setLayout(new BorderLayout()); + frame.add(panel, BorderLayout.NORTH); + frame.add(sysout, BorderLayout.CENTER); + + frame.pack(); + + return frame; + } +} diff --git a/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.html b/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.html deleted file mode 100644 index 16118014e23..00000000000 --- a/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - MultipleMode - - - -

      MultipleMode
      Bug ID: 6467204

      - -

      See the dialog box (usually in upper left corner) for instructions

      - - - - diff --git a/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.java b/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.java deleted file mode 100644 index e0e7bdf83c7..00000000000 --- a/test/jdk/java/awt/FileDialog/MultipleMode/MultipleMode.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - test - @bug 6467204 - @summary Need to implement "extended" native FileDialog for JFileChooser - @author dmitry.cherepanov@sun.com area=awt.filedialog - @run applet/manual=yesno MultipleMode.html -*/ - -// Note there is no @ in front of test above. This is so that the -// harness will not mistake this file as a test file. It should -// only see the html file as a test file. (the harness runs all -// valid test files, so it would run this test twice if this file -// were valid as well as the html file.) -// Also, note the area= after Your Name in the author tag. Here, you -// should put which functional area the test falls in. See the -// AWT-core home page -> test areas and/or -> AWT team for a list of -// areas. -// There are several places where ManualYesNoTest appear. It is -// recommended that these be changed by a global search and replace, -// such as ESC-% in xemacs. - - - -/** - * MultipleMode.java - * - * summary: - */ - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.*; -import java.io.File; - - -//Manual tests should run as applet tests if possible because they -// get their environments cleaned up, including AWT threads, any -// test created threads, and any system resources used by the test -// such as file descriptors. (This is normally not a problem as -// main tests usually run in a separate VM, however on some platforms -// such as the Mac, separate VMs are not possible and non-applet -// tests will cause problems). Also, you don't have to worry about -// synchronisation stuff in Applet tests the way you do in main -// tests... - - -public class MultipleMode extends Applet -{ - //Declare things used in the test, like buttons and labels here - - public void init() - { - //Create instructions for the user here, as well as set up - // the environment -- set the layout manager, add buttons, - // etc. - this.setLayout (new BorderLayout ()); - - String[] instructions = - { - " 1. Turn the 'multiple' checkbox off and press the 'open' button ", - " 2. Verify that the file dialog doesn't allow the multiple file selection ", - " 3. Select any file and close the file dialog ", - " 4. The results will be displayed, verify the results ", - " 5. Turn the 'multiple' checkbox on and press the 'open' button ", - " 6. Verify that the file dialog allows the multiple file selection ", - " 7. Select several files and close the file dialog ", - " 8. The results will be displayed, verify the results " - }; - Sysout.createDialogWithInstructions( instructions ); - - }//End init() - - public void start () - { - final Checkbox mode = new Checkbox("multiple", true); - Button open = new Button("open"); - open.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - FileDialog d = new FileDialog((Frame)null); - d.setMultipleMode(mode.getState()); - d.setVisible(true); - - // print the results - Sysout.println("DIR:"); - Sysout.println(d.getDirectory()); - Sysout.println("FILE:"); - Sysout.println(d.getFile()); - Sysout.println("FILES:"); - File files[] = d.getFiles(); - for (File f : files) { - Sysout.println(String.valueOf(f)); - } - } - }); - - setLayout(new FlowLayout()); - add(mode); - add(open); - - //Get things going. Request focus, set size, et cetera - setSize (200,200); - setVisible(true); - validate(); - - }// start() - - //The rest of this class is the actions which perform the test... - - //Use Sysout.println to communicate with the user NOT System.out!! - //Sysout.println ("Something Happened!"); - -}// class ManualYesNoTest - -/* Place other classes related to the test after this line */ - - - - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - private static boolean numbering = false; - private static int messageNumber = 0; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - /* Enables message counting for the tester. */ - public static void enableNumbering(boolean enable){ - numbering = enable; - } - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - if (numbering) { - messageIn = "" + messageNumber + " " + messageIn; - messageNumber++; - } - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff --git a/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest.java b/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest.java new file mode 100644 index 00000000000..fc88ffa879e --- /dev/null +++ b/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest.java @@ -0,0 +1,91 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JButton; +import java.awt.FileDialog; +import java.awt.Frame; +import java.io.File; + +/* + * @test + * @bug 6998877 8022531 + * @summary After double-click on the folder names, FileNameOverrideTest FAILED + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SaveFileNameOverrideTest + */ + +public class SaveFileNameOverrideTest { + + private final static String clickDirName = "Directory for double click"; + private static final String INSTRUCTIONS = + """ + 1) Click on the 'Show File Dialog' button. A file dialog will appear. + 2) Double-click on '%s' + 3) Click on a confirmation button. + (It can be 'OK', 'Save' or any other name depending on the platform). + 3) The test will automatically pass or fail. + """ + .formatted(clickDirName); + private final static String dirPath = "."; + + public static void main(String[] args) throws Exception { + System.out.println(System.getProperties()); + System.out.println(new File(dirPath).getAbsolutePath()); + File tmpDir = new File(dirPath + File.separator + clickDirName); + if (!tmpDir.mkdir()) { + throw new RuntimeException("Cannot create directory."); + } + tmpDir.deleteOnExit(); + + PassFailJFrame + .builder() + .title("SaveFileNameOverrideTest Instructions") + .instructions(INSTRUCTIONS) + .splitUIRight(SaveFileNameOverrideTest::getButton) + .rows(8) + .columns(40) + .build() + .awaitAndCheck(); + } + + public static JButton getButton() { + JButton showBtn = new JButton("Show File Dialog"); + showBtn.addActionListener(e -> { + FileDialog fd = + new FileDialog((Frame) null, "Save", FileDialog.SAVE); + + fd.setFile("input"); + fd.setDirectory(new File(dirPath).getAbsolutePath()); + fd.setVisible(true); + + String output = fd.getFile(); + if ("input".equals(output)) { + PassFailJFrame.forcePass(); + } else { + PassFailJFrame.forceFail("TEST FAILED (output file - " + output + ")"); + } + }); + return showBtn; + } +} diff --git a/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.html b/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.html deleted file mode 100644 index 0a0d48e48c6..00000000000 --- a/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - SaveFileNameOverrideTest - - - -

      SaveFileNameOverrideTest
      Bug ID: 6260659

      - -

      See the dialog box (usually in upper left corner) for instructions

      - - - - diff --git a/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.java b/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.java deleted file mode 100644 index 79b5a3a6de0..00000000000 --- a/test/jdk/java/awt/FileDialog/SaveFileNameOverrideTest/SaveFileNameOverrideTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - test - @bug 6998877 8022531 - @summary After double-click on the folder names, FileNameOverrideTest FAILED - @author Sergey.Bylokhov@oracle.com area=awt.filedialog - @library ../../regtesthelpers - @build Sysout - @run applet/manual=yesno SaveFileNameOverrideTest.html -*/ - -import test.java.awt.regtesthelpers.Sysout; - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; - -public class SaveFileNameOverrideTest extends Applet implements ActionListener { - private final static String clickDirName = "Directory for double click"; - private final static String dirPath = "."; - private Button showBtn; - private FileDialog fd; - - public void init() { - this.setLayout(new GridLayout(1, 1)); - - fd = new FileDialog(new Frame(), "Save", FileDialog.SAVE); - - showBtn = new Button("Show File Dialog"); - showBtn.addActionListener(this); - add(showBtn); - - File tmpDir = new File(dirPath + File.separator + clickDirName); - tmpDir.mkdir(); - - String[] instructions = { - "1) Click on 'Show File Dialog' button. A file dialog will come up.", - "2) Double-click on '" + clickDirName + "' and click a confirmation", - " button, it can be 'OK', 'Save' or any other platform-dependent name.", - "3) See result of the test below" - }; - - Sysout.createDialogWithInstructions(instructions); - - }//End init() - - public void start() { - setSize(200, 200); - show(); - }// start() - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == showBtn) { - fd.setFile("input"); - fd.setDirectory(dirPath); - fd.setVisible(true); - String output = fd.getFile(); - if ("input".equals(output)) { - Sysout.println("TEST PASSED"); - } else { - Sysout.println("TEST FAILED (output file - " + output + ")"); - } - } - } -}// class ManualYesNoTest diff --git a/test/jdk/java/awt/Frame/Iconify/IconifiedToFront.java b/test/jdk/java/awt/Frame/Iconify/IconifiedToFront.java new file mode 100644 index 00000000000..5edb5ae7676 --- /dev/null +++ b/test/jdk/java/awt/Frame/Iconify/IconifiedToFront.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, JetBrains s.r.o.. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @key headful + * @bug 8326497 + * @summary Verifies that an iconified window is restored with Window.toFront() + * @library /test/lib + * @run main IconifiedToFront + */ + +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Robot; +import java.awt.Toolkit; + +public class IconifiedToFront { + private static final int PAUSE_MS = 500; + private static Robot robot; + + public static void main(String[] args) throws Exception { + if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.ICONIFIED)) { + return; // Nothing to test + } + + robot = new Robot(); + IconifiedToFront.test1(); + IconifiedToFront.test2(); + } + + private static void test1() { + Frame frame1 = new Frame("IconifiedToFront Test 1"); + try { + frame1.setLayout(new FlowLayout()); + frame1.setSize(400, 300); + frame1.setBackground(Color.green); + frame1.add(new Label("test")); + frame1.setVisible(true); + pause(); + frame1.setExtendedState(Frame.ICONIFIED); + pause(); + frame1.toFront(); + pause(); + int state = frame1.getExtendedState(); + if ((state & Frame.ICONIFIED) != 0) { + throw new RuntimeException("Test Failed: state is still ICONIFIED: " + state); + } + } finally { + frame1.dispose(); + } + } + + private static void test2() { + Frame frame1 = new Frame("IconifiedToFront Test 3"); + try { + frame1.setLayout(new FlowLayout()); + frame1.setSize(400, 300); + frame1.setBackground(Color.green); + frame1.add(new Label("test")); + frame1.setUndecorated(true); + frame1.setVisible(true); + pause(); + frame1.setExtendedState(Frame.ICONIFIED); + pause(); + frame1.toFront(); + pause(); + int state = frame1.getExtendedState(); + if ((state & Frame.ICONIFIED) != 0) { + throw new RuntimeException("Test Failed: state is still ICONIFIED: " + state); + } + } finally { + frame1.dispose(); + } + } + + private static void pause() { + robot.delay(PAUSE_MS); + robot.waitForIdle(); + } +} diff --git a/test/jdk/java/awt/InputMethods/SpanishDiacriticsTest.java b/test/jdk/java/awt/InputMethods/SpanishDiacriticsTest.java new file mode 100644 index 00000000000..0468f222774 --- /dev/null +++ b/test/jdk/java/awt/InputMethods/SpanishDiacriticsTest.java @@ -0,0 +1,92 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8169355 + * @summary Check if Spanish diacritical signs could be typed for TextField + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @run main/manual SpanishDiacriticsTest +*/ + + +import java.util.concurrent.locks.LockSupport; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import javax.swing.JFrame; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +public class SpanishDiacriticsTest { + + static final String INSTRUCTIONS = """ + This test requires the following keyboard layout to be installed: + Windows OS: Spanish (United States) with 'Latin American' keyboard layout. + If using a US layout, the results should still be as described but + you have not tested the real bug. + + 1. A frame with a text field should be displayed. + 2. Set focus to the text field and switch to Spanish + with 'Latin American' keyboard layout. + 3. Type the following: ' ' o - i.e. single quote two times, then o. + If your keyboard has a US physical layout the [ key can be used + to type the single quote when in 'Latin American' keyboard mode. + 4. Type these characters at a normal speed but do NOT be concerned + that they take several seconds to display. That is an + expected behaviour for this test. + + If the text field displays the same three characters you typed: ''o + (i.e. two single quotes followed by o without an acute) + then press Pass; otherwise press Fail. + """; + + public static void main(String[] args) throws Exception { + + PassFailJFrame.builder() + .title("Spanish Diacritics") + .instructions(INSTRUCTIONS) + .rows(20) + .columns(50) + .testUI(SpanishDiacriticsTest::createTestUI) + .build() + .awaitAndCheck(); + } + + static JFrame createTestUI() { + JFrame frame = new JFrame("Spanish Diacritics Test Frame"); + JTextField textField = new JTextField(20); + textField.addKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + LockSupport.parkNanos(1_000_000_000L); + } + }); + frame.add(textField); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.pack(); + return frame; + } +} + diff --git a/test/jdk/java/awt/InputMethods/SpanishDiacriticsTest/SpanishDiacriticsTest.html b/test/jdk/java/awt/InputMethods/SpanishDiacriticsTest/SpanishDiacriticsTest.html deleted file mode 100644 index af6cd0c7610..00000000000 --- a/test/jdk/java/awt/InputMethods/SpanishDiacriticsTest/SpanishDiacriticsTest.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - SpanishDiacriticsTest - - - - -Test run requires the following keyboard layout to be installed: -Windows OS: Spanish (United States) with 'Latin American' keyboard layout - -1. A frame with a text field should be displayed at upper left corner -2. Set focus to the text field and switch to Spanish with 'Latin American' keyboard layout -3. Type the following: ' ' o - i.e. single quote two times (using [ key on US keyboard) then o character. - -If you the text field displays ''o, (i.e. o should be without acute) then the test is passed; otherwise failed. - - diff --git a/test/jdk/java/awt/InputMethods/SpanishDiacriticsTest/SpanishDiacriticsTest.java b/test/jdk/java/awt/InputMethods/SpanishDiacriticsTest/SpanishDiacriticsTest.java deleted file mode 100644 index 78877061e60..00000000000 --- a/test/jdk/java/awt/InputMethods/SpanishDiacriticsTest/SpanishDiacriticsTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8169355 - * @summary Check if Spanish diacritical signs could be typed for TextField - * @author Dmitry Markov - * @run applet/manual=yesno SpanishDiacriticsTest.html -*/ - -import javax.swing.*; -import java.applet.Applet; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.util.concurrent.locks.LockSupport; - -public class SpanishDiacriticsTest extends Applet { - @Override - public void init() { - SwingUtilities.invokeLater(() -> { - JFrame frame = new JFrame(); - JTextField textField = new JTextField(20); - textField.addKeyListener(new KeyAdapter() { - @Override - public void keyTyped(KeyEvent e) { - LockSupport.parkNanos(1_000_000_000L); - } - }); - frame.add(textField); - frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - frame.pack(); - frame.setVisible(true); - }); - } -} - diff --git a/test/jdk/java/awt/TrayIcon/DisposeInActionEventTest.java b/test/jdk/java/awt/TrayIcon/DisposeInActionEventTest.java new file mode 100644 index 00000000000..98a473bc64a --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/DisposeInActionEventTest.java @@ -0,0 +1,132 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.image.BufferedImage; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +import jdk.test.lib.Platform; + +/* + * @test + * @bug 6299866 8316931 + * @summary Tests that no NPE is thrown when the tray icon is disposed from the + * handler of action event caused by clicking on this icon. + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @run main/manual DisposeInActionEventTest + */ + +public class DisposeInActionEventTest { + private static SystemTray systemTray; + private static TrayIcon trayIcon; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new jtreg.SkippedException("The test cannot be run because " + + "SystemTray is not supported."); + } + String clickInstruction = + (Platform.isOSX()) ? "Right-click" : "Double click (left mouse button)"; + + String instructions = "When the test starts, it adds an icon to the tray area.\n" + + "The icon is a red filled square with a white border.\n" + + "If you don't see this tray icon, please make sure that the tray area\n" + + "(also called Taskbar Status Area on MS Windows, Notification\n" + + "Area on Gnome or System Tray on KDE) is visible.\n" + + "On macOS the default location is the right of the top system bar.\n\n" + + clickInstruction + " the tray icon to trigger the action event.\n" + + "Brief information about action events is printed\n" + + "in the Event Message Display frame.\n" + + "After each action event, the tray icon is removed from\n" + + "the tray and then added back in a second.\n\n" + + "The test checks if any exceptions are thrown when removing and\n" + + "re-adding the icon. If something is wrong, the test will automatically fail.\n" + + "Repeat clicks several times. Then press PASS button."; + + try { + PassFailJFrame.builder() + .title("DisposeInActionEventTest") + .instructions(instructions) + .rows(18) + .columns(45) + .testUI(DisposeInActionEventTest::showFrameAndIcon) + .build() + .awaitAndCheck(); + } finally { + if (systemTray != null) { + systemTray.remove(trayIcon); + } + } + } + + private static JFrame showFrameAndIcon() { + JFrame frame = new JFrame("Event Message Display"); + frame.setLayout(new BorderLayout()); + + JTextArea textArea = new JTextArea(); + frame.getContentPane().add(new JScrollPane(textArea)); + frame.setSize(400, 200); + + BufferedImage img = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); + Graphics g = img.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, 32, 32); + g.setColor(Color.RED); + g.fillRect(6, 6, 20, 20); + g.dispose(); + + systemTray = SystemTray.getSystemTray(); + trayIcon = new TrayIcon(img); + trayIcon.setImageAutoSize(true); + trayIcon.addActionListener(ev -> { + textArea.append(ev + "\n"); + systemTray.remove(trayIcon); + new Thread(() -> { + try { + Thread.sleep(1000); + systemTray.add(trayIcon); + } catch (AWTException | InterruptedException e) { + e.printStackTrace(); + PassFailJFrame.forceFail("Exception caught: " + e.getMessage()); + } + }).start(); + }); + + try { + systemTray.add(trayIcon); + } catch (AWTException e) { + e.printStackTrace(); + PassFailJFrame.forceFail("Exception caught: " + e.getMessage()); + } + + return frame; + } +} diff --git a/test/jdk/java/awt/TrayIcon/DisposeInActionEventTest/DisposeInActionEventTest.html b/test/jdk/java/awt/TrayIcon/DisposeInActionEventTest/DisposeInActionEventTest.html deleted file mode 100644 index fde3c620a01..00000000000 --- a/test/jdk/java/awt/TrayIcon/DisposeInActionEventTest/DisposeInActionEventTest.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - DisposeInActionEventTest - - - -

      DisposeInActionEventTest
      Bug ID: 6299866

      - -

      See the dialog box (usually in upper left corner) for instructions

      - - - - diff --git a/test/jdk/java/awt/TrayIcon/DisposeInActionEventTest/DisposeInActionEventTest.java b/test/jdk/java/awt/TrayIcon/DisposeInActionEventTest/DisposeInActionEventTest.java deleted file mode 100644 index 1d9ff597d6b..00000000000 --- a/test/jdk/java/awt/TrayIcon/DisposeInActionEventTest/DisposeInActionEventTest.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -/* - test - @bug 6299866 - @summary Tests that no NPE is thrown when the tray icon is disposed from the - handler of action event caused by clicking on this icon. - @library ../../regtesthelpers - @build Sysout - @author artem.ananiev: area=awt.tray - @run applet/manual=yesno DisposeInActionEventTest.html -*/ - -import java.applet.*; - -import java.awt.*; -import java.awt.image.*; - -import jdk.test.lib.Platform; -import test.java.awt.regtesthelpers.Sysout; - -public class DisposeInActionEventTest extends Applet { - private boolean traySupported; - - private SystemTray systemTray; - private TrayIcon trayIcon; - - public void init() { - this.setLayout(new BorderLayout()); - - String[] instructions; - traySupported = SystemTray.isSupported(); - if (!traySupported) { - instructions = new String[]{ - "The test cannot be run because SystemTray is not supported.", - "Simply press PASS button." - }; - } else { - String clickInstruction; - if (Platform.isOSX()) { - clickInstruction = "right"; - } else { - clickInstruction = "left"; - } - instructions = new String[]{ - "When the test starts, it adds the icon to the tray aread. If you", - " don't see a tray icon, please, make sure that the tray area", - " (also called Taskbar Status Area on MS Windows, Notification", - " Area on Gnome or System Tray on KDE) is visible.", - "Double-click with " + clickInstruction + " button on the tray icon to trigger the", - " action event. Brief information about action events is printed", - " below. After each action event the tray icon is removed from", - " the tray and then added back in a second.", - "The test performs some automatic checks when removing the icon. If", - " something is wrong the corresponding message is displayed below.", - " Repeat double-clicks several times. If no 'Test FAILED' messages", - " are printed, press PASS button else FAIL button." - }; - } - Sysout.createDialogWithInstructions(instructions); - } - - @Override - public void start() { - setSize(200, 200); - setVisible(true); - validate(); - - if (!traySupported) return; - - System.setProperty("sun.awt.exception.handler", "DisposeInActionEventTest$EDTExceptionHandler"); - - BufferedImage img = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - Graphics g = img.createGraphics(); - g.setColor(Color.WHITE); - g.fillRect(0, 0, 32, 32); - g.setColor(Color.RED); - g.fillRect(6, 6, 20, 20); - g.dispose(); - - systemTray = SystemTray.getSystemTray(); - trayIcon = new TrayIcon(img); - trayIcon.setImageAutoSize(true); - trayIcon.addActionListener(ev -> { - Sysout.println(ev.toString()); - systemTray.remove(trayIcon); - new Thread(() -> { - try { - Thread.sleep(1000); - systemTray.add(trayIcon); - } catch (AWTException | InterruptedException e) { - Sysout.println(e.toString()); - Sysout.println("!!! The test coudn't be performed !!!"); - } - } - ).start(); - } - ); - - try { - systemTray.add(trayIcon); - } catch (AWTException e) { - Sysout.println(e.toString()); - Sysout.println("!!! The test coudn't be performed !!!"); - } - } -} diff --git a/test/jdk/java/awt/TrayIcon/ShowAfterDisposeTest/ShowAfterDisposeTest.java b/test/jdk/java/awt/TrayIcon/ShowAfterDisposeTest/ShowAfterDisposeTest.java index 7b1d917c710..cfa01be92b3 100644 --- a/test/jdk/java/awt/TrayIcon/ShowAfterDisposeTest/ShowAfterDisposeTest.java +++ b/test/jdk/java/awt/TrayIcon/ShowAfterDisposeTest/ShowAfterDisposeTest.java @@ -21,15 +21,6 @@ * questions. */ -/* - * @test - * @bug 6384984 8004032 - * @library ../../regtesthelpers /test/lib - * @build PassFailJFrame jtreg.SkippedException - * @summary TrayIcon try to dispay a tooltip when is not visible - * @run main/manual ShowAfterDisposeTest -*/ - import java.awt.AWTException; import java.awt.BorderLayout; import java.awt.Color; @@ -42,7 +33,18 @@ import javax.swing.JFrame; import javax.swing.SwingUtilities; +/* + * @test + * @bug 6384984 8004032 8316931 + * @library ../../regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @summary TrayIcon try to dispay a tooltip when is not visible + * @run main/manual ShowAfterDisposeTest + */ public class ShowAfterDisposeTest { + private static SystemTray tray; + private static TrayIcon icon; + public static void main(String[] args) throws Exception { if (!SystemTray.isSupported()) { throw new jtreg.SkippedException("The test cannot be run because SystemTray is not supported."); @@ -64,15 +66,21 @@ public void startTest() throws Exception { "3) If the bug is reproducible then the test will fail without assistance.\n" + "4) Just press the 'pass' button."; - PassFailJFrame.builder() - .title("Test Instructions Frame") - .instructions(instructions) - .testTimeOut(10) - .rows(10) - .columns(45) - .testUI(ShowAfterDisposeTest::showFrameAndIcon) - .build() - .awaitAndCheck(); + try { + PassFailJFrame.builder() + .title("Test Instructions Frame") + .instructions(instructions) + .testTimeOut(10) + .rows(10) + .columns(45) + .testUI(ShowAfterDisposeTest::showFrameAndIcon) + .build() + .awaitAndCheck(); + } finally { + if (tray != null) { + tray.remove(icon); + } + } } private static JFrame showFrameAndIcon() { @@ -87,8 +95,8 @@ private static JFrame showFrameAndIcon() { g.fillRect(6, 6, 20, 20); g.dispose(); - final SystemTray tray = SystemTray.getSystemTray(); - final TrayIcon icon = new TrayIcon(img); + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(img); icon.setImageAutoSize(true); icon.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { diff --git a/test/jdk/java/foreign/CallGeneratorHelper.java b/test/jdk/java/foreign/CallGeneratorHelper.java index ee3930a56e7..132a89b75f1 100644 --- a/test/jdk/java/foreign/CallGeneratorHelper.java +++ b/test/jdk/java/foreign/CallGeneratorHelper.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 @@ -213,11 +213,7 @@ public static void main(String[] args) { static void generateDowncalls(boolean header) { if (header) { System.out.println( - "#ifdef _WIN64\n" + - "#define EXPORT __declspec(dllexport)\n" + - "#else\n" + - "#define EXPORT\n" + - "#endif\n" + "#include \"export.h\"\n" ); for (int j = 1; j <= MAX_FIELDS; j++) { @@ -267,11 +263,7 @@ static void generateDowncallFunction(String fName, Ret ret, List para static void generateUpcalls(boolean header) { if (header) { System.out.println( - "#ifdef _WIN64\n" + - "#define EXPORT __declspec(dllexport)\n" + - "#else\n" + - "#define EXPORT\n" + - "#endif\n" + "#include \"export.h\"\n" ); for (int j = 1; j <= MAX_FIELDS; j++) { diff --git a/test/jdk/java/foreign/arraystructs/libArrayStructs.c b/test/jdk/java/foreign/arraystructs/libArrayStructs.c index 28ab57093f5..7adf79551ec 100644 --- a/test/jdk/java/foreign/arraystructs/libArrayStructs.c +++ b/test/jdk/java/foreign/arraystructs/libArrayStructs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" struct S1 { char f0[1]; }; struct S2 { char f0[2]; }; diff --git a/test/jdk/java/foreign/capturecallstate/libCaptureCallState.c b/test/jdk/java/foreign/capturecallstate/libCaptureCallState.c index 9a8925474a2..d76c9d7beda 100644 --- a/test/jdk/java/foreign/capturecallstate/libCaptureCallState.c +++ b/test/jdk/java/foreign/capturecallstate/libCaptureCallState.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 @@ -23,11 +23,7 @@ #include -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT void set_errno_V(int value) { errno = value; diff --git a/test/jdk/java/foreign/critical/libCritical.c b/test/jdk/java/foreign/critical/libCritical.c index 52bfa60677a..cc03db3c43c 100644 --- a/test/jdk/java/foreign/critical/libCritical.c +++ b/test/jdk/java/foreign/critical/libCritical.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -23,11 +23,7 @@ #include -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT void empty() {} diff --git a/test/jdk/java/foreign/dontrelease/libDontRelease.c b/test/jdk/java/foreign/dontrelease/libDontRelease.c index c7a8f743083..bcaeb6aaa70 100644 --- a/test/jdk/java/foreign/dontrelease/libDontRelease.c +++ b/test/jdk/java/foreign/dontrelease/libDontRelease.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 @@ -21,10 +21,6 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT void test_ptr(void* ptr) {} diff --git a/test/jdk/java/foreign/libAddressDereference.c b/test/jdk/java/foreign/libAddressDereference.c index b78b3d02f3e..d18d60e624e 100644 --- a/test/jdk/java/foreign/libAddressDereference.c +++ b/test/jdk/java/foreign/libAddressDereference.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -22,11 +22,7 @@ * */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT void* get_addr(void* align) { return align; diff --git a/test/jdk/java/foreign/libIntrinsics.c b/test/jdk/java/foreign/libIntrinsics.c index 89d0a09c7b6..b52d2756fba 100644 --- a/test/jdk/java/foreign/libIntrinsics.c +++ b/test/jdk/java/foreign/libIntrinsics.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 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 @@ -24,11 +24,7 @@ #include -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT void empty() { } @@ -85,4 +81,4 @@ EXPORT short invoke_high_arity5(int x, double d, long long l, float f, char c, s } EXPORT short invoke_high_arity6(int x, double d, long long l, float f, char c, short s1, short s2) { return s2; -} \ No newline at end of file +} diff --git a/test/jdk/java/foreign/libLibraryLookup.c b/test/jdk/java/foreign/libLibraryLookup.c index 13719ad9ba8..dd575f52b96 100644 --- a/test/jdk/java/foreign/libLibraryLookup.c +++ b/test/jdk/java/foreign/libLibraryLookup.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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" int count = 0; diff --git a/test/jdk/java/foreign/libLookupTest.c b/test/jdk/java/foreign/libLookupTest.c index d78b46528a1..055cae5e23e 100644 --- a/test/jdk/java/foreign/libLookupTest.c +++ b/test/jdk/java/foreign/libLookupTest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 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 @@ -21,12 +21,7 @@ * questions. */ - #ifdef _WIN64 - #define EXPORT __declspec(dllexport) - #else - #define EXPORT - #endif - - EXPORT void f() { } - EXPORT int c = 42; +#include "export.h" +EXPORT void f() { } +EXPORT int c = 42; diff --git a/test/jdk/java/foreign/libNull.c b/test/jdk/java/foreign/libNull.c index 52ea8493f21..a93c8d776f1 100644 --- a/test/jdk/java/foreign/libNull.c +++ b/test/jdk/java/foreign/libNull.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, 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 @@ -21,12 +21,8 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif - #include +#include "export.h" + EXPORT void* get_null() { return NULL; } diff --git a/test/jdk/java/foreign/libSafeAccess.c b/test/jdk/java/foreign/libSafeAccess.c index 4b44e24054d..f7a0bdb4554 100644 --- a/test/jdk/java/foreign/libSafeAccess.c +++ b/test/jdk/java/foreign/libSafeAccess.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" struct Point { int x; diff --git a/test/jdk/java/foreign/libTestUpcallHighArity.c b/test/jdk/java/foreign/libTestUpcallHighArity.c index 052bd2ce168..cd6b6de4e32 100644 --- a/test/jdk/java/foreign/libTestUpcallHighArity.c +++ b/test/jdk/java/foreign/libTestUpcallHighArity.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" struct S_PDI { void* p0; double p1; int p2; }; diff --git a/test/jdk/java/foreign/libTestUpcallStructScope.c b/test/jdk/java/foreign/libTestUpcallStructScope.c index e27ab0092cc..e778133b496 100644 --- a/test/jdk/java/foreign/libTestUpcallStructScope.c +++ b/test/jdk/java/foreign/libTestUpcallStructScope.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" struct S_PDI { void* p0; double p1; int p2; }; diff --git a/test/jdk/java/foreign/loaderLookup/lookup/libFoo.c b/test/jdk/java/foreign/loaderLookup/lookup/libFoo.c index 68525215b93..d9f07bcfd3a 100644 --- a/test/jdk/java/foreign/loaderLookup/lookup/libFoo.c +++ b/test/jdk/java/foreign/loaderLookup/lookup/libFoo.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 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 @@ -23,11 +23,7 @@ #include -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT void foo(void) { // do nothing diff --git a/test/jdk/java/foreign/nested/libNested.c b/test/jdk/java/foreign/nested/libNested.c index c31fb0dc4cc..39becbb9831 100644 --- a/test/jdk/java/foreign/nested/libNested.c +++ b/test/jdk/java/foreign/nested/libNested.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -21,11 +21,8 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" + #ifdef _AIX #pragma align (natural) #endif diff --git a/test/jdk/java/foreign/normalize/libNormalize.c b/test/jdk/java/foreign/normalize/libNormalize.c index 4a21551278f..68c352d8e86 100644 --- a/test/jdk/java/foreign/normalize/libNormalize.c +++ b/test/jdk/java/foreign/normalize/libNormalize.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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" // we use 'int' here to make sure the native code doesn't touch any of the bits // the important part is that our Java code performs argument normalization diff --git a/test/jdk/java/foreign/passheapsegment/libPassHeapSegment.c b/test/jdk/java/foreign/passheapsegment/libPassHeapSegment.c index fdb1981ac65..850c2db8be9 100644 --- a/test/jdk/java/foreign/passheapsegment/libPassHeapSegment.c +++ b/test/jdk/java/foreign/passheapsegment/libPassHeapSegment.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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT void test_args(void* ptr) {} diff --git a/test/jdk/java/foreign/shared.h b/test/jdk/java/foreign/shared.h index 0f6183891a7..72093a0d04d 100644 --- a/test/jdk/java/foreign/shared.h +++ b/test/jdk/java/foreign/shared.h @@ -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 @@ -21,6 +21,8 @@ * questions. */ +#include "export.h" + #ifdef __clang__ #pragma clang optimize off #elif defined __GNUC__ @@ -29,11 +31,6 @@ #pragma optimize( "", off ) #endif -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif #ifdef _AIX #pragma align (natural) #endif diff --git a/test/jdk/java/foreign/stackwalk/libAsyncStackWalk.cpp b/test/jdk/java/foreign/stackwalk/libAsyncStackWalk.cpp index 5461966d055..afde7678869 100644 --- a/test/jdk/java/foreign/stackwalk/libAsyncStackWalk.cpp +++ b/test/jdk/java/foreign/stackwalk/libAsyncStackWalk.cpp @@ -21,14 +21,9 @@ * questions. */ +#include "export.h" #include "testlib_threads.hpp" -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif - typedef void (*CB_t)(void); static void start(void* ctxt) { diff --git a/test/jdk/java/foreign/stackwalk/libReentrantUpcalls.c b/test/jdk/java/foreign/stackwalk/libReentrantUpcalls.c index 3dd8ac07d9b..250c31256c6 100644 --- a/test/jdk/java/foreign/stackwalk/libReentrantUpcalls.c +++ b/test/jdk/java/foreign/stackwalk/libReentrantUpcalls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT void do_recurse(int depth, void (*cb)(int, void*)) { cb(depth, cb); diff --git a/test/jdk/java/foreign/stackwalk/libStackWalk.c b/test/jdk/java/foreign/stackwalk/libStackWalk.c index 19d3f5e3d45..b2b03b50738 100644 --- a/test/jdk/java/foreign/stackwalk/libStackWalk.c +++ b/test/jdk/java/foreign/stackwalk/libStackWalk.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT void foo(void (*cb)(void)) { cb(); diff --git a/test/jdk/java/foreign/upcalldeopt/libUpcallDeopt.c b/test/jdk/java/foreign/upcalldeopt/libUpcallDeopt.c index ae2a8dc0173..c51dbc937ac 100644 --- a/test/jdk/java/foreign/upcalldeopt/libUpcallDeopt.c +++ b/test/jdk/java/foreign/upcalldeopt/libUpcallDeopt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT void foo(void (*cb)(int, int, int, int), int a0, int a1, int a2, int a3) { cb(a0, a1, a2, a3); diff --git a/test/jdk/java/foreign/virtual/libVirtual.c b/test/jdk/java/foreign/virtual/libVirtual.c index 86c4c737a94..7f7961da408 100644 --- a/test/jdk/java/foreign/virtual/libVirtual.c +++ b/test/jdk/java/foreign/virtual/libVirtual.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 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 @@ -22,11 +22,7 @@ * */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT int funcA() { return 1; diff --git a/test/jdk/java/lang/Math/WorstCaseTests.java b/test/jdk/java/lang/Math/WorstCaseTests.java index 32e39479b4b..a479c6a3444 100644 --- a/test/jdk/java/lang/Math/WorstCaseTests.java +++ b/test/jdk/java/lang/Math/WorstCaseTests.java @@ -89,9 +89,11 @@ public static void main(String... args) { failures += testWorstAcos(); failures += testWorstTan(); failures += testWorstAtan(); + failures += testWorstAtan2(); failures += testWorstPow2(); failures += testWorstSinh(); failures += testWorstCosh(); + failures += testWorstHypot(); if (failures > 0) { System.err.printf("Testing worst cases incurred %d failures.%n", failures); @@ -481,6 +483,32 @@ private static int testAtanCase(double input, double expected) { return failures; } + /* + * 2 ulp stated error bound + */ + private static int testWorstAtan2() { + int failures = 0; + double [][] testCases = { + // Input with large worst-case observed error for another math library + {-0x0.00000000039a2p-1022, 0x0.000fdf02p-1022, -0x1.d0ce6fac85de8p-27}, + }; + + for(double[] testCase: testCases) { + failures += testAtan2Case(testCase[0], testCase[1], testCase[2]); + } + + return failures; + } + + private static int testAtan2Case(double input1, double input2, double expected) { + int failures = 0; + // Cannot represent exact result, allow 1 additional ulp on top of documented bound. + double ulps = 2.0 + 1.0; + failures += Tests.testUlpDiff("Math.atan2", input1, input2, Math::atan2, expected, ulps); + failures += Tests.testUlpDiff("StrictMath.atan2", input1, input2, StrictMath::atan2, expected, ulps); + return failures; + } + /* * 1 ulp stated error bound */ @@ -570,4 +598,30 @@ private static int testCoshCase(double input, double expected) { failures += Tests.testBounds("StrictMath.cosh", input, StrictMath::cosh, expected, out); return failures; } + + /* + * 1.5 ulp stated error bound + */ + private static int testWorstHypot() { + int failures = 0; + double [][] testCases = { + // Input with large worst-case observed error for another math library + {-0x0.fffffffffffffp-1022, 0x0.0000000000001p-1022, 0x0.fffffffffffffp-1022}, + }; + + for(double[] testCase: testCases) { + failures += testHypotCase(testCase[0], testCase[1], testCase[2]); + } + + return failures; + } + + private static int testHypotCase(double input1, double input2, double expected) { + int failures = 0; + // Cannot represent exact result, allow 1 additional ulp on top of documented bound, rounding up. + double ulps = 3.0; // 1.5 + 1.0, rounded up + failures += Tests.testUlpDiff("Math.hypot", input1, input2, Math::hypot, expected, ulps); + failures += Tests.testUlpDiff("StrictMath.hypot", input1, input2, StrictMath::hypot, expected, ulps); + return failures; + } } diff --git a/test/jdk/java/lang/ProcessBuilder/JspawnhelperWarnings.java b/test/jdk/java/lang/ProcessBuilder/JspawnhelperWarnings.java new file mode 100644 index 00000000000..0ff68186502 --- /dev/null +++ b/test/jdk/java/lang/ProcessBuilder/JspawnhelperWarnings.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8325567 + * @requires (os.family == "linux") | (os.family == "aix") | (os.family == "mac") + * @library /test/lib + * @run driver JspawnhelperWarnings + */ + +import java.nio.file.Paths; +import java.util.Arrays; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class JspawnhelperWarnings { + + private static void tryWithNArgs(int nArgs) throws Exception { + System.out.println("Running jspawnhelper with " + nArgs + " args"); + String[] args = new String[nArgs + 1]; + Arrays.fill(args, "1"); + args[0] = Paths.get(System.getProperty("java.home"), "lib", "jspawnhelper").toString(); + Process p = ProcessTools.startProcess("jspawnhelper", new ProcessBuilder(args)); + OutputAnalyzer oa = new OutputAnalyzer(p); + oa.shouldHaveExitValue(1); + oa.shouldContain("This command is not for general use"); + } + + public static void main(String[] args) throws Exception { + for (int nArgs = 0; nArgs < 10; nArgs++) { + tryWithNArgs(nArgs); + } + } +} diff --git a/test/jdk/java/lang/Thread/jni/AttachCurrentThread/libImplicitAttach.c b/test/jdk/java/lang/Thread/jni/AttachCurrentThread/libImplicitAttach.c index a3dcb6ac050..ade58ccb7c0 100644 --- a/test/jdk/java/lang/Thread/jni/AttachCurrentThread/libImplicitAttach.c +++ b/test/jdk/java/lang/Thread/jni/AttachCurrentThread/libImplicitAttach.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 @@ -20,15 +20,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -#include + #include +#include + +#include "export.h" #define STACK_SIZE 0x100000 /** * Creates n threads to execute the given function. */ -void start_threads(int n, void *(*f)(void *)) { +EXPORT void start_threads(int n, void *(*f)(void *)) { pthread_t tid; pthread_attr_t attr; int i; diff --git a/test/jdk/java/net/httpclient/ManyRequests.java b/test/jdk/java/net/httpclient/ManyRequests.java index 8e3eb7eba94..89f26d3a761 100644 --- a/test/jdk/java/net/httpclient/ManyRequests.java +++ b/test/jdk/java/net/httpclient/ManyRequests.java @@ -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 @@ -187,7 +187,7 @@ static void test(HttpsServer server, HttpClient client) throws Exception { URI baseURI = URIBuilder.newBuilder() .scheme("https") - .host(InetAddress.getLoopbackAddress().getHostName()) + .loopback() .port(port) .path("/foo/x").build(); server.createContext("/foo", new TestEchoHandler()); diff --git a/test/jdk/java/nio/channels/FileChannel/Size.java b/test/jdk/java/nio/channels/FileChannel/Size.java index fd6e744f03f..2db86a8089e 100644 --- a/test/jdk/java/nio/channels/FileChannel/Size.java +++ b/test/jdk/java/nio/channels/FileChannel/Size.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, 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 @@ -24,6 +24,7 @@ /* @test * @bug 4563125 * @summary Test size method of FileChannel + * @library /test/lib * @run main/othervm Size * @key randomness */ @@ -31,8 +32,10 @@ import java.io.*; import java.nio.MappedByteBuffer; import java.nio.channels.*; +import java.nio.file.FileStore; +import java.nio.file.Path; import java.util.Random; - +import jtreg.SkippedException; /** * Testing FileChannel's size method. @@ -65,6 +68,8 @@ private static void testSmallFile() throws Exception { // Test for bug 4563125 private static void testLargeFile() throws Exception { File largeFile = new File("largeFileTest"); + largeFile.deleteOnExit(); + long testSize = ((long)Integer.MAX_VALUE) * 2; initTestFile(largeFile, 10); try (FileChannel fc = new RandomAccessFile(largeFile, "rw").getChannel()) { @@ -75,8 +80,15 @@ private static void testLargeFile() throws Exception { + "Expect size " + (testSize + 10) + ", actual size " + fc.size()); } + } catch (IOException ioe) { + if ("File too large".equals(ioe.getMessage())) { + Path p = largeFile.toPath(); + FileStore store = p.getFileSystem().provider().getFileStore(p); + if ("msdos".equals(store.type())) + throw new SkippedException("file too big for FAT32"); + } + throw ioe; } - largeFile.deleteOnExit(); } /** diff --git a/test/jdk/java/security/testlibrary/CertificateBuilder.java b/test/jdk/java/security/testlibrary/CertificateBuilder.java index df485b06e0c..e1b1211a9d5 100644 --- a/test/jdk/java/security/testlibrary/CertificateBuilder.java +++ b/test/jdk/java/security/testlibrary/CertificateBuilder.java @@ -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 @@ -30,6 +30,8 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.Extension; +import java.time.temporal.ChronoUnit; +import java.time.Instant; import javax.security.auth.x500.X500Principal; import java.math.BigInteger; @@ -43,6 +45,7 @@ import sun.security.x509.AuthorityKeyIdentifierExtension; import sun.security.x509.SubjectKeyIdentifierExtension; import sun.security.x509.BasicConstraintsExtension; +import sun.security.x509.CertificateSerialNumber; import sun.security.x509.ExtendedKeyUsageExtension; import sun.security.x509.DNSName; import sun.security.x509.GeneralName; @@ -499,7 +502,9 @@ private byte[] encodeTbsCert(X509Certificate issuerCert, } // Serial Number - SerialNumber sn = new SerialNumber(serialNumber); + CertificateSerialNumber sn = (serialNumber != null) ? + new CertificateSerialNumber(serialNumber) : + CertificateSerialNumber.newRandom64bit(new SecureRandom()); sn.encode(tbsCertItems); // Algorithm ID @@ -516,8 +521,12 @@ private byte[] encodeTbsCert(X509Certificate issuerCert, // Validity period (set as UTCTime) DerOutputStream valSeq = new DerOutputStream(); - valSeq.putUTCTime(notBefore); - valSeq.putUTCTime(notAfter); + Instant now = Instant.now(); + Date startDate = (notBefore != null) ? notBefore : Date.from(now); + valSeq.putUTCTime(startDate); + Date endDate = (notAfter != null) ? notAfter : + Date.from(now.plus(90, ChronoUnit.DAYS)); + valSeq.putUTCTime(endDate); tbsCertItems.write(DerValue.tag_Sequence, valSeq); // Subject Name @@ -557,6 +566,10 @@ private byte[] encodeTbsCert(X509Certificate issuerCert, */ private void encodeExtensions(DerOutputStream tbsStream) throws IOException { + + if (extensions.isEmpty()) { + return; + } DerOutputStream extSequence = new DerOutputStream(); DerOutputStream extItems = new DerOutputStream(); diff --git a/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java b/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java index 6d8ab9c9a0c..664f3fdd951 100644 --- a/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java +++ b/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java @@ -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 @@ -23,25 +23,27 @@ /* * @test - * @bug 8282929 - * @summary Verifies that toLocalizedPattern() method correctly returns - * monetary symbols in a currency formatter - * @run testng ToLocalizedPatternTest + * @bug 8282929 8326908 + * @summary Verify DecimalFormat::toLocalizedPattern correctness. + * @run junit ToLocalizedPatternTest */ -import static org.testng.Assert.assertEquals; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; -@Test public class ToLocalizedPatternTest { private static final char MONETARY_GROUPING = 'g'; private static final char MONETARY_DECIMAL = 'd'; - public void testToLocalizedPattern() { + // Verifies that the toLocalizedPattern() method correctly returns + // monetary symbols for a currency formatter. + @Test + public void monetarySymbolsTest() { var dfs = new DecimalFormatSymbols(Locale.US); // Customize the decimal format symbols @@ -58,4 +60,17 @@ public void testToLocalizedPattern() { .replace(',', MONETARY_GROUPING) .replace('.', MONETARY_DECIMAL)); } + + // Verify some common symbols are enforced with the DFS + @Test + public void useDFSWhenLocalizedTest() { + DecimalFormatSymbols dfs = new DecimalFormatSymbols(); + dfs.setGroupingSeparator('a'); + dfs.setDecimalSeparator('b'); + dfs.setDigit('c'); + dfs.setZeroDigit('d'); + // Create a DecimalFormat that utilizes the above symbols + DecimalFormat dFmt = new DecimalFormat("###,##0.###", dfs); + assertEquals("caccdbccc", dFmt.toLocalizedPattern()); + } } diff --git a/test/jdk/java/text/Format/DecimalFormat/ToPatternTest.java b/test/jdk/java/text/Format/DecimalFormat/ToPatternTest.java new file mode 100644 index 00000000000..c9749c09326 --- /dev/null +++ b/test/jdk/java/text/Format/DecimalFormat/ToPatternTest.java @@ -0,0 +1,130 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 8326908 + * @summary Verify DecimalFormat::toPattern correctness. + * @run junit ToPatternTest + */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.text.DecimalFormat; +import java.util.stream.Stream; + +public class ToPatternTest { + + // DecimalFormat constant + private static final int DOUBLE_FRACTION_DIGITS = 340; + + // Ensure that toPattern() provides the correct amount of minimum + // and maximum digits for integer/fraction. + @ParameterizedTest + @MethodSource("minMaxDigits") + public void basicTest(int maxInt, int minInt, int maxFrac, int minFrac) { + DecimalFormat dFmt = new DecimalFormat(); + + dFmt.setMaximumIntegerDigits(maxInt); + dFmt.setMinimumIntegerDigits(minInt); + dFmt.setMaximumFractionDigits(maxFrac); + dFmt.setMinimumFractionDigits(minFrac); + + // Non-localized separator always uses '.' + String[] patterns = dFmt.toPattern().split("\\."); + assertEquals(2, patterns.length, + dFmt.toPattern() + " should be split into an integer/fraction portion"); + String integerPattern = patterns[0]; + String fractionPattern = patterns[1]; + + // Count # and 0 explicitly (since there are grouping symbols) + assertEquals(integerPattern.chars().filter(ch -> ch == '0').count() + + integerPattern.chars().filter(ch -> ch == '#').count(), + Math.max(dFmt.getGroupingSize(), dFmt.getMinimumIntegerDigits()) + 1); + assertEquals(integerPattern.chars().filter(ch -> ch == '0').count(), dFmt.getMinimumIntegerDigits()); + assertEquals(fractionPattern.length(), dFmt.getMaximumFractionDigits()); + assertEquals(fractionPattern.chars().filter(ch -> ch == '0').count(), dFmt.getMinimumFractionDigits()); + } + + // General and edge cases for the min and max Integer/Fraction digits + private static Stream minMaxDigits() { + return Stream.of( + Arguments.of(10, 5, 10, 5), + Arguments.of(0, 0, 1, 1), + Arguments.of(1, 1, 1, 1), + Arguments.of(5, 5, 5, 5), + Arguments.of(5, 10, 5, 10), + Arguments.of(333, 27, 409, 3) + ); + } + + // Ensure that a NegativePattern is explicitly produced when required. + @Test + public void negativeSubPatternTest() { + DecimalFormat dFmt = new DecimalFormat(); + dFmt.setPositivePrefix("foo"); + dFmt.setPositiveSuffix("bar"); + dFmt.setNegativePrefix("baz"); + dFmt.setNegativeSuffix("qux"); + + String[] patterns = dFmt.toPattern().split(";"); + assertEquals(2, patterns.length, + "There should be a positivePattern and negativePattern"); + String positivePattern = patterns[0]; + String negativePattern = patterns[1]; + + assertTrue(positivePattern.startsWith(dFmt.getPositivePrefix())); + assertTrue(positivePattern.endsWith(dFmt.getPositiveSuffix())); + assertTrue(negativePattern.startsWith(dFmt.getNegativePrefix())); + assertTrue(negativePattern.endsWith(dFmt.getNegativeSuffix())); + } + + // 8326908: Verify that an empty pattern DecimalFormat does not throw an + // OutOfMemoryError when toPattern() is invoked. Behavioral change of + // MAXIMUM_INTEGER_DIGITS replaced with DOUBLE_FRACTION_DIGITS for empty + // pattern initialization. + @Test + public void emptyStringPatternTest() { + DecimalFormat empty = new DecimalFormat(""); + // Verify new maximum fraction digits value + assertEquals(DOUBLE_FRACTION_DIGITS, empty.getMaximumFractionDigits()); + // Verify no OOME for empty pattern + assertDoesNotThrow(empty::toPattern); + // Check toString for coverage, as it invokes toPattern + assertDoesNotThrow(empty::toString); + } + + // Verify that only the last grouping interval is used for the grouping size. + @Test + public void groupingSizeTest() { + assertEquals(22, + new DecimalFormat( "###,####,"+"#".repeat(22)).getGroupingSize()); + } +} diff --git a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java index d0141b304a8..04a6e89db7b 100644 --- a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java +++ b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.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 @@ -25,8 +25,9 @@ * @test * @bug 8025703 8040211 8191404 8203872 8222980 8225435 8241082 8242010 8247432 * 8258795 8267038 8287180 8302512 8304761 8306031 8308021 8313702 8318322 + * 8327631 * @summary Checks the IANA language subtag registry data update - * (LSR Revision: 2023-10-16) with Locale and Locale.LanguageRange + * (LSR Revision: 2024-03-07) with Locale and Locale.LanguageRange * class methods. * @run main LanguageSubtagRegistryTest */ diff --git a/test/jdk/java/util/Properties/PropertiesStoreTest.java b/test/jdk/java/util/Properties/PropertiesStoreTest.java index ab58ea78903..b5a5b5a45aa 100644 --- a/test/jdk/java/util/Properties/PropertiesStoreTest.java +++ b/test/jdk/java/util/Properties/PropertiesStoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, 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 @@ -55,9 +55,9 @@ public class PropertiesStoreTest { private static final String DATE_FORMAT_PATTERN = "EEE MMM dd HH:mm:ss zzz uuuu"; - // use a neutral locale, since when the date comment was written by Properties.store(...), - // it internally calls the Date.toString() which always writes in a locale insensitive manner - private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN, Locale.ROOT); + // use Locale.US, since when the date comment was written by Properties.store(...), + // it internally calls the Date.toString() which uses Locale.US for time zone names + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN, Locale.US); private static final Locale PREV_LOCALE = Locale.getDefault(); @DataProvider(name = "propsProvider") diff --git a/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java b/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java index 0f154f307f8..b6459b7b8f5 100644 --- a/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java +++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -45,57 +46,59 @@ public static void main(String[] args) throws Throwable { } static void executeTest() throws Throwable { - final ConcurrentHashMap m = new ConcurrentHashMap<>(); - final ThreadLocalRandom rnd = ThreadLocalRandom.current(); - final int nCPU = Runtime.getRuntime().availableProcessors(); - final int minWorkers = 2; - final int maxWorkers = Math.max(minWorkers, Math.min(32, nCPU)); - final int nWorkers = rnd.nextInt(minWorkers, maxWorkers + 1); - final int sizePerWorker = 1024; - final int maxSize = nWorkers * sizePerWorker; + try (var executor = Executors.newCachedThreadPool()) { + final ConcurrentHashMap m = new ConcurrentHashMap<>(); + final ThreadLocalRandom rnd = ThreadLocalRandom.current(); + final int nCPU = Runtime.getRuntime().availableProcessors(); + final int minWorkers = 2; + final int maxWorkers = Math.max(minWorkers, Math.min(32, nCPU)); + final int nWorkers = rnd.nextInt(minWorkers, maxWorkers + 1); + final int sizePerWorker = 1024; + final int maxSize = nWorkers * sizePerWorker; - // The foreman busy-checks that the size of the arrays obtained - // from the keys and values views grows monotonically until it - // reaches the maximum size. + // The foreman busy-checks that the size of the arrays obtained + // from the keys and values views grows monotonically until it + // reaches the maximum size. - // NOTE: these size constraints are not specific to toArray and are - // applicable to any form of traversal of the collection views - CompletableFuture foreman = CompletableFuture.runAsync(new Runnable() { - private int prevSize = 0; + // NOTE: these size constraints are not specific to toArray and are + // applicable to any form of traversal of the collection views + CompletableFuture foreman = CompletableFuture.runAsync(new Runnable() { + private int prevSize = 0; - private boolean checkProgress(Object[] a) { - int size = a.length; - if (size < prevSize || size > maxSize) - throw new AssertionError( - String.format("prevSize=%d size=%d maxSize=%d", - prevSize, size, maxSize)); - prevSize = size; - return size == maxSize; - } + private boolean checkProgress(Object[] a) { + int size = a.length; + if (size < prevSize || size > maxSize) + throw new AssertionError( + String.format("prevSize=%d size=%d maxSize=%d", + prevSize, size, maxSize)); + prevSize = size; + return size == maxSize; + } - public void run() { - Integer[] empty = new Integer[0]; - for (;;) - if (checkProgress(m.values().toArray()) - & checkProgress(m.keySet().toArray()) - & checkProgress(m.values().toArray(empty)) - & checkProgress(m.keySet().toArray(empty))) - return; - } - }); + public void run() { + Integer[] empty = new Integer[0]; + for (; ; ) + if (checkProgress(m.values().toArray()) + & checkProgress(m.keySet().toArray()) + & checkProgress(m.values().toArray(empty)) + & checkProgress(m.keySet().toArray(empty))) + return; + } + }, executor); - // Each worker puts globally unique keys into the map - List> workers = - IntStream.range(0, nWorkers) - .mapToObj(w -> (Runnable) () -> { - for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++) - m.put(o + i, i); - }) - .map(CompletableFuture::runAsync) - .collect(Collectors.toList()); + // Each worker puts globally unique keys into the map + List> workers = + IntStream.range(0, nWorkers) + .mapToObj(w -> (Runnable) () -> { + for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++) + m.put(o + i, i); + }) + .map(r -> CompletableFuture.runAsync(r, executor)) + .collect(Collectors.toList()); - // Wait for workers and foreman to complete - workers.forEach(CompletableFuture::join); - foreman.join(); + // Wait for workers and foreman to complete + workers.forEach(CompletableFuture::join); + foreman.join(); + } } } diff --git a/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.html b/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.html deleted file mode 100644 index 077034e6547..00000000000 --- a/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -The test is suitable only for Windows - -1. Create a link -2. Copy path to the link into TextField -3. Run the Windows Task Manager. Select the Processes tab and find the java process -4. Press the Start button in the test window -5. Wait several minutes and observe in the Windows Task Manager -that Memory Usage of java process is not increasing - - diff --git a/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.java b/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.java index 2c32f5f2b5e..b3a313b3ca9 100644 --- a/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.java +++ b/test/jdk/javax/swing/JFileChooser/6798062/bug6798062.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, 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 @@ -21,54 +21,82 @@ * questions. */ -/* @test %W% %E% - @bug 6798062 - @summary Memory Leak on using getFiles of FileSystemView - @author Pavel Porvatov - @modules java.desktop/sun.awt - java.desktop/sun.awt.shell - @run applet/manual=done bug6798062.html -*/ +/* + * @test + * @bug 6798062 + * @requires (os.family == "windows") + * @summary Memory Leak on using getFiles of FileSystemView + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @modules java.desktop/sun.awt + * java.desktop/sun.awt.shell + * @run main/manual bug6798062 + */ import sun.awt.OSInfo; import sun.awt.shell.ShellFolder; -import javax.swing.*; +import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.*; import java.io.File; import java.io.FileNotFoundException; - -public class bug6798062 extends JApplet { - - private final JSlider slider = new JSlider(0, 100); - - private final JTextField tfLink = new JTextField(); - - private final JButton btnStart = new JButton("Start"); - - private final JButton btnStop = new JButton("Stop"); - - private final JButton btnGC = new JButton("Run System.gc()"); +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.JTextField; + +public class bug6798062 { + + private static final String INSTRUCTIONS = """ + The test is suitable only for Windows. + + 1. Create a shortcut (.lnk) file + 2. Copy path to the shortcut (.lnk file) into TextField + 3. Run the Windows Task Manager. Select the Processes tab and find the java process + 4. Press the Start button in the test window + 5. Wait several minutes and observe in the Windows Task Manager + that Memory Usage of java process is not increasing + If memory usage is increasing, click Fail else click Pass."""; + + private static JSlider slider; + private static JTextField tfLink; + private static JButton btnStart; + private static JButton btnStop; + private static JButton btnGC; private ShellFolder folder; - private Thread thread; - public static void main(String[] args) { + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JFileChooser Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(10) + .rows(10) + .columns(35) + .testUI(bug6798062::createUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + slider = new JSlider(0, 100); + tfLink = new JTextField(); + btnStart = new JButton("Start"); + btnStop = new JButton("Stop"); + btnGC = new JButton("Run System.gc()"); JFrame frame = new JFrame("bug6798062"); frame.setSize(400, 300); - frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new bug6798062().initialize()); - frame.setVisible(true); - } - - public void init() { - add(initialize()); + return frame; } private JComponent initialize() { @@ -87,7 +115,7 @@ private JComponent initialize() { try { folder = ShellFolder.getShellFolder(new File(tempDir)); } catch (FileNotFoundException e) { - fail("Directory " + tempDir + " not found"); + fail("Directory not found"); } slider.setMajorTickSpacing(10); @@ -153,7 +181,7 @@ private void setEnabledState(boolean enabled) { } private static void fail(String msg) { - throw new RuntimeException(msg); + PassFailJFrame.forceFail(msg); } private class MyThread extends Thread { @@ -169,7 +197,7 @@ private MyThread(int delay, String link) { try { linkFolder = ShellFolder.getShellFolder(new File(link)); } catch (FileNotFoundException e) { - e.printStackTrace(); + fail("File not found"); linkFolder = null; } @@ -184,7 +212,7 @@ public void run() { try { link.getLinkLocation(); } catch (FileNotFoundException e) { - e.printStackTrace(); + fail("File not found"); } } diff --git a/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.html b/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.html deleted file mode 100644 index 99133770bff..00000000000 --- a/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - -Follow the instructions below. -1) Check that current filter in the opened JFileChooser is a "CustomFileFilter". -2) Close the JFileChooser. -3) Test will repeat steps 1 - 2 for all supported look and feels. -4) If it's true for all look and feels then the test passed, otherwise it failed. - - diff --git a/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.java b/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.java index 2bca535fe8d..9da801d6af7 100644 --- a/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.java +++ b/test/jdk/javax/swing/JFileChooser/FileFilterDescription/FileFilterDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 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 @@ -21,44 +21,57 @@ * questions. */ -import java.applet.Applet; import java.io.File; - +import java.awt.BorderLayout; import javax.swing.JFileChooser; +import javax.swing.JFrame; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.filechooser.FileFilter; -public final class FileFilterDescription extends Applet { +/* + * @test + * @bug 8029536 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FileFilterDescription + */ +public final class FileFilterDescription { - @Override - public void init() { - } - - @Override - public void start() { - try { - test(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } + private static final String INSTRUCTIONS = """ + 1) Check that current filter in the opened JFileChooser is a "CustomFileFilter". + 2) Close the JFileChooser. + 3) Test will repeat steps 1 - 2 for all supported look and feels. + 4) If it's true for all look and feels then click Pass else click Fail. """; + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .title("JFileChooser Filefilter Instructions") + .instructions(INSTRUCTIONS) + .rows(10) + .columns(35) + .position(PassFailJFrame.Position.TOP_LEFT_CORNER) + .build(); - public static void test() throws Exception { final UIManager.LookAndFeelInfo[] infos = UIManager .getInstalledLookAndFeels(); for (final UIManager.LookAndFeelInfo info : infos) { SwingUtilities.invokeAndWait(() -> { - final JFileChooser chooser = new JFileChooser(); setLookAndFeel(info); + JFrame frame = new JFrame("JFileChooser FileFilter test"); + final JFileChooser chooser = new JFileChooser(); chooser.setAcceptAllFileFilterUsed(false); chooser.setFileFilter(new CustomFileFilter()); SwingUtilities.updateComponentTreeUI(chooser); + frame.add(chooser, BorderLayout.CENTER); + frame.pack(); + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, PassFailJFrame.Position.TOP_LEFT_CORNER); chooser.showDialog(null, "Open"); }); } + passFailJFrame.awaitAndCheck(); } private static void setLookAndFeel(final UIManager.LookAndFeelInfo info) { diff --git a/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.html b/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.html deleted file mode 100644 index 0db8864e8d8..00000000000 --- a/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Drag the internal frame inside the green undecorated window, -if you can drag it the test passes, otherwise fails. - - diff --git a/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.java b/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.java index d56f10d39ef..88b890d7b2c 100644 --- a/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.java +++ b/test/jdk/javax/swing/JInternalFrame/6726866/bug6726866.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2017, 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 @@ -21,11 +21,14 @@ * questions. */ -/* @test - @bug 6726866 8186617 - @summary Repainting artifacts when resizing or dragging JInternalFrames in +/* + * @test + * @bug 6726866 8186617 + * @summary Repainting artifacts when resizing or dragging JInternalFrames in non-opaque toplevel - @run applet/manual=yesno bug6726866.html + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug6726866 */ import java.awt.Color; @@ -36,10 +39,26 @@ import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLabel; +import javax.swing.SwingUtilities; + +public class bug6726866 { -public class bug6726866 extends JApplet { + private static final String INSTRUCTIONS = """ + Drag the internal frame inside the green undecorated window, + if you can drag it the test passes, otherwise fails. """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JInternalFrame Instructions") + .instructions(INSTRUCTIONS) + .rows(5) + .columns(35) + .testUI(bug6726866::createUI) + .build() + .awaitAndCheck(); + } - public void init() { + private static JFrame createUI() { JFrame frame = new JFrame("bug6726866"); frame.setUndecorated(true); setWindowNonOpaque(frame); @@ -53,10 +72,8 @@ public void init() { desktop.add(iFrame); frame.add(desktop); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(400, 400); - frame.setVisible(true); - frame.toFront(); + return frame; } public static void setWindowNonOpaque(Window window) { diff --git a/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.html b/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.html deleted file mode 100644 index ca7bac5dac5..00000000000 --- a/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - Message Dialog should pop up - with a button font size 10 - and message font size 24. - - It should be true even on OS X. - If it is not so press "Fail" else press "Pass". - - - - - diff --git a/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.java b/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.java deleted file mode 100644 index fd20840867a..00000000000 --- a/test/jdk/javax/swing/JOptionPane/4174551/bug4174551.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 4174551 - * @summary JOptionPane should allow custom buttons - * @author Xhipra Tyagi(xhipra.tyagi@india.sun.com) area=Swing - * @run applet/manual=yesno bug4174551.html - */ -import java.awt.Font; -import javax.swing.JApplet; -import javax.swing.UIManager; -import javax.swing.JOptionPane; - -public class bug4174551 extends JApplet { - - public void init() { - try { - java.awt.EventQueue.invokeLater( () -> { - UIManager.getDefaults().put("OptionPane.buttonFont", new Font("Dialog", Font.PLAIN, 10)); - UIManager.getDefaults().put("OptionPane.messageFont", new Font("Dialog", Font.PLAIN, 24)); - JOptionPane.showMessageDialog(null, "HI 24!"); - - System.out.println(UIManager.getDefaults().get("OptionPane.buttonFont")); - System.out.println(UIManager.getDefaults().get("OptionPane.messageFont")); - }); - }catch(Exception ex) { - ex.printStackTrace(); - } - } -} diff --git a/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.html b/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.html deleted file mode 100644 index e63e0ea768b..00000000000 --- a/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - High resolution icon test, bug ID 8024926 - - - -

      See the dialog box (usually in upper left corner) for instructions

      - - diff --git a/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.java b/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.java deleted file mode 100644 index 89aa754be88..00000000000 --- a/test/jdk/javax/swing/JOptionPane/8024926/bug8024926.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -import java.awt.BorderLayout; -import java.awt.Dialog; -import java.awt.EventQueue; -import java.awt.Frame; -import java.awt.TextArea; -import javax.swing.JApplet; -import javax.swing.JOptionPane; - -import jdk.test.lib.Platform; - -/** - * @test - * @bug 8024926 8040279 - * @summary [macosx] AquaIcon HiDPI support - * @author Alexander Scherbatiy - * @library /test/lib - * @build jdk.test.lib.Platform - * @run applet/manual=yesno bug8024926.html - */ -public class bug8024926 extends JApplet { - //Declare things used in the test, like buttons and labels here - - public void init() { - //Create instructions for the user here, as well as set up - // the environment -- set the layout manager, add buttons, - // etc. - this.setLayout(new BorderLayout()); - - - if (Platform.isOSX()) { - String[] instructions = { - "Verify that high resolution system icons are used" - + " in JOptionPane on HiDPI displays.", - "1) Run the test on Retina display or enable the Quartz Debug" - + " and select the screen resolution with (HiDPI) label", - "2) Check that the error icon on the JOptionPane is smooth", - "If so, press PASS, else press FAIL." - }; - Sysout.createDialogWithInstructions(instructions); - - } else { - String[] instructions = { - "This test is not applicable to the current platform. Press PASS." - }; - Sysout.createDialogWithInstructions(instructions); - } - - - }//End init() - - public void start() { - //Get things going. Request focus, set size, et cetera - setSize(200, 200); - setVisible(true); - validate(); - EventQueue.invokeLater(new Runnable() { - - public void run() { - createAndShowGUI(); - } - }); - }// start() - - //The rest of this class is the actions which perform the test... - //Use Sysout.println to communicate with the user NOT System.out!! - //Sysout.println ("Something Happened!"); - private static void createAndShowGUI() { - JOptionPane.showMessageDialog(null, - "Icons should have high resolution.", - "High resolution icon test.", - JOptionPane.ERROR_MESSAGE); - } -}// class BlockedWindowTest - -/* Place other classes related to the test after this line */ -/** - * ************************************************** - * Standard Test Machinery DO NOT modify anything below -- it's a standard chunk - * of code whose purpose is to make user interaction uniform, and thereby make - * it simpler to read and understand someone else's test. - * ************************************************** - */ -/** - * This is part of the standard test machinery. It creates a dialog (with the - * instructions), and is the interface for sending text messages to the user. To - * print the instructions, send an array of strings to Sysout.createDialog - * WithInstructions method. Put one line of instructions per array entry. To - * display a message for the tester to see, simply call Sysout.println with the - * string to be displayed. This mimics System.out.println but works within the - * test harness as well as standalone. - */ -class Sysout { - - private static TestDialog dialog; - - public static void createDialogWithInstructions(String[] instructions) { - dialog = new TestDialog(new Frame(), "Instructions"); - dialog.printInstructions(instructions); - dialog.setVisible(true); - println("Any messages for the tester will display here."); - } - - public static void createDialog() { - dialog = new TestDialog(new Frame(), "Instructions"); - String[] defInstr = {"Instructions will appear here. ", ""}; - dialog.printInstructions(defInstr); - dialog.setVisible(true); - println("Any messages for the tester will display here."); - } - - public static void printInstructions(String[] instructions) { - dialog.printInstructions(instructions); - } - - public static void println(String messageIn) { - dialog.displayMessage(messageIn); - } -}// Sysout class - -/** - * This is part of the standard test machinery. It provides a place for the test - * instructions to be displayed, and a place for interactive messages to the - * user to be displayed. To have the test instructions displayed, see Sysout. To - * have a message to the user be displayed, see Sysout. Do not call anything in - * this dialog directly. - */ -class TestDialog extends Dialog { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog(Frame frame, String name) { - super(frame, name); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea("", 15, maxStringLength, scrollBoth); - add("North", instructionsText); - - messageText = new TextArea("", 5, maxStringLength, scrollBoth); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions(String[] instructions) { - //Clear out any current instructions - instructionsText.setText(""); - - //Go down array of instruction strings - - String printStr, remainingStr; - for (int i = 0; i < instructions.length; i++) { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i]; - while (remainingStr.length() > 0) { - //if longer than max then chop off first max chars to print - if (remainingStr.length() >= maxStringLength) { - //Try to chop on a word boundary - int posOfSpace = remainingStr.lastIndexOf(' ', maxStringLength - 1); - - if (posOfSpace <= 0) { - posOfSpace = maxStringLength - 1; - } - - printStr = remainingStr.substring(0, posOfSpace + 1); - remainingStr = remainingStr.substring(posOfSpace + 1); - } //else just print - else { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append(printStr + "\n"); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage(String messageIn) { - messageText.append(messageIn + "\n"); - System.out.println(messageIn); - } -}// TestDialog class diff --git a/test/jdk/javax/swing/JOptionPane/bug4174551.java b/test/jdk/javax/swing/JOptionPane/bug4174551.java new file mode 100644 index 00000000000..f65f95192b7 --- /dev/null +++ b/test/jdk/javax/swing/JOptionPane/bug4174551.java @@ -0,0 +1,78 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4174551 + * @summary JOptionPane should allow custom buttons + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4174551 + */ +import java.awt.FlowLayout; +import java.awt.Font; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.UIManager; + +public class bug4174551 { + private static final String INSTRUCTIONS = """ + Two Message Dialog should pop up side-by-side + one with a custom message font size 24 with message "HI 24" + and another with default optionpane message font size with message "HI default" + If custom message font size is not more than default message fontsize + AND + custom message buttonfont size is more than default message buttonfont size + press "Fail" else press "Pass". """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JOptionPane Instructions") + .instructions(INSTRUCTIONS) + .rows(8) + .columns(40) + .testUI(bug4174551::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JDialog createTestUI() { + JOptionPane defaultPane = new JOptionPane(); + defaultPane.setMessage("HI default"); + defaultPane.setMessageType(JOptionPane.INFORMATION_MESSAGE); + UIManager.getDefaults().put("OptionPane.buttonFont", new Font("Dialog", Font.PLAIN, 10)); + UIManager.getDefaults().put("OptionPane.messageFont", new Font("Dialog", Font.PLAIN, 24)); + JOptionPane optionPane = new JOptionPane(); + optionPane.setMessage("HI 24!"); + optionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE); + JDialog dialog = new JDialog(); + dialog.setLayout(new FlowLayout()); + dialog.add(optionPane); + dialog.add(defaultPane); + dialog.pack(); + + System.out.println(UIManager.getDefaults().get("OptionPane.buttonFont")); + System.out.println(UIManager.getDefaults().get("OptionPane.messageFont")); + return dialog; + } +} diff --git a/test/jdk/javax/swing/JOptionPane/bug8024926.java b/test/jdk/javax/swing/JOptionPane/bug8024926.java new file mode 100644 index 00000000000..667e21f39f5 --- /dev/null +++ b/test/jdk/javax/swing/JOptionPane/bug8024926.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013, 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. + * + * 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. + */ +import java.awt.BorderLayout; +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.TextArea; +import javax.swing.JDialog; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +/** + * @test + * @bug 8024926 8040279 + * @requires (os.family == "mac") + * @summary [macosx] AquaIcon HiDPI support + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug8024926 + */ +public class bug8024926 { + + private static final String INSTRUCTIONS = """ + Verify that high resolution system icons are used + in JOptionPane on HiDPI displays. + 1) Run the test on Retina display or enable the Quartz Debug + and select the screen resolution with (HiDPI) label. + "2) Check that the error icon on the JOptionPane is smooth. + "If so, press PASS, else press FAIL."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("AquaIcon HIDPI Instructions") + .instructions(INSTRUCTIONS) + .rows(10) + .columns(35) + .testUI(bug8024926::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JDialog createTestUI() { + JOptionPane optionPane = new JOptionPane("High resolution icon test"); + optionPane.setMessage("Icons should have high resolutions"); + optionPane.setMessageType(JOptionPane.ERROR_MESSAGE); + JDialog dialog = new JDialog(); + dialog.setContentPane(optionPane); + dialog.pack(); + return dialog; + } +} diff --git a/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.html b/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.html deleted file mode 100644 index d1356c3f6d5..00000000000 --- a/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -Click on the top-bar and combo-box more than once. -Make sure popup menu and drop-down list have a border and their items are drawn properly. - - diff --git a/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.java b/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.java deleted file mode 100644 index cf73ba608f7..00000000000 --- a/test/jdk/javax/swing/JPopupMenu/7160604/bug7160604.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test - @bug 7160604 - @summary Using non-opaque windows - popups are initially not painted correctly - @author Oleg Pekhovskiy - @run applet/manual=yesno bug7160604.html -*/ - -import javax.swing.AbstractAction; -import javax.swing.BorderFactory; -import javax.swing.JApplet; -import javax.swing.JComboBox; -import javax.swing.JLabel; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JWindow; -import javax.swing.SwingUtilities; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import static java.awt.GraphicsDevice.WindowTranslucency.*; - -public class bug7160604 extends JApplet { - - public void init() { - SwingUtilities.invokeLater(() -> { - if (!GraphicsEnvironment - .getLocalGraphicsEnvironment() - .getDefaultScreenDevice() - .isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT)) { - // Tested translucency is not supported. Test passed - return; - } - - final JWindow window = new JWindow(); - window.setLocation(200, 200); - window.setSize(300, 300); - - final JLabel label = new JLabel("...click to invoke JPopupMenu"); - label.setOpaque(true); - final JPanel contentPane = new JPanel(new BorderLayout()); - contentPane.setBorder(BorderFactory.createLineBorder(Color.RED)); - window.setContentPane(contentPane); - contentPane.add(label, BorderLayout.NORTH); - - final JComboBox comboBox = new JComboBox(new Object[]{"1", "2", "3", "4"}); - contentPane.add(comboBox, BorderLayout.SOUTH); - - final JPopupMenu jPopupMenu = new JPopupMenu(); - - jPopupMenu.add("string"); - jPopupMenu.add(new AbstractAction("action") { - @Override - public void actionPerformed(final ActionEvent e) { - } - }); - jPopupMenu.add(new JLabel("label")); - jPopupMenu.add(new JMenuItem("MenuItem")); - label.addMouseListener(new MouseAdapter() { - @Override - public void mouseReleased(final MouseEvent e) { - jPopupMenu.show(label, 0, 0); - } - }); - - window.setBackground(new Color(0, 0, 0, 0)); - - window.setVisible(true); - }); - } -} diff --git a/test/jdk/javax/swing/JPopupMenu/bug7160604.java b/test/jdk/javax/swing/JPopupMenu/bug7160604.java new file mode 100644 index 00000000000..591817b75c9 --- /dev/null +++ b/test/jdk/javax/swing/JPopupMenu/bug7160604.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2013, 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. + * + * 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. + */ + +/* + * @test + * @bug 7160604 + * @summary Using non-opaque windows - popups are initially not painted correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug7160604 +*/ +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.GraphicsEnvironment; +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import static java.awt.GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT; +import javax.swing.AbstractAction; +import javax.swing.BorderFactory; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JWindow; +import javax.swing.SwingUtilities; + +public class bug7160604 { + + private static final String INSTRUCTIONS = """ + Click on the top-bar and combo-box at the bottom more than once. + Check top-bar popup menu and combo-box drop-down list have a border + and their items are drawn properly. + If yes, Click Pass else click Fail."""; + + public static void main(String[] args) throws Exception { + if (!GraphicsEnvironment + .getLocalGraphicsEnvironment() + .getDefaultScreenDevice() + .isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT)) { + // Tested translucency is not supported. Test passed + return; + } + PassFailJFrame.builder() + .title("PopupMenu Instructions") + .instructions(INSTRUCTIONS) + .rows(5) + .columns(35) + .testUI(bug7160604::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JWindow createTestUI() { + + final JWindow window = new JWindow(); + window.setLocation(200, 200); + window.setSize(300, 300); + + final JLabel label = new JLabel("...click to invoke JPopupMenu"); + label.setOpaque(true); + final JPanel contentPane = new JPanel(new BorderLayout()); + contentPane.setBorder(BorderFactory.createLineBorder(Color.RED)); + window.setContentPane(contentPane); + contentPane.add(label, BorderLayout.NORTH); + + final JComboBox comboBox = new JComboBox(new Object[]{"1", "2", "3", "4"}); + contentPane.add(comboBox, BorderLayout.SOUTH); + + final JPopupMenu jPopupMenu = new JPopupMenu(); + + jPopupMenu.add("string"); + jPopupMenu.add(new AbstractAction("action") { + @Override + public void actionPerformed(final ActionEvent e) { + } + }); + jPopupMenu.add(new JLabel("label")); + jPopupMenu.add(new JMenuItem("MenuItem")); + label.addMouseListener(new MouseAdapter() { + @Override + public void mouseReleased(final MouseEvent e) { + jPopupMenu.show(label, 0, 0); + } + }); + + window.setBackground(new Color(0, 0, 0, 0)); + + return window; + } +} diff --git a/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.html b/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.html deleted file mode 100644 index a473b819d1c..00000000000 --- a/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - -Choose the variable applet size and try to resize the applet. -The test passes the thumb is painted correctly. - - - - - diff --git a/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.java b/test/jdk/javax/swing/JScrollBar/Test8039464.java similarity index 74% rename from test/jdk/javax/swing/JScrollBar/8039464/Test8039464.java rename to test/jdk/javax/swing/JScrollBar/Test8039464.java index 44bb33abd94..780d5e9db77 100644 --- a/test/jdk/javax/swing/JScrollBar/8039464/Test8039464.java +++ b/test/jdk/javax/swing/JScrollBar/Test8039464.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 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 @@ -26,7 +26,6 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; -import javax.swing.JApplet; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JScrollBar; @@ -37,11 +36,16 @@ * @test * @bug 8039464 * @summary Tests enabling/disabling of titled border's caption - * @author Sergey Malenkov - * @run applet/manual=yesno Test8039464.html + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual Test8039464 */ -public class Test8039464 extends JApplet { +public class Test8039464 { + private static final String INSTRUCTIONS = """ + If the scrollbar thumb is painted correctly in system lookandfeel + click Pass else click Fail. """; + static { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); @@ -50,11 +54,6 @@ public class Test8039464 extends JApplet { } } - @Override - public void init() { - init(this); - } - private static void init(Container container) { container.setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); @@ -77,16 +76,20 @@ private static void init(Container container) { } public static void main(String[] args) throws Exception { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JFrame frame = new JFrame("8039464"); - init(frame); - frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame.pack(); - frame.setLocationRelativeTo(null); - frame.setVisible(true); - } - }); + PassFailJFrame.builder() + .title("JScrollBar Instructions") + .instructions(INSTRUCTIONS) + .rows(5) + .columns(35) + .testUI(Test8039464::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("8039464"); + init(frame); + frame.pack(); + return frame; } } diff --git a/test/jdk/javax/swing/JToolTip/4644444/bug4644444.html b/test/jdk/javax/swing/JToolTip/4644444/bug4644444.html deleted file mode 100644 index b7e9bcb03fe..00000000000 --- a/test/jdk/javax/swing/JToolTip/4644444/bug4644444.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - bug4644444 - - - -

      bug4644444
      Bug ID: 4644444

      - -

      See the dialog box (usually in upper left corner) for instructions

      - - - - diff --git a/test/jdk/javax/swing/JToolTip/4644444/bug4644444.java b/test/jdk/javax/swing/JToolTip/4644444/bug4644444.java deleted file mode 100644 index 124c565a9cb..00000000000 --- a/test/jdk/javax/swing/JToolTip/4644444/bug4644444.java +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.awt.*; -import javax.swing.*; -import java.awt.event.*; - -/* - * test - * @bug 4644444 8076246 -*/ - -public class bug4644444 extends JApplet { - - JPanel panel; - JButton button; - - public bug4644444() throws Exception { - java.awt.EventQueue.invokeLater( () -> { - panel = new JPanel(); - button = new JButton("whooo"); - button.setToolTipText("Somthing really long 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); - panel.add(button); - getContentPane().add(panel); - }); - } - - public void init() { - String[][] instructionsSet = - { - { - " Note : Incase of Assertion failure,user can enter", - " remarks by pressing 'Assertion Fail Remarks ' button", - " ", - " You would see a testframe with a Button", - " ", - " ON ALL PLATFORMS", - "1. Move the mouse on the button, ", - " so that the tooltip attached to it comes up ", - "2. Tool tip should get adjusted it-self to show ", - " its full length of text. ", - "3. If tooltip text gets cut, ", - " press 'Assertion Fail' else press 'Assertion Pass'", - "4. Similarly, move the applet to different locations of the screen, ", - " & see if tooltip works properly everywhere. " - } - }; - - String[] exceptionsSet = - { - "JToolTip is shown partially when placed very close to screen boundaries", - }; - - Sysout.setInstructionsWithExceptions(instructionsSet,exceptionsSet); - - } - - public void start (){} - - public void destroy(){ - if(Sysout.failStatus()) { - String failMsg = Sysout.getFailureMessages(); - failMsg = failMsg.replace('\n',' '); - throw new RuntimeException(failMsg); - }// End destroy - } -} - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout - { - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - - public static void setInstructionsWithExceptions(String instructionsSet[][], - String exceptionsSet[]) { - createDialogWithInstructions(instructionsSet[0]); - dialog.setInstructions(instructionsSet); - dialog.setExceptionMessages(exceptionsSet); - } - - public static String getFailureMessages() { - return dialog.failureMessages; - } - - public static boolean failStatus() { - return dialog.failStatus; - } - - }// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog - { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 70; - - Panel assertPanel; - Button assertPass,assertFail,remarks; - HandleAssert handleAssert; - boolean failStatus=false; - int instructionCounter=0; - String instructions[][]; - int exceptionCounter=0; - String exceptionMessages[]; - String failureMessages="
      "; - String remarksMessage=null; - RemarksDialog remarksDialog; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 14, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 3, maxStringLength, scrollBoth ); - add("Center", messageText); - - assertPanel = new Panel(new FlowLayout()); - assertPass=new Button("Assertion Pass"); - assertPass.setName("Assertion Pass"); - assertFail=new Button("Assertion Fail"); - assertFail.setName("Assertion Fail"); - remarks = new Button("Assertion Fail Remarks"); - remarks.setEnabled(false); - remarks.setName("Assertion Remarks"); - assertPanel.add(assertPass); - assertPanel.add(assertFail); - assertPanel.add(remarks); - handleAssert = new HandleAssert(); - assertPass.addActionListener(handleAssert); - assertFail.addActionListener(handleAssert); - remarks.addActionListener(handleAssert); - add("South",assertPanel); - pack(); - - show(); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - } - - public void emptyMessage() { - messageText.setText(""); - } - - public void setInstructions(String insStr[][]) { - instructions=insStr; - } - - public void setExceptionMessages(String exceptionMessages[]) { - this.exceptionMessages=exceptionMessages; - } - - class HandleAssert implements ActionListener { - public void actionPerformed(ActionEvent ae) { - if(ae.getSource()==remarks) { - remarksDialog = new RemarksDialog(TestDialog.this, - "Assertion Remarks Dialog",true); - remarks.setEnabled(false); - if(remarksMessage!=null) - failureMessages+=". User Remarks : "+remarksMessage; - } - else { - if(instructionCounter"+ - exceptionMessages[exceptionCounter]; - } - } - exceptionCounter++; - } - } - } - - class RemarksDialog extends Dialog implements ActionListener{ - Panel rootPanel,remarksPanel; - TextArea textarea; - Button addRemarks,cancelRemarks; - public RemarksDialog(Dialog owner,String title,boolean modal) { - super(owner,title,modal); - rootPanel = new Panel(new BorderLayout()); - remarksPanel = new Panel(new FlowLayout()); - textarea = new TextArea(5,30); - addRemarks=new Button("Add Remarks"); - addRemarks.addActionListener(this); - cancelRemarks = new Button("Cancel Remarks"); - cancelRemarks.addActionListener(this); - remarksPanel.add(addRemarks); - remarksPanel.add(cancelRemarks); - rootPanel.add(textarea,"Center"); - rootPanel.add(remarksPanel,"South"); - add(rootPanel); - setBounds(150,150,400,200); - setVisible(true); - } - - public void actionPerformed(ActionEvent ae) { - remarksMessage=null; - if(ae.getSource()==addRemarks) { - String msg = textarea.getText().trim(); - if (msg.length()>0) - remarksMessage=msg; - } - dispose(); - } - - } - -}// TestDialog class diff --git a/test/jdk/javax/swing/JToolTip/bug4644444.java b/test/jdk/javax/swing/JToolTip/bug4644444.java new file mode 100644 index 00000000000..2921ecf0da5 --- /dev/null +++ b/test/jdk/javax/swing/JToolTip/bug4644444.java @@ -0,0 +1,63 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JButton; +import javax.swing.JFrame; + +/* + * @test + * @bug 4644444 8076246 + * @summary JToolTip is shown improperly when placed very close to screen boundaries + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4644444 + */ + +public class bug4644444 { + + private static final String INSTRUCTIONS = """ + 1. Move the mouse on the button, so that the tooltip is visible. + 2. Tooltip should get adjusted itself to show its full length of text. + 3. Similarly, move the frame to different locations of the screen + & see if tooltip works properly everywhere. + 4. Press 'Pass' if tooltip text is fully visible else press 'Fail'. """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JToolTip Instructions") + .instructions(INSTRUCTIONS) + .testUI(bug4644444::createUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + JFrame frame = new JFrame("bug4644444"); + JButton button = new JButton("Button"); + button.setToolTipText("Something really long 1234567890 1234567890 " + + "1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"); + frame.getContentPane().add(button); + frame.setSize(200, 80); + return frame; + } +} diff --git a/test/jdk/javax/swing/reliability/HangDuringStaticInitialization.java b/test/jdk/javax/swing/reliability/HangDuringStaticInitialization.java index fc820a32fa1..d6666d21309 100644 --- a/test/jdk/javax/swing/reliability/HangDuringStaticInitialization.java +++ b/test/jdk/javax/swing/reliability/HangDuringStaticInitialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, 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 @@ -33,7 +33,6 @@ /** * @test * @bug 8189604 8208702 - * @requires !vm.debug | os.family != "windows" * @run main/othervm -Djava.awt.headless=false HangDuringStaticInitialization * @run main/othervm -Djava.awt.headless=true HangDuringStaticInitialization */ diff --git a/test/jdk/javax/swing/text/BoxView/bug6494356.java b/test/jdk/javax/swing/text/BoxView/bug6494356.java new file mode 100644 index 00000000000..fe899d57984 --- /dev/null +++ b/test/jdk/javax/swing/text/BoxView/bug6494356.java @@ -0,0 +1,135 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 6494356 + * @key headful + * @summary Test that BoxView.layout() is not called with negative arguments + * @run main bug6494356 + */ + +import java.awt.Dimension; +import java.awt.Toolkit; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.CountDownLatch; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import javax.swing.text.Element; +import javax.swing.text.StyleConstants; +import javax.swing.text.View; +import javax.swing.text.ViewFactory; +import javax.swing.text.html.HTML; +import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.ParagraphView; + +public class bug6494356 { + static JEditorPane ep; + private static final CountDownLatch latch = new CountDownLatch(1); + + public static void main(final String[] args) throws Exception { + final Path file = Path.of("bug6494356.html"); + try (Writer writer = Files.newBufferedWriter(file)) { + writer.write("

      Paragraph

      "); + } + try { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + ep = new JEditorPane(); + ep.setEditorKitForContentType("text/html", new MyEditorKit()); + ep.addPropertyChangeListener("page", new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent pce) { + if (pce.getPropertyName().equals("page")) { + latch.countDown(); + } + } + }); + JFrame f = new JFrame(); + f.setTitle("6494356"); + f.setSize(new Dimension( + Toolkit.getDefaultToolkit().getScreenSize().width, 600)); + f.setContentPane(ep); + f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + f.setVisible(true); + try { + ep.setPage("file:" + file); + } catch (Exception ex) { + testPassed = false; + throw new RuntimeException(ex); + } + } + }); + + latch.await(); + if (!testPassed) { + throw new RuntimeException("test failed."); + } + } finally { + Files.delete(file); + } + System.out.println("6494356 OK"); + } + + static volatile boolean testPassed = true; + + static class MyEditorKit extends HTMLEditorKit { + static class MyViewFactory extends HTMLFactory { + public View create(Element elem) { + HTML.Tag tag = (HTML.Tag) elem.getAttributes().getAttribute( + StyleConstants.NameAttribute); + if ((tag != null) && (tag == HTML.Tag.P)) { + return new MyParagraphView(elem); + } else { + return super.create(elem); + } + } + + static class MyParagraphView extends ParagraphView { + MyParagraphView(Element elem) { + super(elem); + } + + protected void layout(int width, int height) { + if ((width < 0) || (height < 0)) { + testPassed = false; + throw new RuntimeException("w=" + width + " h=" + height); + } + super.layout(width, height); + } + } + + } + + final ViewFactory viewFactory = new MyViewFactory(); + + public ViewFactory getViewFactory() { + return viewFactory; + } + } + +} + diff --git a/test/jdk/javax/swing/text/GlyphView/4984669/bug4984669.html b/test/jdk/javax/swing/text/GlyphView/4984669/bug4984669.html deleted file mode 100644 index f9991a231c1..00000000000 --- a/test/jdk/javax/swing/text/GlyphView/4984669/bug4984669.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - -The four lines printed above in a bold typeface should all be underlined. -It is a bug if any of these lines is underlined only partially. -The very first line should not be underlined at all. - - diff --git a/test/jdk/javax/swing/text/GlyphView/4984669/bug4984669.java b/test/jdk/javax/swing/text/GlyphView/htmlUnderliningTest.java similarity index 54% rename from test/jdk/javax/swing/text/GlyphView/4984669/bug4984669.java rename to test/jdk/javax/swing/text/GlyphView/htmlUnderliningTest.java index ba590f9472a..b12a129dfa2 100644 --- a/test/jdk/javax/swing/text/GlyphView/4984669/bug4984669.java +++ b/test/jdk/javax/swing/text/GlyphView/htmlUnderliningTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 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 @@ -21,24 +21,48 @@ * questions. */ +import javax.swing.JEditorPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyledEditorKit; + /* @test - @bug 4984669 8002148 - @summary Tests HTML underlining - @author Peter Zhelezniakov - @run applet/manual=yesno bug4984669.html -*/ -import javax.swing.*; -import javax.swing.text.*; + * @bug 4984669 8002148 + * @summary Tests HTML underlining + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual htmlUnderliningTest + */ + +public class htmlUnderliningTest { + public static void main(String[] args) throws Exception { + String testInstructions = """ + The four lines printed in a bold typeface should all be underlined. + It is a bug if any of these lines is underlined only partially. + The very first line should not be underlined at all. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(testInstructions) + .rows(4) + .columns(35) + .splitUI(htmlUnderliningTest::initializeTest) + .build() + .awaitAndCheck(); + } -public class bug4984669 extends JApplet -{ - public void init() { + public static JPanel initializeTest() { + JPanel panel = new JPanel(); JEditorPane pane = new JEditorPane(); - this.getContentPane().add(new JScrollPane(pane)); + panel.add(new JScrollPane(pane)); pane.setEditorKit(new StyledEditorKit()); try { - pane.getDocument().insertString(0,"12 \n",null); + pane.getDocument().insertString(0, "12 \n", null); MutableAttributeSet attrs = new SimpleAttributeSet(); StyleConstants.setFontSize(attrs, 36); @@ -51,5 +75,6 @@ public void init() { } catch (Exception e) { throw new Error("Failed: Unexpected Exception", e); } + return panel; } } diff --git a/test/jdk/sun/java2d/cmm/ColorConvertOp/ColConvCCMTest.java b/test/jdk/sun/java2d/cmm/ColorConvertOp/ColConvCCMTest.java index 22e055fbe8e..97ed058ff5a 100644 --- a/test/jdk/sun/java2d/cmm/ColorConvertOp/ColConvCCMTest.java +++ b/test/jdk/sun/java2d/cmm/ColorConvertOp/ColConvCCMTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -23,7 +23,7 @@ /** * @test - * @bug 6476665 7033534 6830714 8052162 8196572 + * @bug 6476665 7033534 6830714 8052162 8196572 8326661 * @summary Verifies color conversion of Component Color Model based images * @run main ColConvCCMTest */ @@ -59,8 +59,8 @@ public class ColConvCCMTest extends ColConvTest { 2.5, // sRGB (isOpenProfile() ? 45.0 : 10.1), // LINEAR_RGB 10.5, // GRAY - (isOpenProfile() ? 215.0 : 45.5), // PYCC - (isOpenProfile() ? 56.0 : 47.5) // CIEXYZ + (isOpenProfile() ? 215.0 : 64.5), // PYCC + (isOpenProfile() ? 56.0 : 55.5) // CIEXYZ }; final static String [] gldImgNames = { diff --git a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java index b8ea9863327..c15f10aab3e 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java +++ b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 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 @@ -27,7 +27,7 @@ /* * @test - * @bug 8080462 8226651 8242332 + * @bug 8080462 8226651 8242332 8325164 * @summary testing interoperability of PSS signatures of PKCS11 provider * against SunRsaSign provider * @library /test/lib .. @@ -51,9 +51,12 @@ public static void main(String[] args) throws Exception { @Override public void main(Provider p) throws Exception { + Provider sunRsaSign = Security.getProvider("SunRsaSign"); + Security.removeProvider("SunRsaSign"); + Signature sigPkcs11; Signature sigSunRsaSign = - Signature.getInstance("RSASSA-PSS", "SunRsaSign"); + Signature.getInstance("RSASSA-PSS", sunRsaSign); KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", p); kpg.initialize(3072); diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java b/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java index 1f6886f2d69..e9e4158f20e 100644 --- a/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java +++ b/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8029661 + * @bug 8029661 8325164 * @summary Test TLS 1.2 * @modules java.base/sun.security.internal.spec * java.base/sun.security.util @@ -412,6 +412,18 @@ static private SSLEngine createSSLEngine(boolean client) ssle = sslCtx.createSSLEngine("localhost", 443); ssle.setUseClientMode(client); SSLParameters sslParameters = ssle.getSSLParameters(); + // verify that FFDHE named groups are available + boolean ffdheAvailable = Arrays.stream(sslParameters.getNamedGroups()) + .anyMatch(ng -> ng.startsWith("ffdhe")); + if (!ffdheAvailable) { + throw new RuntimeException("No FFDHE named groups available"); + } + // verify that ECDHE named groups are available + boolean ecdheAvailable = Arrays.stream(sslParameters.getNamedGroups()) + .anyMatch(ng -> ng.startsWith("secp")); + if (!ecdheAvailable) { + throw new RuntimeException("No ECDHE named groups available"); + } ssle.setSSLParameters(sslParameters); return ssle; @@ -426,28 +438,6 @@ private static void initialize() throws Exception { // 1. SunPKCS11 (with an NSS FIPS mode backend) // 2. SUN (to handle X.509 certificates) // 3. SunJSSE (for a TLS engine) - // - // RSASSA-PSS algorithm is not currently supported in SunPKCS11 - // but in SUN provider. As a result, it can be negotiated by the - // TLS engine. The problem is that SunPKCS11 keys are sensitive - // in FIPS mode and cannot be used in a SUN algorithm (conversion - // fails as plain values cannot be extracted). - // - // To workaround this issue, we disable RSASSA-PSS algorithm for - // TLS connections. Once JDK-8222937 is fixed, this workaround can - // (and should) be removed. - // - // On a final note, the list of disabled TLS algorithms - // (jdk.tls.disabledAlgorithms) has to be updated at this point, - // before it is read in sun.security.ssl.SSLAlgorithmConstraints - // class initialization. - String disabledAlgorithms = - Security.getProperty("jdk.tls.disabledAlgorithms"); - if (disabledAlgorithms.length() > 0) { - disabledAlgorithms += ", "; - } - disabledAlgorithms += "RSASSA-PSS"; - Security.setProperty("jdk.tls.disabledAlgorithms", disabledAlgorithms); if (initSecmod() == false) { return; diff --git a/test/jdk/sun/security/pkcs12/GetSetEntryTest.java b/test/jdk/sun/security/pkcs12/GetSetEntryTest.java new file mode 100644 index 00000000000..2bfb92aae2f --- /dev/null +++ b/test/jdk/sun/security/pkcs12/GetSetEntryTest.java @@ -0,0 +1,150 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 8327461 + * @summary engineGetEntry in PKCS12KeyStore should be thread-safe + * @library /test/lib ../../../java/security/testlibrary + * @modules java.base/sun.security.x509 + * java.base/sun.security.util + * @build CertificateBuilder + * @run main GetSetEntryTest + */ + +import java.math.BigInteger; +import java.security.cert.X509Certificate; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.spec.ECGenParameterSpec; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.TimeUnit; +import java.util.Date; + +import sun.security.testlibrary.CertificateBuilder; + +public class GetSetEntryTest { + + public static final String TEST = "test"; + + public static void main(String[] args) throws Exception { + KeyStore ks = KeyStore.getInstance("PKCS12"); + char[] password = "password".toCharArray(); + KeyStore.PasswordProtection protParam = new KeyStore.PasswordProtection(password); + ks.load(null, null); + + CertificateBuilder cbld = new CertificateBuilder(); + KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("EC"); + keyPairGen1.initialize(new ECGenParameterSpec("secp256r1")); + KeyPair ecKeyPair = keyPairGen1.genKeyPair(); + + long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); + long end = start + TimeUnit.DAYS.toMillis(1085); + boolean[] kuBitSettings = {true, false, false, false, false, true, + true, false, false}; + + // Set up the EC Cert + cbld.setSubjectName("CN=EC Test Cert, O=SomeCompany"). + setPublicKey(ecKeyPair.getPublic()). + setSerialNumber(new BigInteger("1")). + setValidity(new Date(start), new Date(end)). + addSubjectKeyIdExt(ecKeyPair.getPublic()). + addAuthorityKeyIdExt(ecKeyPair.getPublic()). + addBasicConstraintsExt(true, true, -1). + addKeyUsageExt(kuBitSettings); + + X509Certificate ecCert = cbld.build(null, ecKeyPair.getPrivate(), "SHA256withECDSA"); + + KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("RSA"); + keyPairGen2.initialize(4096); + KeyPair rsaKeyPair = keyPairGen2.genKeyPair(); + + cbld.reset(); + // Set up the RSA Cert + cbld.setSubjectName("CN=RSA Test Cert, O=SomeCompany"). + setPublicKey(rsaKeyPair.getPublic()). + setSerialNumber(new BigInteger("1")). + setValidity(new Date(start), new Date(end)). + addSubjectKeyIdExt(rsaKeyPair.getPublic()). + addAuthorityKeyIdExt(rsaKeyPair.getPublic()). + addBasicConstraintsExt(true, true, -1). + addKeyUsageExt(kuBitSettings); + + X509Certificate rsaCert = cbld.build(null, rsaKeyPair.getPrivate(), "SHA256withRSA"); + + KeyStore.PrivateKeyEntry ecEntry = new KeyStore.PrivateKeyEntry(ecKeyPair.getPrivate(), + new X509Certificate[]{ecCert}); + KeyStore.PrivateKeyEntry rsaEntry = new KeyStore.PrivateKeyEntry(rsaKeyPair.getPrivate(), + new X509Certificate[]{rsaCert}); + + test(ks, ecEntry, rsaEntry, protParam); + } + + private static final int MAX_ITERATIONS = 100; + + private static void test(KeyStore ks, KeyStore.PrivateKeyEntry ec, + KeyStore.PrivateKeyEntry rsa, + KeyStore.PasswordProtection protParam) + throws Exception { + ks.setEntry(TEST, ec, protParam); + + AtomicBoolean syncIssue = new AtomicBoolean(false); + + Thread thread = new Thread(() -> { + int iterations = 0; + while (!syncIssue.get() && iterations < MAX_ITERATIONS) { + try { + ks.setEntry(TEST, ec, protParam); + ks.setEntry(TEST, rsa, protParam); + } catch (Exception ex) { + syncIssue.set(true); + ex.printStackTrace(); + System.out.println("Test failed"); + System.exit(1); + } + iterations++; + } + }); + thread.start(); + + int iterations = 0; + while (!syncIssue.get() && iterations < MAX_ITERATIONS) { + try { + ks.getEntry(TEST, protParam); + } catch (Exception ex) { + syncIssue.set(true); + ex.printStackTrace(); + System.out.println("Test failed"); + System.exit(1); + } + iterations++; + } + + thread.join(); + + if (!syncIssue.get()) { + System.out.println("Test completed successfully"); + } + } +} diff --git a/test/jdk/sun/security/provider/certpath/PKIXCertComparator/Order.java b/test/jdk/sun/security/provider/certpath/PKIXCertComparator/Order.java new file mode 100644 index 00000000000..b353a8748c9 --- /dev/null +++ b/test/jdk/sun/security/provider/certpath/PKIXCertComparator/Order.java @@ -0,0 +1,186 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 8317431 + * @summary Verify order of PKIXCertComparator sorting algorithm + * @modules java.base/sun.security.provider.certpath:+open + * java.base/sun.security.x509 + * java.base/sun.security.util + * @library /test/lib ../../../../../java/security/testlibrary + * @build CertificateBuilder + * @run main Order + */ + +import java.lang.reflect.Constructor; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.cert.X509Certificate; +import java.util.Comparator; +import java.util.Set; +import javax.security.auth.x500.X500Principal; +import sun.security.x509.X509CertImpl; + +import jdk.test.lib.Asserts; +import sun.security.testlibrary.CertificateBuilder; + +public class Order { + + private record CertAndKeyPair(X509Certificate cert, KeyPair keyPair) {} + + private static KeyPairGenerator kpg; + + public static void main(String[] args) throws Exception { + kpg = KeyPairGenerator.getInstance("RSA"); + kpg.initialize(2048); + + // Create top-level root CA cert with KIDs (Subject and Auth KeyIds) + // A root CA doesn't usually have an Auth KeyId but for this test, + // it doesn't matter. + CertAndKeyPair rootCA = + createCert(null, "CN=Root CA, O=Java, C=US", true, true); + System.out.println(rootCA.cert); + + // Create intermediate CA cert with KIDs, issued by root CA + CertAndKeyPair javaCA = + createCert(rootCA, "CN=Java CA, O=Java, C=US", true, true); + System.out.println(javaCA.cert); + + // Create intermediate CA cert without KIDs, issued by root CA. + // This CA has the same DN/public key as the CA with KIDs. + CertAndKeyPair javaCAWoKids = createCert(rootCA, + "CN=Java CA, O=Java, C=US", true, false, javaCA.keyPair); + System.out.println(javaCAWoKids.cert); + + // Create another intermediate CA cert without KIDs, issued by root CA. + CertAndKeyPair openJDKCAWoKids = createCert(rootCA, + "CN=OpenJDK CA, O=OpenJDK, C=US", true, false); + System.out.println(openJDKCAWoKids.cert); + + // Create another intermediate CA with KIDs, issued by Java CA + CertAndKeyPair secCA = createCert(javaCAWoKids, + "CN=Security CA, OU=Security, O=Java, C=US", true, true); + System.out.println(secCA.cert); + + // Cross certify Java CA with OpenJDK CA + CertAndKeyPair javaCAIssuedByOpenJDKCA = createCert(openJDKCAWoKids, + "CN=Java CA, O=Java, C=US", true, false, javaCA.keyPair); + System.out.println(javaCAIssuedByOpenJDKCA.cert); + + // Cross certify Security CA with OpenJDK CA + CertAndKeyPair secCAIssuedByOpenJDKCA = createCert(openJDKCAWoKids, + "CN=Security CA, OU=Security, O=Java, C=US", true, false, secCA.keyPair); + System.out.println(secCAIssuedByOpenJDKCA.cert); + + // Create end entity cert without KIDs issued by Security CA. + CertAndKeyPair ee = createCert(secCA, + "CN=EE, OU=Security, O=Java, C=US", false, false); + System.out.println(ee.cert); + + // Create another end entity cert without KIDs issued by Java CA. + // This EE has the same DN/public key as the one above. + CertAndKeyPair eeIssuedByJavaCA = createCert(javaCA, + "CN=EE, OU=Security, O=Java, C=US", false, false); + System.out.println(eeIssuedByJavaCA.cert); + + Constructor ctor = getPKIXCertComparatorCtor(); + Set trustedSubjects = + Set.of(new X500Principal("CN=Root CA, O=Java, C=US")); + + System.out.println("Test that equal certs are treated the same"); + Comparator c = (Comparator) ctor.newInstance(trustedSubjects, + secCA.cert); + Asserts.assertTrue(c.compare(javaCA.cert, javaCA.cert) == 0); + + System.out.println("Test that cert with matching kids is preferred"); + Asserts.assertTrue(c.compare(javaCA.cert, javaCAWoKids.cert) == -1); + Asserts.assertTrue(c.compare(javaCAWoKids.cert, javaCA.cert) == 1); + + System.out.println("Test that cert issued by anchor is preferred"); + Asserts.assertTrue( + c.compare(javaCAWoKids.cert, javaCAIssuedByOpenJDKCA.cert) == -1); + Asserts.assertTrue( + c.compare(javaCAIssuedByOpenJDKCA.cert, javaCAWoKids.cert) == 1); + + System.out.println( + "Test that cert issuer in same namespace as anchor is preferred"); + c = (Comparator) ctor.newInstance(trustedSubjects, ee.cert); + Asserts.assertTrue( + c.compare(secCA.cert, secCAIssuedByOpenJDKCA.cert) == -1); + Asserts.assertTrue( + c.compare(secCAIssuedByOpenJDKCA.cert, secCA.cert) == 1); + + System.out.println( + "Test cert issuer in same namespace closest to root is preferred"); + Asserts.assertTrue(c.compare(eeIssuedByJavaCA.cert, ee.cert) == -1); + Asserts.assertTrue(c.compare(ee.cert, eeIssuedByJavaCA.cert) == 1); + } + + private static boolean[] CA_KEY_USAGE = + new boolean[] {true,false,false,false,false,true,true,false,false}; + private static boolean[] EE_KEY_USAGE = + new boolean[] {true,false,false,false,false,false,false,false,false}; + + private static CertAndKeyPair createCert(CertAndKeyPair issuer, + String subjectDn, boolean ca, boolean kids) throws Exception { + + KeyPair kp = kpg.generateKeyPair(); + return createCert(issuer, subjectDn, ca, kids, kp); + } + + private static CertAndKeyPair createCert(CertAndKeyPair issuer, + String subjectDn, boolean ca, boolean kids, KeyPair kp) + throws Exception { + + if (issuer == null) { + issuer = new CertAndKeyPair(null, kp); + } + CertificateBuilder cb = new CertificateBuilder() + .setSubjectName(subjectDn) + .setPublicKey(kp.getPublic()); + + if (ca) { + cb = cb.addBasicConstraintsExt(true, true, -1) + .addKeyUsageExt(CA_KEY_USAGE); + } else { + cb = cb.addBasicConstraintsExt(true, false, -1) + .addKeyUsageExt(EE_KEY_USAGE); + } + if (kids) { + cb = cb.addAuthorityKeyIdExt(issuer.keyPair.getPublic()) + .addSubjectKeyIdExt(kp.getPublic()); + } + X509Certificate cert = + cb.build(issuer.cert, issuer.keyPair.getPrivate(), "SHA256withRSA"); + return new CertAndKeyPair(cert, kp); + } + + private static Constructor getPKIXCertComparatorCtor() throws Exception { + var cl = Class.forName( + "sun.security.provider.certpath.ForwardBuilder$PKIXCertComparator"); + var c = cl.getDeclaredConstructor(Set.class, X509CertImpl.class); + c.setAccessible(true); + return c; + } +} diff --git a/test/jdk/sun/security/tools/keytool/fakegen/java.base/sun/security/ec/ECKeyPairGenerator.java b/test/jdk/sun/security/tools/keytool/fakegen/java.base/sun/security/ec/ECKeyPairGenerator.java index 50de12acf06..5e7429ee616 100644 --- a/test/jdk/sun/security/tools/keytool/fakegen/java.base/sun/security/ec/ECKeyPairGenerator.java +++ b/test/jdk/sun/security/tools/keytool/fakegen/java.base/sun/security/ec/ECKeyPairGenerator.java @@ -74,7 +74,7 @@ public KeyPair generateKeyPair() { " has been patched. Key size " + keySize + " is not supported"); } - ECParameterSpec ecParams = ECUtil.getECParameterSpec(null, keySize); + ECParameterSpec ecParams = ECUtil.getECParameterSpec(keySize); try { return new KeyPair(new ECPublicKeyImpl(new ECPoint(x, y), ecParams), new ECPrivateKeyImpl(s, ecParams)); diff --git a/test/jdk/tools/launcher/exeJliLaunchTest.c b/test/jdk/tools/launcher/exeJliLaunchTest.c index 42b7118fec5..9157b309f56 100644 --- a/test/jdk/tools/launcher/exeJliLaunchTest.c +++ b/test/jdk/tools/launcher/exeJliLaunchTest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 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 @@ -28,9 +28,10 @@ * tools. The rest of the files will be linked in. */ +#include "export.h" #include "java.h" -int +EXPORT int main(int argc, char **args) { //avoid null-terminated array of arguments to test JDK-8303669 diff --git a/test/langtools/jdk/javadoc/doclet/testBreakIterator/TestBreakIterator.java b/test/langtools/jdk/javadoc/doclet/testBreakIterator/TestBreakIterator.java index 72b1336dc59..31f1d3a66da 100644 --- a/test/langtools/jdk/javadoc/doclet/testBreakIterator/TestBreakIterator.java +++ b/test/langtools/jdk/javadoc/doclet/testBreakIterator/TestBreakIterator.java @@ -23,7 +23,7 @@ /* * @test - * @bug 4165985 + * @bug 4165985 8326332 * @summary Determine the end of the first sentence using BreakIterator. * If the first sentence of "method" is parsed correctly, the test passes. * Correct Answer: "This is a class (i.e. it is indeed a class)." @@ -76,5 +76,10 @@ public void test() { """
      A constant indicating that the keyLocation is indeterminate or not relevant.
      """); + + checkOutput("pkg/BreakIteratorTest.html", true, + """ + """); } } diff --git a/test/langtools/jdk/javadoc/doclet/testBreakIterator/pkg/BreakIteratorTest.java b/test/langtools/jdk/javadoc/doclet/testBreakIterator/pkg/BreakIteratorTest.java index 9370d162808..3ea965377f6 100644 --- a/test/langtools/jdk/javadoc/doclet/testBreakIterator/pkg/BreakIteratorTest.java +++ b/test/langtools/jdk/javadoc/doclet/testBreakIterator/pkg/BreakIteratorTest.java @@ -56,4 +56,9 @@ public void foobar(){} */ public void fe(){} + /** + * Inline tags extending + * beyond the first sentence. Tags are closed here. + */ + public void meh(){} } diff --git a/test/langtools/jdk/javadoc/doclet/testNewApiList/TestNewApiList.java b/test/langtools/jdk/javadoc/doclet/testNewApiList/TestNewApiList.java index e757ddc0eed..bf89f377d24 100644 --- a/test/langtools/jdk/javadoc/doclet/testNewApiList/TestNewApiList.java +++ b/test/langtools/jdk/javadoc/doclet/testNewApiList/TestNewApiList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8263468 8269401 8268422 8287524 + * @bug 8263468 8269401 8268422 8287524 8325874 * @summary New page for "recent" new API * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -115,7 +115,9 @@ private void checkMultiReleaseContents() { 3.2 + 5

      Contents

      • Modules
      • @@ -604,9 +606,11 @@ private void checkSingleReleaseDeprecatedElements() {
        Show API deprecated in:
        + 5

        Contents

        • Terminally Deprecated
        • @@ -677,7 +681,9 @@ private void checkPackageContents() { 5 + 6

          Contents

          • Classes
          • diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java b/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java index f9a17947f0c..247ca0f7874 100644 --- a/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java +++ b/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8250768 8261976 8277300 8282452 8287597 8325325 + * @bug 8250768 8261976 8277300 8282452 8287597 8325325 8325874 * @summary test generated docs for items declared using preview * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -78,10 +78,13 @@ public void testPreviewAPIJavadoc() { checkOutput("preview-list.html", true, """ -
              +

              Contents

                diff --git a/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/TestTypeAnnotations.java b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/TestTypeAnnotations.java index f710a978d5e..948ed22c418 100644 --- a/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/TestTypeAnnotations.java +++ b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/TestTypeAnnotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,7 +24,7 @@ /* * @test * @bug 8005091 8009686 8025633 8026567 6469562 8071982 8071984 8162363 8175200 8186332 8182765 - * 8187288 8241969 8259216 + * 8187288 8241969 8259216 8325433 * @summary Make sure that type annotations are displayed correctly * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -133,18 +133,28 @@ annotation interface in typeannos">@FldA java.lang.String,array1Deep""", """ -
                java.lang.String @FldB [][]&nbs\ +
                java.lang.String[] @FldB []&nbs\ p;array2SecondOld
                """, """
                @FldD java.lang.String @FldC @FldB [] @FldC @FldA [] ar\ - ray2Deep
                """); + tml" title="annotation interface in typeannos">@FldC @FldA [] @FldC @FldB [] ar\ + ray2Deep
                """, + + """ +
                @FldA int primitive
                """, + """ +
                @FldA int @FldB [] primitiveArray1Deep
                """); checkOutput("typeannos/ModifiedScoped.html", true, """ @@ -175,14 +185,25 @@ interface in typeannos">@FldB java.lang.String> @MRtnA java.lang.String @MRtnB [] @MRtnA [] @MRtnA [] @MRtnB [] array2Deep()""", """
                @MRtnA java.lang.String[][]&nb\ - sp;array2()
                """); + sp;array2()""", + + """ +
                @MRtnA int \ + primitive()
                """, + + """ +
                @MRtnA int @MRtnB [] primitiveArray1Deep()
                """); checkOutput("typeannos/MtdModifiedScoped.html", true, """ @@ -253,9 +274,22 @@ tation interface in typeannos">@ParamB java.lang.String> a)
                void array2Deep(@ParamA java.lang.String\ - @ParamB [] \ - @ParamA []&n\ - bsp;a)"""); + @ParamA [] \ + @ParamB []&n\ + bsp;a)""", + + """ +
                void primitive(@ParamA int a)
                """, + + """ +
                void primitiveArray1Deep(@ParamA int @ParamB [] \ + ;a)
                """); // Test for type annotations on throws (Throws.java). checkOutput("typeannos/ThrDefaultUnmodified.html", true, @@ -828,5 +862,45 @@ ation interface in typeannos">@RepTypeUseA @RepMethodB @RepMethodB void test()"""); + + checkOutput("typeannos/DeepArrays.html", true, + """ +
                @ArrA java.lang.String @ArrB [] @ArrC [] array2()
                """, + + """ +
                java.lang.String @ArrA [] @ArrB [] @ArrC [] @\ + ArrD [] array4()
                """, + + """ +
                @ArrA ArrParameterized<@ArrC java.lang.String @ArrA [] @ArrB []&\ + gt; @ArrC [] @ArrD [] manyNested()
                """, + + """ +
                void varargs(@ArrA java.lang.String @ArrB [] @ArrC [] @Arr\ + D ... arg)
                """, + + """ +
                int @ArrB [] @ArrA [] mixedStyles(int @ArrB [] @ArrA [\ + ] arg)
                """); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003/TestDescription.java b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/DeepArrays.java similarity index 50% rename from test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003/TestDescription.java rename to test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/DeepArrays.java index 056613ad1be..dd58a1d5d59 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003/TestDescription.java +++ b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/DeepArrays.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, 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 @@ -20,28 +20,31 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package typeannos; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; -/* - * @test - * - * @summary converted from VM Testbase nsk/jvmti/GetObjectMonitorUsage/objmonusage003. - * VM Testbase keywords: [quick, jpda, jvmti, noras] - * VM Testbase readme: - * DESCRIPTION - * The test checks if JVMTI function GetObjectMonitorUsage returns - * the expected values for the owner, entry_count, water_count - * fields of JVMTI_monitor_info. The tescases are the following: - * - unowned object without any waitings - * - owned object without any waitings - * - unowned object with waitings through Object.wait() - * - unowned object has been waiting - * COMMENTS - * Fixed according to 4669812 bug. - * Ported from JVMDI test nsk/jvmdi/GetMonitorInfo/getmoninfo003. - * - * @library /vmTestbase - * /test/lib - * @run main/othervm/native -agentlib:objmonusage003 nsk.jvmti.GetObjectMonitorUsage.objmonusage003 - */ +public class DeepArrays { + @ArrA String @ArrB [] @ArrC [] array2() { return null; } + String @ArrA [] @ArrB [] @ArrC [] @ArrD [] array4() { return null; } + @ArrA ArrParameterized<@ArrC String @ArrA [] @ArrB []> @ArrC [] @ArrD [] manyNested() { return null; } + void varargs(@ArrA String @ArrB [] @ArrC [] @ArrD ... arg) {} + int @ArrA [] mixedStyles(int @ArrB [] @ArrA [] arg) @ArrB [] { return null; } // JLS example 10.2-2 +} + +class ArrParameterized {} +@Target(ElementType.TYPE_USE) +@Documented +@interface ArrA { } +@Target(ElementType.TYPE_USE) +@Documented +@interface ArrB { } +@Target(ElementType.TYPE_USE) +@Documented +@interface ArrC { } +@Target(ElementType.TYPE_USE) +@Documented +@interface ArrD { } diff --git a/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/Fields.java b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/Fields.java index 359562c94f6..f9ff63edb7f 100644 --- a/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/Fields.java +++ b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/Fields.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -47,6 +47,9 @@ class DefaultScope { // Old-style array syntax String array2FirstOld @FldA []; String array2SecondOld [] @FldB []; + + @FldA int primitive; + @FldA int @FldB [] primitiveArray1Deep; } class ModifiedScoped { diff --git a/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/MethodReturnType.java b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/MethodReturnType.java index fbfb9789199..50b05aa3dd7 100644 --- a/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/MethodReturnType.java +++ b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/MethodReturnType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -49,6 +49,9 @@ class MtdDefaultScope { // Old-style array syntax String array2FirstOld() @MRtnA [] { return null; } String array2SecondOld() [] @MRtnB [] { return null; } + + @MRtnA int primitive() { return 0; } + @MRtnA int @MRtnB [] primitiveArray1Deep() { return null; } } class MtdModifiedScoped { diff --git a/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/Parameters.java b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/Parameters.java index 6fe8dfcd108..977192c0212 100644 --- a/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/Parameters.java +++ b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/typeannos/Parameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -42,6 +42,9 @@ void array2(@ParamA String [] [] a) {} void array2Deep(@ParamA String @ParamA [] @ParamB [] a) {} void array2First(String @ParamA [] [] a) {} void array2Second(String [] @ParamB [] a) {} + + void primitive(@ParamA int a) {} + void primitiveArray1Deep(@ParamA int @ParamB [] a) {} } class ParaParameterized { } diff --git a/test/langtools/tools/javac/launcher/BasicSourceLauncherTests.java b/test/langtools/tools/javac/launcher/BasicSourceLauncherTests.java index 1a686a8a38f..bf44a704b31 100644 --- a/test/langtools/tools/javac/launcher/BasicSourceLauncherTests.java +++ b/test/langtools/tools/javac/launcher/BasicSourceLauncherTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -100,11 +100,7 @@ void main() { } """); - // Replace with plain Run.of(hi) once implict classes are out of preview - System.setProperty("jdk.internal.javac.source", String.valueOf(Runtime.version().feature())); var run = Run.of(hi, List.of("--enable-preview"), List.of()); - System.clearProperty("jdk.internal.javac.source"); - assertAll("# " + run, () -> assertLinesMatch( """ diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index 7f6270c5182..a8817c3df79 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -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 @@ -52,12 +52,9 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import java.util.List; import java.util.Properties; import java.util.regex.Pattern; -import java.util.stream.Collectors; import com.sun.tools.javac.launcher.SourceLauncher; import com.sun.tools.javac.launcher.Fault; @@ -535,10 +532,9 @@ public void testEnablePreviewNoSource(Path base) throws IOException { List log = new JavaTask(tb) .vmOptions("--enable-preview") .className(base.resolve("HelloWorld.java").toString()) - .run(Task.Expect.FAIL) - .getOutputLines(Task.OutputKind.STDERR); - log = log.stream().filter(s->!s.matches("^Picked up .*JAVA.*OPTIONS:.*")).collect(Collectors.toList()); - checkEqual("stderr", log, List.of("error: --enable-preview must be used with --source")); + .run(Task.Expect.SUCCESS) + .getOutputLines(Task.OutputKind.STDOUT); + checkEqual("stdout", log, List.of("Hello World! []")); } @Test diff --git a/test/lib-test/jdk/test/whitebox/CPUInfoTest.java b/test/lib-test/jdk/test/whitebox/CPUInfoTest.java index c3713f300a6..138327ec44f 100644 --- a/test/lib-test/jdk/test/whitebox/CPUInfoTest.java +++ b/test/lib-test/jdk/test/whitebox/CPUInfoTest.java @@ -65,7 +65,7 @@ public class CPUInfoTest { "avx512_vbmi2", "avx512_vbmi", "rdtscp", "rdpid", "hv", "fsrm", "avx512_bitalg", "gfni", "f16c", "pku", "ospke", "cet_ibt", - "cet_ss", "avx512_ifma", "serialize" + "cet_ss", "avx512_ifma", "serialize", "avx_ifma" ); // @formatter:on // Checkstyle: resume diff --git a/test/lib/jdk/test/lib/thread/libVThreadPinner.c b/test/lib/jdk/test/lib/thread/libVThreadPinner.c index 958e636e3db..31738c64f1b 100644 --- a/test/lib/jdk/test/lib/thread/libVThreadPinner.c +++ b/test/lib/jdk/test/lib/thread/libVThreadPinner.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -23,11 +23,7 @@ #include -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" /* * Call a function with the given function pointer. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003/libobjmonusage003.cpp b/test/lib/native/export.h similarity index 74% rename from test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003/libobjmonusage003.cpp rename to test/lib/native/export.h index 855a62349d8..7e0eac383a5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage003/libobjmonusage003.cpp +++ b/test/lib/native/export.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 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 @@ -21,13 +21,15 @@ * questions. */ -#include "native_thread.cpp" -#include "nsk_tools.cpp" -#include "jni_tools.cpp" -#include "jvmti_tools.cpp" -#include "agent_tools.cpp" -#include "jvmti_FollowRefObjects.cpp" -#include "Injector.cpp" -#include "JVMTITools.cpp" -#include "agent_common.cpp" -#include "objmonusage003.cpp" +#ifndef TEST_LIB_NATIVE_EXPORT_H +#define TEST_LIB_NATIVE_EXPORT_H + +#ifdef _WIN64 + #define EXPORT __declspec(dllexport) +#elif defined(__GNUC__) + #define EXPORT __attribute__((visibility("default"))) +#else + #define EXPORT +#endif + +#endif // TEST_LIB_NATIVE_EXPORT_H diff --git a/test/micro/org/openjdk/bench/java/lang/MathBench.java b/test/micro/org/openjdk/bench/java/lang/MathBench.java index c7dde019154..fe461ee3f9c 100644 --- a/test/micro/org/openjdk/bench/java/lang/MathBench.java +++ b/test/micro/org/openjdk/bench/java/lang/MathBench.java @@ -141,6 +141,11 @@ public double ceilDouble() { return Math.ceil(double4Dot1); } + @Benchmark + public double addCeilFloorDouble() { + return Math.ceil(double4Dot1) + Math.floor(double4Dot1); + } + @Benchmark public double copySignDouble() { return Math.copySign(double81, doubleNegative12); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/libCallOverhead.c b/test/micro/org/openjdk/bench/java/lang/foreign/libCallOverhead.c index 8ad44f58cec..5297b77bb30 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/libCallOverhead.c +++ b/test/micro/org/openjdk/bench/java/lang/foreign/libCallOverhead.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, 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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT void func() {} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/libCriticalCalls.c b/test/micro/org/openjdk/bench/java/lang/foreign/libCriticalCalls.c index 6c76ef3d1b3..ca3838a50ca 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/libCriticalCalls.c +++ b/test/micro/org/openjdk/bench/java/lang/foreign/libCriticalCalls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT int sum_ints(int* arr, int size) { int sum = 0; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/libPtr.c b/test/micro/org/openjdk/bench/java/lang/foreign/libPtr.c index ed21ef198f3..ed8bf5ffd4d 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/libPtr.c +++ b/test/micro/org/openjdk/bench/java/lang/foreign/libPtr.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 @@ -21,14 +21,10 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif - #include +#include "export.h" + EXPORT long long id_long_long(long long value) { return value; } diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/libQSort.c b/test/micro/org/openjdk/bench/java/lang/foreign/libQSort.c index cafb83d8708..01fe313e864 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/libQSort.c +++ b/test/micro/org/openjdk/bench/java/lang/foreign/libQSort.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 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 @@ -21,12 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif - +#include "export.h" EXPORT int compar(const void* e0, const void* e1) { int i0 = *((int*) e0); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/libUpcalls.c b/test/micro/org/openjdk/bench/java/lang/foreign/libUpcalls.c index 220a890a812..fa534bca54f 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/libUpcalls.c +++ b/test/micro/org/openjdk/bench/java/lang/foreign/libUpcalls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 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 @@ -21,11 +21,7 @@ * questions. */ -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif +#include "export.h" EXPORT void blank(void (*cb)(void)) { cb(); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/points/support/libPoint.c b/test/micro/org/openjdk/bench/java/lang/foreign/points/support/libPoint.c index 5d4a23a8d6f..5e1913e2aa7 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/points/support/libPoint.c +++ b/test/micro/org/openjdk/bench/java/lang/foreign/points/support/libPoint.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 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 @@ -20,17 +20,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -#include + #include +#include +#include "export.h" #include "points.h" -#ifdef _WIN64 -#define EXPORT __declspec(dllexport) -#else -#define EXPORT -#endif - EXPORT double distance(Point p1, Point p2) { int xDist = abs(p1.x - p2.x); int yDist = abs(p1.y - p2.y);