diff --git a/.github/workflows/build-alpine-linux.yml b/.github/workflows/build-alpine-linux.yml index 0d366a4bdd0..a39b342a248 100644 --- a/.github/workflows/build-alpine-linux.yml +++ b/.github/workflows/build-alpine-linux.yml @@ -59,7 +59,7 @@ on: jobs: build-linux: name: build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 container: image: alpine:3.20 diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml index b3c63f488a0..e70937f57b6 100644 --- a/.github/workflows/build-cross-compile.yml +++ b/.github/workflows/build-cross-compile.yml @@ -48,7 +48,7 @@ on: jobs: build-cross-compile: name: build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index f398625cb2c..0680dea6bbe 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -75,7 +75,7 @@ on: jobs: build-linux: name: build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false @@ -115,9 +115,21 @@ jobs: if [[ '${{ inputs.apt-architecture }}' != '' ]]; then sudo dpkg --add-architecture ${{ inputs.apt-architecture }} fi - sudo apt-get update - sudo apt-get install --only-upgrade apt - sudo apt-get install gcc-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} g++-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} libxrandr-dev${{ steps.arch.outputs.suffix }} libxtst-dev${{ steps.arch.outputs.suffix }} libcups2-dev${{ steps.arch.outputs.suffix }} libasound2-dev${{ steps.arch.outputs.suffix }} ${{ inputs.apt-extra-packages }} + sudo apt update + sudo apt install --only-upgrade apt + sudo apt install \ + gcc-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} \ + g++-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} \ + libasound2-dev${{ steps.arch.outputs.suffix }} \ + libcups2-dev${{ steps.arch.outputs.suffix }} \ + libfontconfig1-dev${{ steps.arch.outputs.suffix }} \ + libx11-dev${{ steps.arch.outputs.suffix }} \ + libxext-dev${{ steps.arch.outputs.suffix }} \ + libxrandr-dev${{ steps.arch.outputs.suffix }} \ + libxrender-dev${{ steps.arch.outputs.suffix }} \ + libxt-dev${{ steps.arch.outputs.suffix }} \ + libxtst-dev${{ steps.arch.outputs.suffix }} \ + ${{ inputs.apt-extra-packages }} sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${{ inputs.gcc-major-version }} 100 --slave /usr/bin/g++ g++ /usr/bin/g++-${{ inputs.gcc-major-version }} - name: 'Configure' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4d1e8a8be3d..09e6ed65a47 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,7 +57,7 @@ jobs: prepare: name: 'Prepare the run' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 env: # List of platforms to exclude by default EXCLUDED_PLATFORMS: 'alpine-linux-x64' @@ -405,7 +405,7 @@ jobs: with: platform: linux-x64 bootjdk-platform: linux-x64 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} debug-suffix: -debug @@ -419,7 +419,7 @@ jobs: with: platform: linux-x64 bootjdk-platform: linux-x64 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} static-suffix: "-static" diff --git a/.jcheck/conf b/.jcheck/conf index 60881e74d2a..25af49f8ef8 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -1,7 +1,7 @@ [general] project=jdk jbs=JDK -version=26 +version=27 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists,copyright diff --git a/bin/generate-symbol-data.sh b/bin/generate-symbol-data.sh index 283757a6918..14d8763ad81 100644 --- a/bin/generate-symbol-data.sh +++ b/bin/generate-symbol-data.sh @@ -38,7 +38,7 @@ # directory. # - open a terminal program and run these commands: # cd "${JDK_CHECKOUT}"/src/jdk.compiler/share/data/symbols -# bash ../../../../../make/scripts/generate-symbol-data.sh "${JDK_N_INSTALL}" +# bash ../../../../../bin/generate-symbol-data.sh "${JDK_N_INSTALL}" # - this command will generate or update data for "--release N" into the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols # directory, updating all registration necessary. If the goal was to update the data, and there are no # new or changed files in the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols directory after running this script, diff --git a/doc/building.html b/doc/building.html index 19313ebf43a..8e5a7625371 100644 --- a/doc/building.html +++ b/doc/building.html @@ -541,6 +541,11 @@ href="#apple-xcode">Apple Xcode on some strategies to deal with this.

It is recommended that you use at least macOS 14 and Xcode 15.4, but earlier versions may also work.

+

Starting with Xcode 26, introduced in macOS 26, the Metal toolchain +no longer comes bundled with Xcode, so it needs to be installed +separately. This can either be done via the Xcode's Settings/Components +UI, or in the command line calling +xcodebuild -downloadComponent metalToolchain.

The standard macOS environment contains the basic tooling needed to build, but for external libraries a package manager is recommended. The JDK uses homebrew in the examples, but diff --git a/doc/building.md b/doc/building.md index 1fbd395a9d1..b626027f101 100644 --- a/doc/building.md +++ b/doc/building.md @@ -352,6 +352,11 @@ on some strategies to deal with this. It is recommended that you use at least macOS 14 and Xcode 15.4, but earlier versions may also work. +Starting with Xcode 26, introduced in macOS 26, the Metal toolchain no longer +comes bundled with Xcode, so it needs to be installed separately. This can +either be done via the Xcode's Settings/Components UI, or in the command line +calling `xcodebuild -downloadComponent metalToolchain`. + The standard macOS environment contains the basic tooling needed to build, but for external libraries a package manager is recommended. The JDK uses [homebrew](https://brew.sh/) in the examples, but feel free to use whatever diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index a2ffb57e5a3..362245cd00a 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -1037,8 +1037,8 @@ running destructors at exit can lead to problems.

Some of the approaches used in HotSpot to avoid dynamic initialization include:

diff --git a/doc/starting-next-release.md b/doc/starting-next-release.md index 10bc364a3e4..5bb9c5839a4 100644 --- a/doc/starting-next-release.md +++ b/doc/starting-next-release.md @@ -65,4 +65,4 @@ to be updated for a particular release. * `test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java` update annotation processor extended by `javac` tests to cover the new source version * `test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out` and `test/langtools/tools/javac/preview/classReaderTest/Client.preview.out`: update expected messages for preview errors and warnings - +* `test/langtools/tools/javac/versions/Versions.java`: add new source version to the set of valid sources and add new enum constant for the new class file version. diff --git a/make/Bundles.gmk b/make/Bundles.gmk index cf3b77e4e52..8161b3b0362 100644 --- a/make/Bundles.gmk +++ b/make/Bundles.gmk @@ -125,13 +125,6 @@ define SetupBundleFileBody && $(TAR) cf - -$(TAR_INCLUDE_PARAM) $$($1_$$d_LIST_FILE) \ $(TAR_IGNORE_EXIT_VALUE) ) \ | ( $(CD) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) && $(TAR) xf - )$$(NEWLINE) ) - # Rename stripped pdb files - ifeq ($(call isTargetOs, windows)+$(SHIP_DEBUG_SYMBOLS), true+public) - for f in `$(FIND) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) -name "*.stripped.pdb"`; do \ - $(ECHO) Renaming $$$${f} to $$$${f%stripped.pdb}pdb $(LOG_INFO); \ - $(MV) $$$${f} $$$${f%stripped.pdb}pdb; \ - done - endif # Unzip any zipped debuginfo files ifeq ($$($1_UNZIP_DEBUGINFO), true) for f in `$(FIND) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) -name "*.diz"`; do \ @@ -222,14 +215,6 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) ifeq ($(call isTargetOs, windows), true) ifeq ($(SHIP_DEBUG_SYMBOLS), ) JDK_SYMBOLS_EXCLUDE_PATTERN := %.pdb - else - ifeq ($(SHIP_DEBUG_SYMBOLS), public) - JDK_SYMBOLS_EXCLUDE_PATTERN := \ - $(filter-out \ - %.stripped.pdb, \ - $(filter %.pdb, $(ALL_JDK_FILES)) \ - ) - endif endif endif @@ -244,10 +229,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) ) JDK_SYMBOLS_BUNDLE_FILES := \ - $(filter-out \ - %.stripped.pdb, \ - $(call FindFiles, $(SYMBOLS_IMAGE_DIR)) \ - ) + $(call FindFiles, $(SYMBOLS_IMAGE_DIR)) TEST_DEMOS_BUNDLE_FILES := $(filter $(JDK_DEMOS_IMAGE_HOMEDIR)/demo/%, \ $(ALL_JDK_DEMOS_FILES)) @@ -267,14 +249,6 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) ifeq ($(call isTargetOs, windows), true) ifeq ($(SHIP_DEBUG_SYMBOLS), ) JRE_SYMBOLS_EXCLUDE_PATTERN := %.pdb - else - ifeq ($(SHIP_DEBUG_SYMBOLS), public) - JRE_SYMBOLS_EXCLUDE_PATTERN := \ - $(filter-out \ - %.stripped.pdb, \ - $(filter %.pdb, $(ALL_JRE_FILES)) \ - ) - endif endif endif diff --git a/make/Images.gmk b/make/Images.gmk index c5877e44c22..89c0a834477 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -282,29 +282,33 @@ else endif CMDS_TARGET_SUBDIR := bin -# Param 1 - either JDK or JRE +# Copy debug info files into symbols bundle. +# In case of Windows and --with-external-symbols-in-bundles=public, take care to remove *.stripped.pdb files SetupCopyDebuginfo = \ $(foreach m, $(ALL_$1_MODULES), \ + $(eval dbgfiles := $(call FindDebuginfoFiles, $(SUPPORT_OUTPUTDIR)/modules_libs/$m)) \ + $(eval dbgfiles := $(if $(filter true+public,$(call isTargetOs,windows)+$(SHIP_DEBUG_SYMBOLS)), \ + $(filter-out %.stripped.pdb,$(dbgfiles)),$(dbgfiles)) \ + ) \ $(eval $(call SetupCopyFiles, COPY_$1_LIBS_DEBUGINFO_$m, \ SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/$m, \ DEST := $($1_IMAGE_DIR)/$(LIBS_TARGET_SUBDIR), \ - FILES := $(call FindDebuginfoFiles, \ - $(SUPPORT_OUTPUTDIR)/modules_libs/$m), \ + FILES := $(dbgfiles), \ )) \ $(eval $1_TARGETS += $$(COPY_$1_LIBS_DEBUGINFO_$m)) \ + $(eval dbgfiles := $(call FindDebuginfoFiles, $(SUPPORT_OUTPUTDIR)/modules_cmds/$m)) \ + $(eval dbgfiles := $(if $(filter true+public,$(call isTargetOs,windows)+$(SHIP_DEBUG_SYMBOLS)), \ + $(filter-out %.stripped.pdb,$(dbgfiles)),$(dbgfiles)) \ + ) \ $(eval $(call SetupCopyFiles, COPY_$1_CMDS_DEBUGINFO_$m, \ SRC := $(SUPPORT_OUTPUTDIR)/modules_cmds/$m, \ DEST := $($1_IMAGE_DIR)/$(CMDS_TARGET_SUBDIR), \ - FILES := $(call FindDebuginfoFiles, \ - $(SUPPORT_OUTPUTDIR)/modules_cmds/$m), \ + FILES := $(dbgfiles), \ )) \ $(eval $1_TARGETS += $$(COPY_$1_CMDS_DEBUGINFO_$m)) \ ) -# No space before argument to avoid having to put $(strip ) everywhere in -# implementation above. -$(call SetupCopyDebuginfo,JDK) -$(call SetupCopyDebuginfo,JRE) +# No space before argument to avoid having to put $(strip ) everywhere in implementation above. $(call SetupCopyDebuginfo,SYMBOLS) ################################################################################ diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 1f50b97531b..946b1332edc 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -873,7 +873,7 @@ define SetupRunJtregTestBody $1_JTREG_BASIC_OPTIONS += -testThreadFactoryPath:$$(JTREG_TEST_THREAD_FACTORY_JAR) $1_JTREG_BASIC_OPTIONS += -testThreadFactory:$$(JTREG_TEST_THREAD_FACTORY) $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \ - $$(addprefix $$($1_TEST_ROOT)/, ProblemList-$$(JTREG_TEST_THREAD_FACTORY).txt) \ + $$(addprefix $$($1_TEST_ROOT)/, ProblemList-$$(JTREG_TEST_THREAD_FACTORY).txt) \ )) endif @@ -881,8 +881,8 @@ define SetupRunJtregTestBody AGENT := $$(LIBRARY_PREFIX)JvmtiStressAgent$$(SHARED_LIBRARY_SUFFIX)=$$(JTREG_JVMTI_STRESS_AGENT) $1_JTREG_BASIC_OPTIONS += -javaoption:'-agentpath:$(TEST_IMAGE_DIR)/hotspot/jtreg/native/$$(AGENT)' $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \ - $$(addprefix $$($1_TEST_ROOT)/, ProblemList-jvmti-stress-agent.txt) \ - )) + $$(addprefix $$($1_TEST_ROOT)/, ProblemList-jvmti-stress-agent.txt) \ + )) endif @@ -1092,7 +1092,7 @@ define SetupRunJtregTestBody $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR) \ $$($1_TEST_TMP_DIR)) $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, \ - $$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \ + $$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \ ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/text/stats.txt @@ -1102,11 +1102,11 @@ define SetupRunJtregTestBody $$(call LogWarn, Test report is stored in $$(strip \ $$(subst $$(TOPDIR)/, , $$($1_TEST_RESULTS_DIR)))) - # Read jtreg documentation to learn on the test stats categories: - # https://github.com/openjdk/jtreg/blob/master/src/share/doc/javatest/regtest/faq.md#what-do-all-those-numbers-in-the-test-results-line-mean - # In jtreg, "skipped:" category accounts for tests that threw jtreg.SkippedException at runtime. - # At the same time these tests contribute to "passed:" tests. - # In here we don't want that and so we substract number of "skipped:" from "passed:". + # Read jtreg documentation to learn on the test stats categories: + # https://github.com/openjdk/jtreg/blob/master/src/share/doc/javatest/regtest/faq.md#what-do-all-those-numbers-in-the-test-results-line-mean + # In jtreg, "skipped:" category accounts for tests that threw jtreg.SkippedException at runtime. + # At the same time these tests contribute to "passed:" tests. + # In here we don't want that and so we substract number of "skipped:" from "passed:". $$(if $$(wildcard $$($1_RESULT_FILE)), \ $$(eval $1_PASSED_AND_RUNTIME_SKIPPED := $$(shell $$(AWK) '{ gsub(/[,;]/, ""); \ diff --git a/make/ToolsJdk.gmk b/make/ToolsJdk.gmk index 629cadbf83a..b04d7820c91 100644 --- a/make/ToolsJdk.gmk +++ b/make/ToolsJdk.gmk @@ -79,7 +79,7 @@ TOOL_GENERATEEXTRAPROPERTIES = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_too build.tools.generateextraproperties.GenerateExtraProperties TOOL_GENERATECASEFOLDING = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ - build.tools.generatecharacter.CaseFolding + build.tools.generatecharacter.GenerateCaseFolding TOOL_MAKEZIPREPRODUCIBLE = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.makezipreproducible.MakeZipReproducible diff --git a/make/autoconf/basic.m4 b/make/autoconf/basic.m4 index 316bfc5037d..bb6908d9194 100644 --- a/make/autoconf/basic.m4 +++ b/make/autoconf/basic.m4 @@ -353,7 +353,12 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT], [set up toolchain on Mac OS using a path to an Xcode installation])]) UTIL_DEPRECATED_ARG_WITH(sys-root) - UTIL_DEPRECATED_ARG_WITH(tools-dir) + + AC_ARG_WITH([tools-dir], [AS_HELP_STRING([--with-tools-dir], + [Point to a nonstandard Visual Studio installation location on Windows by + specifying any existing directory 2 or 3 levels below the installation + root.])] + ) if test "x$with_xcode_path" != x; then if test "x$OPENJDK_BUILD_OS" = "xmacosx"; then diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index 572790b567b..b0dc565b39f 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -34,7 +34,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS], FLAGS_SETUP_LDFLAGS_CPU_DEP([TARGET]) # Setup the build toolchain - FLAGS_SETUP_LDFLAGS_CPU_DEP([BUILD], [OPENJDK_BUILD_]) + FLAGS_SETUP_LDFLAGS_CPU_DEP([BUILD], [OPENJDK_BUILD_], [BUILD_]) AC_SUBST(ADLC_LDFLAGS) ]) @@ -52,11 +52,6 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], # add --no-as-needed to disable default --as-needed link flag on some GCC toolchains # add --icf=all (Identical Code Folding — merges identical functions) BASIC_LDFLAGS="-Wl,-z,defs -Wl,-z,relro -Wl,-z,now -Wl,--no-as-needed -Wl,--exclude-libs,ALL" - if test "x$LINKER_TYPE" = "xgold"; then - if test x$DEBUG_LEVEL = xrelease; then - BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,--icf=all" - fi - fi # Linux : remove unused code+data in link step if test "x$ENABLE_LINKTIME_GC" = xtrue; then @@ -108,6 +103,9 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], # Setup OS-dependent LDFLAGS if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$TOOLCHAIN_TYPE" = xclang; then + if test x$DEBUG_LEVEL = xrelease; then + BASIC_LDFLAGS_JDK_ONLY="$BASIC_LDFLAGS_JDK_ONLY -Wl,-dead_strip" + fi # FIXME: We should really generalize SetSharedLibraryOrigin instead. OS_LDFLAGS_JVM_ONLY="-Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." OS_LDFLAGS="-mmacosx-version-min=$MACOSX_VERSION_MIN -Wl,-reproducible" @@ -166,7 +164,8 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], ################################################################################ # $1 - Either BUILD or TARGET to pick the correct OS/CPU variables to check # conditionals against. -# $2 - Optional prefix for each variable defined. +# $2 - Optional prefix for each variable defined (OPENJDK_BUILD_ or nothing). +# $3 - Optional prefix for toolchain variables (BUILD_ or nothing). AC_DEFUN([FLAGS_SETUP_LDFLAGS_CPU_DEP], [ # Setup CPU-dependent basic LDFLAGS. These can differ between the target and @@ -200,6 +199,12 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_CPU_DEP], fi fi + if test "x${$3LD_TYPE}" = "xgold"; then + if test x$DEBUG_LEVEL = xrelease; then + $1_CPU_LDFLAGS="${$1_CPU_LDFLAGS} -Wl,--icf=all" + fi + fi + # Export variables according to old definitions, prefix with $2 if present. LDFLAGS_JDK_COMMON="$BASIC_LDFLAGS $BASIC_LDFLAGS_JDK_ONLY \ $OS_LDFLAGS $DEBUGLEVEL_LDFLAGS_JDK_ONLY ${$2EXTRA_LDFLAGS}" diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 15210efe4a7..c882deb10a7 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -516,7 +516,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_LD_VERSION], if [ [[ "$LINKER_VERSION_STRING" == *gold* ]] ]; then [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \ $SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*) .*/\1/'` ] - LINKER_TYPE=gold + $1_TYPE=gold else [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \ $SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*/\1/'` ] diff --git a/make/common/native/Flags.gmk b/make/common/native/Flags.gmk index 843701cb4db..efb4c08e74c 100644 --- a/make/common/native/Flags.gmk +++ b/make/common/native/Flags.gmk @@ -229,6 +229,11 @@ define SetupLinkerFlags # TOOLCHAIN_TYPE plus OPENJDK_TARGET_OS ifeq ($$($1_LINK_TIME_OPTIMIZATION), true) $1_EXTRA_LDFLAGS += $(LDFLAGS_LTO) + # Instruct the ld64 linker not to delete the temporary object file + # generated during Link Time Optimization + ifeq ($(call isTargetOs, macosx), true) + $1_EXTRA_LDFLAGS += -Wl,-object_path_lto,$$($1_OBJECT_DIR)/$$($1_NAME)_lto_helper.o + endif endif $1_EXTRA_LDFLAGS += $$($1_LDFLAGS_$(OPENJDK_TARGET_OS_TYPE)) $$($1_LDFLAGS_$(OPENJDK_TARGET_OS)) \ diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index 977809535ba..4392d86ac33 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -26,17 +26,17 @@ # Default version, product, and vendor information to use, # unless overridden by configure -DEFAULT_VERSION_FEATURE=26 +DEFAULT_VERSION_FEATURE=27 DEFAULT_VERSION_INTERIM=0 DEFAULT_VERSION_UPDATE=0 DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2026-03-17 -DEFAULT_VERSION_CLASSFILE_MAJOR=70 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" +DEFAULT_VERSION_DATE=2026-09-15 +DEFAULT_VERSION_CLASSFILE_MAJOR=71 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 -DEFAULT_ACCEPTABLE_BOOT_VERSIONS="25 26" -DEFAULT_JDK_SOURCE_TARGET_VERSION=26 +DEFAULT_ACCEPTABLE_BOOT_VERSIONS="25 26 27" +DEFAULT_JDK_SOURCE_TARGET_VERSION=27 DEFAULT_PROMOTED_VERSION_PRE=ea diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index b0ea27e5081..39a549b7db0 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -151,6 +151,12 @@ JVM_STRIPFLAGS ?= $(STRIPFLAGS) # This source set is reused so save in cache. $(call FillFindCache, $(JVM_SRC_DIRS)) +ifeq ($(SHIP_DEBUG_SYMBOLS), full) + CFLAGS_SHIP_DEBUGINFO := -DSHIP_DEBUGINFO_FULL +else ifeq ($(SHIP_DEBUG_SYMBOLS), public) + CFLAGS_SHIP_DEBUGINFO := -DSHIP_DEBUGINFO_PUBLIC +endif + ifeq ($(call isTargetOs, windows), true) ifeq ($(STATIC_LIBS), true) WIN_EXPORT_FILE := $(JVM_OUTPUTDIR)/static-win-exports.def @@ -158,10 +164,6 @@ ifeq ($(call isTargetOs, windows), true) WIN_EXPORT_FILE := $(JVM_OUTPUTDIR)/win-exports.def endif - ifeq ($(SHIP_DEBUG_SYMBOLS), public) - CFLAGS_STRIPPED_DEBUGINFO := -DHAS_STRIPPED_DEBUGINFO - endif - JVM_LDFLAGS += -def:$(WIN_EXPORT_FILE) endif @@ -187,7 +189,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \ CFLAGS := $(JVM_CFLAGS), \ abstract_vm_version.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \ arguments.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \ - whitebox.cpp_CXXFLAGS := $(CFLAGS_STRIPPED_DEBUGINFO), \ + whitebox.cpp_CXXFLAGS := $(CFLAGS_SHIP_DEBUGINFO), \ DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc), \ DISABLED_WARNINGS_gcc_ad_$(HOTSPOT_TARGET_CPU_ARCH).cpp := nonnull, \ DISABLED_WARNINGS_gcc_bytecodeInterpreter.cpp := unused-label, \ diff --git a/make/jdk/src/classes/build/tools/generatecharacter/CaseFolding.java b/make/jdk/src/classes/build/tools/generatecharacter/CaseFolding.java deleted file mode 100644 index 9abc2059b6a..00000000000 --- a/make/jdk/src/classes/build/tools/generatecharacter/CaseFolding.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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 build.tools.generatecharacter; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class CaseFolding { - - public static void main(String[] args) throws Throwable { - if (args.length != 3) { - System.err.println("Usage: java CaseFolding TemplateFile CaseFolding.txt CaseFolding.java"); - System.exit(1); - } - var templateFile = Paths.get(args[0]); - var caseFoldingTxt = Paths.get(args[1]); - var genSrcFile = Paths.get(args[2]); - var supportedTypes = "^.*; [CTS]; .*$"; - var caseFoldingEntries = Files.lines(caseFoldingTxt) - .filter(line -> !line.startsWith("#") && line.matches(supportedTypes)) - .map(line -> { - String[] cols = line.split("; "); - return new String[] {cols[0], cols[1], cols[2]}; - }) - .filter(cols -> { - // the folding case doesn't map back to the original char. - var cp1 = Integer.parseInt(cols[0], 16); - var cp2 = Integer.parseInt(cols[2], 16); - return Character.toUpperCase(cp2) != cp1 && Character.toLowerCase(cp2) != cp1; - }) - .map(cols -> String.format(" entry(0x%s, 0x%s)", cols[0], cols[2])) - .collect(Collectors.joining(",\n", "", "")); - - // hack, hack, hack! the logic does not pick 0131. just add manually to support 'I's. - // 0049; T; 0131; # LATIN CAPITAL LETTER I - final String T_0x0131_0x49 = String.format(" entry(0x%04x, 0x%04x),\n", 0x0131, 0x49); - - // Generate .java file - Files.write( - genSrcFile, - Files.lines(templateFile) - .map(line -> line.contains("%%%Entries") ? T_0x0131_0x49 + caseFoldingEntries : line) - .collect(Collectors.toList()), - StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - } -} diff --git a/make/jdk/src/classes/build/tools/generatecharacter/GenerateCaseFolding.java b/make/jdk/src/classes/build/tools/generatecharacter/GenerateCaseFolding.java new file mode 100644 index 00000000000..2f6a9add5cb --- /dev/null +++ b/make/jdk/src/classes/build/tools/generatecharacter/GenerateCaseFolding.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatecharacter; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class GenerateCaseFolding { + + public static void main(String[] args) throws Throwable { + if (args.length != 3) { + System.err.println("Usage: java GenerateCaseFolding TemplateFile CaseFolding.txt CaseFolding.java"); + System.exit(1); + } + var templateFile = Paths.get(args[0]); + var caseFoldingTxt = Paths.get(args[1]); + var genSrcFile = Paths.get(args[2]); + + // java.lang + var supportedTypes = "^.*; [CF]; .*$"; // full/1:M case folding + String[][] caseFoldings = Files.lines(caseFoldingTxt) + .filter(line -> !line.startsWith("#") && line.matches(supportedTypes)) + .map(line -> { + var fields = line.split("; "); + var cp = fields[0]; + fields = fields[2].trim().split(" "); + var folding = new String[fields.length + 1]; + folding[0] = cp; + System.arraycopy(fields, 0, folding, 1, fields.length); + return folding; + }) + .toArray(size -> new String[size][]); + + // util.regex + var expandedSupportedTypes = "^.*; [CTS]; .*$"; + var expanded_caseFoldingEntries = Files.lines(caseFoldingTxt) + .filter(line -> !line.startsWith("#") && line.matches(expandedSupportedTypes)) + .map(line -> { + String[] cols = line.split("; "); + return new String[]{cols[0], cols[1], cols[2]}; + }) + .filter(cols -> { + // the folding case doesn't map back to the original char. + var cp1 = Integer.parseInt(cols[0], 16); + var cp2 = Integer.parseInt(cols[2], 16); + return Character.toUpperCase(cp2) != cp1 && Character.toLowerCase(cp2) != cp1; + }) + .map(cols -> String.format(" entry(0x%s, 0x%s)", cols[0], cols[2])) + .collect(Collectors.joining(",\n", "", "")); + + // hack, hack, hack! the logic does not pick 0131. just add manually to support 'I's. + // 0049; T; 0131; # LATIN CAPITAL LETTER I + final String T_0x0131_0x49 = String.format(" entry(0x%04x, 0x%04x),\n", 0x0131, 0x49); + + Files.write( + genSrcFile, + Files.lines(templateFile) + .map(line -> line.contains("%%%Entries") ? genFoldingEntries(caseFoldings) : line) + .map(line -> line.contains("%%%Expanded_Case_Map_Entries") ? T_0x0131_0x49 + expanded_caseFoldingEntries : line) + .collect(Collectors.toList()), + StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } + + private static long foldingToLong(String[] folding) { + int cp = Integer.parseInt(folding[0], 16); + long value = (long)Integer.parseInt(folding[1], 16); + if (!Character.isSupplementaryCodePoint(cp) && folding.length != 2) { + var shift = 16; + for (int j = 2; j < folding.length; j++) { + value |= (long)Integer.parseInt(folding[j], 16) << shift; + shift <<= 1; + } + value = value | (long) (folding.length - 1) << 48; + } + return value; + } + + private static String genFoldingEntries(String[][] foldings) { + StringBuilder sb = new StringBuilder(); + sb.append(" private static final int[] CASE_FOLDING_CPS = {\n"); + int width = 10; + for (int i = 0; i < foldings.length; i++) { + if (i % width == 0) + sb.append(" "); + sb.append(String.format("0X%s", foldings[i][0])); + if (i < foldings.length - 1) + sb.append(", "); + if (i % width == width - 1 || i == foldings.length - 1) + sb.append("\n"); + } + sb.append(" };\n\n"); + + sb.append(" private static final long[] CASE_FOLDING_VALUES = {\n"); + width = 6; + for (int i = 0; i < foldings.length; i++) { + if (i % width == 0) + sb.append(" "); // indent + sb.append(String.format("0x%013xL", foldingToLong(foldings[i]))); + if (i < foldings.length - 1) + sb.append(", "); + if (i % width == width - 1 || i == foldings.length - 1) { + sb.append("\n"); + } + } + sb.append(" };\n"); + return sb.toString(); + } +} diff --git a/make/modules/java.base/Gensrc.gmk b/make/modules/java.base/Gensrc.gmk index 79db438934e..e8236f0b0e4 100644 --- a/make/modules/java.base/Gensrc.gmk +++ b/make/modules/java.base/Gensrc.gmk @@ -120,3 +120,25 @@ $(INTPOLY_GEN_DONE): $(INTPLOY_HEADER) $(BUILD_TOOLS_JDK) TARGETS += $(INTPOLY_GEN_DONE) ################################################################################ + +RELEASE_FILE_TEMPLATE := $(TOPDIR)/src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template +RELEASE_FILE_TARGET := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/jdk/internal/misc/resources/release.txt + +RELEASE_FILE_VARDEPS := $(COMPANY_NAME) $(VERSION_STRING) $(VERSION_DATE) +RELEASE_FILE_VARDEPS_FILE := $(call DependOnVariable, RELEASE_FILE_VARDEPS, \ + $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/jlink_release_txt.vardeps) + +$(eval $(call SetupTextFileProcessing, BUILD_RELEASE_FILE, \ + SOURCE_FILES := $(RELEASE_FILE_TEMPLATE), \ + OUTPUT_FILE := $(RELEASE_FILE_TARGET), \ + REPLACEMENTS := \ + @@COMPANY_NAME@@ => $(COMPANY_NAME) ; \ + @@VERSION_STRING@@ => $(VERSION_STRING) ; \ + @@VERSION_DATE@@ => $(VERSION_DATE) , \ +)) + +$(BUILD_RELEASE_FILE): $(RELEASE_FILE_VARDEPS_FILE) + +TARGETS += $(BUILD_RELEASE_FILE) + +################################################################################ diff --git a/make/modules/java.base/Java.gmk b/make/modules/java.base/Java.gmk index fc091377456..e20db38297d 100644 --- a/make/modules/java.base/Java.gmk +++ b/make/modules/java.base/Java.gmk @@ -34,7 +34,7 @@ DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' JAVAC_FLAGS += -XDstringConcat=inline -COPY += .icu .dat .spp .nrm content-types.properties \ +COPY += .icu .dat .spp .nrm .txt content-types.properties \ hijrah-config-Hijrah-umalqura_islamic-umalqura.properties CLEAN += intrinsic.properties diff --git a/make/modules/java.base/gensrc/GensrcCharacterData.gmk b/make/modules/java.base/gensrc/GensrcCharacterData.gmk index c05b126299b..d7947d907e2 100644 --- a/make/modules/java.base/gensrc/GensrcCharacterData.gmk +++ b/make/modules/java.base/gensrc/GensrcCharacterData.gmk @@ -72,5 +72,22 @@ TARGETS += $(GENSRC_CHARACTERDATA) ################################################################################ + +GENSRC_STRINGCASEFOLDING := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/lang/CaseFolding.java + +STRINGCASEFOLDING_TEMPLATE := $(MODULE_SRC)/share/classes/jdk/internal/lang/CaseFolding.java.template +CASEFOLDINGTXT := $(MODULE_SRC)/share/data/unicodedata/CaseFolding.txt + +$(GENSRC_STRINGCASEFOLDING): $(BUILD_TOOLS_JDK) $(STRINGCASEFOLDING_TEMPLATE) $(CASEFOLDINGTXT) + $(call LogInfo, Generating $@) + $(call MakeTargetDir) + $(TOOL_GENERATECASEFOLDING) \ + $(STRINGCASEFOLDING_TEMPLATE) \ + $(CASEFOLDINGTXT) \ + $(GENSRC_STRINGCASEFOLDING) + +TARGETS += $(GENSRC_STRINGCASEFOLDING) + + endif # include guard include MakeIncludeEnd.gmk diff --git a/make/modules/java.base/gensrc/GensrcRegex.gmk b/make/modules/java.base/gensrc/GensrcRegex.gmk index a30f22b34d4..c46a029e2c2 100644 --- a/make/modules/java.base/gensrc/GensrcRegex.gmk +++ b/make/modules/java.base/gensrc/GensrcRegex.gmk @@ -50,22 +50,5 @@ TARGETS += $(GENSRC_INDICCONJUNCTBREAK) ################################################################################ -GENSRC_CASEFOLDING := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/util/regex/CaseFolding.java - -CASEFOLDINGTEMP := $(MODULE_SRC)/share/classes/jdk/internal/util/regex/CaseFolding.java.template -CASEFOLDINGTXT := $(MODULE_SRC)/share/data/unicodedata/CaseFolding.txt - -$(GENSRC_CASEFOLDING): $(BUILD_TOOLS_JDK) $(CASEFOLDINGTEMP) $(CASEFOLDINGTXT) - $(call LogInfo, Generating $@) - $(call MakeTargetDir) - $(TOOL_GENERATECASEFOLDING) \ - $(CASEFOLDINGTEMP) \ - $(CASEFOLDINGTXT) \ - $(GENSRC_CASEFOLDING) - -TARGETS += $(GENSRC_CASEFOLDING) - -################################################################################ - endif # include guard include MakeIncludeEnd.gmk diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index 4cd7f5bac90..f273065a6df 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -164,6 +164,24 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) ifeq ($(USE_EXTERNAL_LIBPNG), false) LIBSPLASHSCREEN_HEADER_DIRS += libsplashscreen/libpng + LIBSPLASHSCREEN_CFLAGS += -DPNG_NO_MMX_CODE -DPNG_ARM_NEON_OPT=0 + -DPNG_ARM_NEON_IMPLEMENTATION=0 -DPNG_LOONGARCH_LSX_OPT=0 + + ifeq ($(call isTargetOs, linux)+$(call isTargetCpuArch, ppc), true+true) + LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0 + endif + + # The libpng bundled with jdk is a reduced version which does not + # contain .png_init_filter_functions_vsx. + # Therefore we need to disable PNG_POWERPC_VSX_OPT explicitly by setting + # it to 0. If this define is not set, it would be automatically set to 2, + # because + # "#if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__)" + # expands to true. This would results in the fact that + # .png_init_filter_functions_vsx is needed in libpng. + ifeq ($(call isTargetOs, aix), true) + LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0 + endif else LIBSPLASHSCREEN_EXCLUDES += libpng endif @@ -176,25 +194,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) LIBSPLASHSCREEN_STATIC_LIB_EXCLUDE_OBJS += $(LIBZIP_OBJS) endif - LIBSPLASHSCREEN_CFLAGS += -DSPLASHSCREEN -DPNG_NO_MMX_CODE \ - -DPNG_ARM_NEON_OPT=0 -DPNG_ARM_NEON_IMPLEMENTATION=0 \ - -DPNG_LOONGARCH_LSX_OPT=0 - - ifeq ($(call isTargetOs, linux)+$(call isTargetCpuArch, ppc), true+true) - LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0 - endif - - # The external libpng submitted in the jdk is a reduced version - # which does not contain .png_init_filter_functions_vsx. - # Therefore we need to disable PNG_POWERPC_VSX_OPT explicitly by setting - # it to 0. If this define is not set, it would be automatically set to 2, - # because - # "#if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__)" - # expands to true. This would results in the fact that - # .png_init_filter_functions_vsx is needed in libpng. - ifeq ($(call isTargetOs, aix), true) - LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0 - endif + LIBSPLASHSCREEN_CFLAGS += -DSPLASHSCREEN ifeq ($(call isTargetOs, macosx), true) # libsplashscreen on macosx does not use the unix code diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 9c76ed24788..b9252cc56ff 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2003,6 +2003,9 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r if (bottom_type()->isa_vect() && !bottom_type()->isa_vectmask()) { uint ireg = ideal_reg(); + DEBUG_ONLY(int algm = MIN2(RegMask::num_registers(ireg), (int)Matcher::stack_alignment_in_slots()) * VMRegImpl::stack_slot_size); + assert((src_lo_rc != rc_stack) || is_aligned(src_offset, algm), "unaligned vector spill sp offset %d (src)", src_offset); + assert((dst_lo_rc != rc_stack) || is_aligned(dst_offset, algm), "unaligned vector spill sp offset %d (dst)", dst_offset); if (ireg == Op_VecA && masm) { int sve_vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { diff --git a/src/hotspot/cpu/aarch64/aarch64_atomic.ad b/src/hotspot/cpu/aarch64/aarch64_atomic.ad index faac2a43110..3b05a637215 100644 --- a/src/hotspot/cpu/aarch64/aarch64_atomic.ad +++ b/src/hotspot/cpu/aarch64/aarch64_atomic.ad @@ -695,7 +695,7 @@ instruct getAndSetP(indirect mem, iRegP newval, iRegPNoSp oldval) %{ instruct getAndSetIAcq(indirect mem, iRegI newval, iRegINoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set oldval (GetAndSetI mem newval)); - ins_cost(2*VOLATILE_REF_COST); + ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchgw_acq $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchgalw($oldval$$Register, $newval$$Register, as_Register($mem$$base)); @@ -706,7 +706,7 @@ instruct getAndSetIAcq(indirect mem, iRegI newval, iRegINoSp oldval) %{ instruct getAndSetLAcq(indirect mem, iRegL newval, iRegLNoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set oldval (GetAndSetL mem newval)); - ins_cost(2*VOLATILE_REF_COST); + ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchg_acq $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchgal($oldval$$Register, $newval$$Register, as_Register($mem$$base)); @@ -717,7 +717,7 @@ instruct getAndSetLAcq(indirect mem, iRegL newval, iRegLNoSp oldval) %{ instruct getAndSetNAcq(indirect mem, iRegN newval, iRegNNoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set oldval (GetAndSetN mem newval)); - ins_cost(2*VOLATILE_REF_COST); + ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchgw_acq $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchgalw($oldval$$Register, $newval$$Register, as_Register($mem$$base)); @@ -728,7 +728,7 @@ instruct getAndSetNAcq(indirect mem, iRegN newval, iRegNNoSp oldval) %{ instruct getAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); match(Set oldval (GetAndSetP mem newval)); - ins_cost(2*VOLATILE_REF_COST); + ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchg_acq $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchgal($oldval$$Register, $newval$$Register, as_Register($mem$$base)); diff --git a/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 index 721b720873a..dc51754e7f9 100644 --- a/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 @@ -187,7 +187,7 @@ ifelse($1$3,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_Lo $3,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), `dnl') match(Set oldval (GetAndSet$1 mem newval)); - ins_cost(`'ifelse($4,Acq,,2*)VOLATILE_REF_COST); + ins_cost(`'ifelse($3,Acq,,2*)VOLATILE_REF_COST); format %{ "atomic_xchg$2`'ifelse($3,Acq,_acq) $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchg`'ifelse($3,Acq,al)$2($oldval$$Register, $newval$$Register, as_Register($mem$$base)); diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 94694b58d2f..dbec2d76d4f 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -85,7 +85,7 @@ void Relocation::pd_set_call_destination(address x) { } else { MacroAssembler::pd_patch_instruction(addr(), x); } - assert(pd_call_destination(addr()) == x, "fail in reloc"); + guarantee(pd_call_destination(addr()) == x, "fail in reloc"); } void trampoline_stub_Relocation::pd_fix_owner_after_move() { diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 8dbc5dbac03..7e2f333ba40 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -2879,7 +2879,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKe (key) in little endian int array // address generate_aescrypt_encryptBlock() { __ align(CodeEntryAlignment); @@ -2912,7 +2912,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKd (key) in little endian int array // address generate_aescrypt_decryptBlock() { assert(UseAES, "need AES cryptographic extension support"); @@ -2946,7 +2946,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKe (key) in little endian int array // c_rarg3 - r vector byte array address // c_rarg4 - input length // @@ -3051,7 +3051,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKd (key) in little endian int array // c_rarg3 - r vector byte array address // c_rarg4 - input length // @@ -3178,7 +3178,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKe (key) in little endian int array // c_rarg3 - counter vector byte array address // c_rarg4 - input length // c_rarg5 - saved encryptedCounter start diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 87fcf112756..2a0a9149bb3 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -1795,10 +1795,13 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r return size; // Self copy, no move. if (bottom_type()->isa_vect() != nullptr && ideal_reg() == Op_VecX) { + int src_offset = ra_->reg2offset(src_lo); + int dst_offset = ra_->reg2offset(dst_lo); + DEBUG_ONLY(int algm = MIN2(RegMask::num_registers(ideal_reg()), (int)Matcher::stack_alignment_in_slots()) * VMRegImpl::stack_slot_size); + assert((src_lo_rc != rc_stack) || is_aligned(src_offset, algm), "unaligned vector spill sp offset %d (src)", src_offset); + assert((dst_lo_rc != rc_stack) || is_aligned(dst_offset, algm), "unaligned vector spill sp offset %d (dst)", dst_offset); // Memory->Memory Spill. if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { - int src_offset = ra_->reg2offset(src_lo); - int dst_offset = ra_->reg2offset(dst_lo); if (masm) { __ ld(R0, src_offset, R1_SP); __ std(R0, dst_offset, R1_SP); @@ -1806,26 +1809,20 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r __ std(R0, dst_offset+8, R1_SP); } size += 16; +#ifndef PRODUCT + if (st != nullptr) { + st->print("%-7s [R1_SP + #%d] -> [R1_SP + #%d] \t// vector spill copy", "SPILL", src_offset, dst_offset); + } +#endif // !PRODUCT } // VectorRegister->Memory Spill. else if (src_lo_rc == rc_vec && dst_lo_rc == rc_stack) { VectorSRegister Rsrc = as_VectorRegister(Matcher::_regEncode[src_lo]).to_vsr(); - int dst_offset = ra_->reg2offset(dst_lo); if (PowerArchitecturePPC64 >= 9) { - if (is_aligned(dst_offset, 16)) { - if (masm) { - __ stxv(Rsrc, dst_offset, R1_SP); // matches storeV16_Power9 - } - size += 4; - } else { - // Other alignment can be used by Vector API (VectorPayload in rearrangeOp, - // observed with VectorRearrangeTest.java on Power9). - if (masm) { - __ addi(R0, R1_SP, dst_offset); - __ stxvx(Rsrc, R0); // matches storeV16_Power9 (regarding element ordering) - } - size += 8; + if (masm) { + __ stxv(Rsrc, dst_offset, R1_SP); // matches storeV16_Power9 } + size += 4; } else { if (masm) { __ addi(R0, R1_SP, dst_offset); @@ -1833,24 +1830,25 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r } size += 8; } +#ifndef PRODUCT + if (st != nullptr) { + if (PowerArchitecturePPC64 >= 9) { + st->print("%-7s %s, [R1_SP + #%d] \t// vector spill copy", "STXV", Matcher::regName[src_lo], dst_offset); + } else { + st->print("%-7s R0, R1_SP, %d \t// vector spill copy\n\t" + "%-7s %s, [R0] \t// vector spill copy", "ADDI", dst_offset, "STXVD2X", Matcher::regName[src_lo]); + } + } +#endif // !PRODUCT } // Memory->VectorRegister Spill. else if (src_lo_rc == rc_stack && dst_lo_rc == rc_vec) { VectorSRegister Rdst = as_VectorRegister(Matcher::_regEncode[dst_lo]).to_vsr(); - int src_offset = ra_->reg2offset(src_lo); if (PowerArchitecturePPC64 >= 9) { - if (is_aligned(src_offset, 16)) { - if (masm) { - __ lxv(Rdst, src_offset, R1_SP); - } - size += 4; - } else { - if (masm) { - __ addi(R0, R1_SP, src_offset); - __ lxvx(Rdst, R0); - } - size += 8; + if (masm) { + __ lxv(Rdst, src_offset, R1_SP); } + size += 4; } else { if (masm) { __ addi(R0, R1_SP, src_offset); @@ -1858,6 +1856,16 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r } size += 8; } +#ifndef PRODUCT + if (st != nullptr) { + if (PowerArchitecturePPC64 >= 9) { + st->print("%-7s %s, [R1_SP + #%d] \t// vector spill copy", "LXV", Matcher::regName[dst_lo], src_offset); + } else { + st->print("%-7s R0, R1_SP, %d \t// vector spill copy\n\t" + "%-7s %s, [R0] \t// vector spill copy", "ADDI", src_offset, "LXVD2X", Matcher::regName[dst_lo]); + } + } +#endif // !PRODUCT } // VectorRegister->VectorRegister. else if (src_lo_rc == rc_vec && dst_lo_rc == rc_vec) { @@ -1867,6 +1875,12 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r __ xxlor(Rdst, Rsrc, Rsrc); } size += 4; +#ifndef PRODUCT + if (st != nullptr) { + st->print("%-7s %s, %s, %s\t// vector spill copy", + "XXLOR", Matcher::regName[dst_lo], Matcher::regName[src_lo], Matcher::regName[src_lo]); + } +#endif // !PRODUCT } else { ShouldNotReachHere(); // No VR spill. @@ -6321,8 +6335,36 @@ instruct loadConD_Ex(regD dst, immD src) %{ // Prefetch instructions. // Must be safe to execute with invalid address (cannot fault). +// Special prefetch versions which use the dcbz instruction. +instruct prefetch_alloc_zero(indirectMemory mem, iRegLsrc src) %{ + match(PrefetchAllocation (AddP mem src)); + predicate(AllocatePrefetchStyle == 3); + ins_cost(MEMORY_REF_COST); + + format %{ "PREFETCH $mem, 2, $src \t// Prefetch write-many with zero" %} + size(4); + ins_encode %{ + __ dcbz($src$$Register, $mem$$base$$Register); + %} + ins_pipe(pipe_class_memory); +%} + +instruct prefetch_alloc_zero_no_offset(indirectMemory mem) %{ + match(PrefetchAllocation mem); + predicate(AllocatePrefetchStyle == 3); + ins_cost(MEMORY_REF_COST); + + format %{ "PREFETCH $mem, 2 \t// Prefetch write-many with zero" %} + size(4); + ins_encode %{ + __ dcbz($mem$$base$$Register); + %} + ins_pipe(pipe_class_memory); +%} + instruct prefetch_alloc(indirectMemory mem, iRegLsrc src) %{ match(PrefetchAllocation (AddP mem src)); + predicate(AllocatePrefetchStyle != 3); ins_cost(MEMORY_REF_COST); format %{ "PREFETCH $mem, 2, $src \t// Prefetch write-many" %} @@ -6335,6 +6377,7 @@ instruct prefetch_alloc(indirectMemory mem, iRegLsrc src) %{ instruct prefetch_alloc_no_offset(indirectMemory mem) %{ match(PrefetchAllocation mem); + predicate(AllocatePrefetchStyle != 3); ins_cost(MEMORY_REF_COST); format %{ "PREFETCH $mem, 2 \t// Prefetch write-many" %} diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 948092bbb9a..e48778a8b9f 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -2956,7 +2956,7 @@ class StubGenerator: public StubCodeGenerator { // Arguments for generated stub: // R3_ARG1 - source byte array address // R4_ARG2 - destination byte array address - // R5_ARG3 - K (key) in little endian int array + // R5_ARG3 - sessionKe (key) in little endian int array address generate_aescrypt_decryptBlock() { assert(UseAES, "need AES instructions and misaligned SSE support"); StubId stub_id = StubId::stubgen_aescrypt_decryptBlock_id; diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index e5eb15cb8e4..d0cbe8ea347 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2463,7 +2463,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKe (key) in little endian int array // address generate_aescrypt_encryptBlock() { assert(UseAESIntrinsics, "need AES instructions (Zvkned extension) support"); @@ -2493,8 +2493,8 @@ class StubGenerator: public StubCodeGenerator { __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); __ vle32_v(res, from); - __ mv(t2, 52); - __ blt(keylen, t2, L_aes128); + __ mv(t2, 52); // key length could be only {11, 13, 15} * 4 = {44, 52, 60} + __ bltu(keylen, t2, L_aes128); __ beq(keylen, t2, L_aes192); // Else we fallthrough to the biggest case (256-bit key size) @@ -2542,7 +2542,7 @@ class StubGenerator: public StubCodeGenerator { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address - // c_rarg2 - K (key) in little endian int array + // c_rarg2 - sessionKe (key) in little endian int array // address generate_aescrypt_decryptBlock() { assert(UseAESIntrinsics, "need AES instructions (Zvkned extension) support"); @@ -2572,8 +2572,8 @@ class StubGenerator: public StubCodeGenerator { __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); __ vle32_v(res, from); - __ mv(t2, 52); - __ blt(keylen, t2, L_aes128); + __ mv(t2, 52); // key length could be only {11, 13, 15} * 4 = {44, 52, 60} + __ bltu(keylen, t2, L_aes128); __ beq(keylen, t2, L_aes192); // Else we fallthrough to the biggest case (256-bit key size) @@ -2606,6 +2606,223 @@ class StubGenerator: public StubCodeGenerator { return start; } + // Load big-endian 128-bit from memory. + void be_load_counter_128(Register counter_hi, Register counter_lo, Register counter) { + __ ld(counter_lo, Address(counter, 8)); // Load 128-bits from counter + __ ld(counter_hi, Address(counter)); + __ rev8(counter_lo, counter_lo); // Convert big-endian to little-endian + __ rev8(counter_hi, counter_hi); + } + + // Little-endian 128-bit + 64-bit -> 128-bit addition. + void add_counter_128(Register counter_hi, Register counter_lo) { + assert_different_registers(counter_hi, counter_lo, t0); + __ addi(counter_lo, counter_lo, 1); + __ seqz(t0, counter_lo); // Check for result overflow + __ add(counter_hi, counter_hi, t0); // Add 1 if overflow otherwise 0 + } + + // Store big-endian 128-bit to memory. + void be_store_counter_128(Register counter_hi, Register counter_lo, Register counter) { + assert_different_registers(counter_hi, counter_lo, t0, t1); + __ rev8(t0, counter_lo); // Convert little-endian to big-endian + __ rev8(t1, counter_hi); + __ sd(t0, Address(counter, 8)); // Store 128-bits to counter + __ sd(t1, Address(counter)); + } + + void counterMode_AESCrypt(int round, Register in, Register out, Register key, Register counter, + Register input_len, Register saved_encrypted_ctr, Register used_ptr) { + // Algorithm: + // + // generate_aes_loadkeys(); + // load_counter_128(counter_hi, counter_lo, counter); + // + // L_next: + // if (used >= BLOCK_SIZE) goto L_main_loop; + // + // L_encrypt_next: + // *out = *in ^ saved_encrypted_ctr[used]); + // out++; in++; used++; len--; + // if (len == 0) goto L_exit; + // goto L_next; + // + // L_main_loop: + // if (len == 0) goto L_exit; + // saved_encrypted_ctr = generate_aes_encrypt(counter); + // + // add_counter_128(counter_hi, counter_lo); + // be_store_counter_128(counter_hi, counter_lo, counter); + // used = 0; + // + // if(len < BLOCK_SIZE) goto L_encrypt_next; + // + // v_in = load_16Byte(in); + // v_out = load_16Byte(out); + // v_saved_encrypted_ctr = load_16Byte(saved_encrypted_ctr); + // v_out = v_in ^ v_saved_encrypted_ctr; + // out += BLOCK_SIZE; + // in += BLOCK_SIZE; + // len -= BLOCK_SIZE; + // used = BLOCK_SIZE; + // goto L_main_loop; + // + // + // L_exit: + // store(used); + // result = input_len + // return result; + + const Register used = x28; + const Register len = x29; + const Register counter_hi = x30; + const Register counter_lo = x31; + const Register block_size = t2; + + const unsigned int BLOCK_SIZE = 16; + + VectorRegister working_vregs[] = { + v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15 + }; + + __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); + + __ lwu(used, Address(used_ptr)); + __ mv(len, input_len); + __ mv(block_size, BLOCK_SIZE); + + // load keys to working_vregs according to round + generate_aes_loadkeys(key, working_vregs, round); + + // 128-bit big-endian load + be_load_counter_128(counter_hi, counter_lo, counter); + + Label L_next, L_encrypt_next, L_main_loop, L_exit; + // Check the last saved_encrypted_ctr used value, we fall through + // to L_encrypt_next when the used value lower than block_size + __ bind(L_next); + __ bgeu(used, block_size, L_main_loop); + + // There is still data left fewer than block_size after L_main_loop + // or last used, we encrypt them one by one. + __ bind(L_encrypt_next); + __ add(t0, saved_encrypted_ctr, used); + __ lbu(t1, Address(t0)); + __ lbu(t0, Address(in)); + __ xorr(t1, t1, t0); + __ sb(t1, Address(out)); + __ addi(in, in, 1); + __ addi(out, out, 1); + __ addi(used, used, 1); + __ subi(len, len, 1); + __ beqz(len, L_exit); + __ j(L_next); + + // We will calculate the next saved_encrypted_ctr and encrypt the blocks of data + // one by one until there is less than a full block remaining if len not zero + __ bind(L_main_loop); + __ beqz(len, L_exit); + __ vle32_v(v16, counter); + + // encrypt counter according to round + generate_aes_encrypt(v16, working_vregs, round); + + __ vse32_v(v16, saved_encrypted_ctr); + + // 128-bit little-endian increment + add_counter_128(counter_hi, counter_lo); + // 128-bit big-endian store + be_store_counter_128(counter_hi, counter_lo, counter); + + __ mv(used, 0); + // Check if we have a full block_size + __ bltu(len, block_size, L_encrypt_next); + + // We have one full block to encrypt at least + __ vle32_v(v17, in); + __ vxor_vv(v16, v16, v17); + __ vse32_v(v16, out); + __ add(out, out, block_size); + __ add(in, in, block_size); + __ sub(len, len, block_size); + __ mv(used, block_size); + __ j(L_main_loop); + + __ bind(L_exit); + __ sw(used, Address(used_ptr)); + __ mv(x10, input_len); + __ leave(); + __ ret(); + }; + + // CTR AES crypt. + // Arguments: + // + // Inputs: + // c_rarg0 - source byte array address + // c_rarg1 - destination byte array address + // c_rarg2 - K (key) in little endian int array + // c_rarg3 - counter vector byte array address + // c_rarg4 - input length + // c_rarg5 - saved encryptedCounter start + // c_rarg6 - saved used length + // + // Output: + // x10 - input length + // + address generate_counterMode_AESCrypt() { + assert(UseZvkn, "need AES instructions (Zvkned extension) support"); + assert(UseAESCTRIntrinsics, "need AES instructions (Zvkned extension) support"); + assert(UseZbb, "need basic bit manipulation (Zbb extension) support"); + + __ align(CodeEntryAlignment); + StubId stub_id = StubId::stubgen_counterMode_AESCrypt_id; + StubCodeMark mark(this, stub_id); + + const Register in = c_rarg0; + const Register out = c_rarg1; + const Register key = c_rarg2; + const Register counter = c_rarg3; + const Register input_len = c_rarg4; + const Register saved_encrypted_ctr = c_rarg5; + const Register used_len_ptr = c_rarg6; + + const Register keylen = c_rarg7; // temporary register + + const address start = __ pc(); + __ enter(); + + Label L_exit; + __ beqz(input_len, L_exit); + + Label L_aes128, L_aes192; + // Compute #rounds for AES based on the length of the key array + __ lwu(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); + __ mv(t0, 52); // key length could be only {11, 13, 15} * 4 = {44, 52, 60} + __ bltu(keylen, t0, L_aes128); + __ beq(keylen, t0, L_aes192); + // Else we fallthrough to the biggest case (256-bit key size) + + // Note: the following function performs crypt with key += 15*16 + counterMode_AESCrypt(15, in, out, key, counter, input_len, saved_encrypted_ctr, used_len_ptr); + + // Note: the following function performs crypt with key += 13*16 + __ bind(L_aes192); + counterMode_AESCrypt(13, in, out, key, counter, input_len, saved_encrypted_ctr, used_len_ptr); + + // Note: the following function performs crypt with key += 11*16 + __ bind(L_aes128); + counterMode_AESCrypt(11, in, out, key, counter, input_len, saved_encrypted_ctr, used_len_ptr); + + __ bind(L_exit); + __ mv(x10, input_len); + __ leave(); + __ ret(); + + return start; + } + // code for comparing 8 characters of strings with Latin1 and Utf16 encoding void compare_string_8_x_LU(Register tmpL, Register tmpU, Register strL, Register strU, Label& DIFF) { @@ -6826,6 +7043,10 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); } + if (UseAESCTRIntrinsics) { + StubRoutines::_counterMode_AESCrypt = generate_counterMode_AESCrypt(); + } + if (UsePoly1305Intrinsics) { StubRoutines::_poly1305_processBlocks = generate_poly1305_processBlocks(); } diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 6f4babc872f..75605f25759 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -434,6 +434,15 @@ void VM_Version::c2_initialize() { warning("UseAESIntrinsics enabled, but UseAES not, enabling"); UseAES = true; } + + if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics) && UseZbb) { + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, true); + } + + if (UseAESCTRIntrinsics && !UseZbb) { + warning("Cannot enable UseAESCTRIntrinsics on cpu without UseZbb support."); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } } else { if (UseAES) { warning("AES instructions are not available on this CPU"); @@ -443,11 +452,10 @@ void VM_Version::c2_initialize() { warning("AES intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseAESIntrinsics, false); } - } - - if (UseAESCTRIntrinsics) { - warning("AES/CTR intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + if (UseAESCTRIntrinsics) { + warning("Cannot enable UseAESCTRIntrinsics on cpu without UseZvkn support."); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } } } diff --git a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp index 3e0e1d5bf07..971c8fd3c44 100644 --- a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp +++ b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp @@ -73,7 +73,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(compiler, 109000 WINDOWS_ONLY(+2000)) \ + do_arch_blob(compiler, 120000 WINDOWS_ONLY(+2000)) \ do_stub(compiler, vector_float_sign_mask) \ do_arch_entry(x86, compiler, vector_float_sign_mask, \ vector_float_sign_mask, vector_float_sign_mask) \ diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index 1e728ffa279..24de32a6fe7 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -480,7 +480,7 @@ address StubGenerator::generate_counterMode_VectorAESCrypt() { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address -// c_rarg2 - K (key) in little endian int array +// c_rarg2 - sessionKe (key) in little endian int array // c_rarg3 - counter vector byte array address // Linux // c_rarg4 - input length @@ -1063,7 +1063,7 @@ address StubGenerator::generate_cipherBlockChaining_decryptVectorAESCrypt() { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address -// c_rarg2 - K (key) in little endian int array +// c_rarg2 - sessionKe (key) in little endian int array // address StubGenerator::generate_aescrypt_encryptBlock() { assert(UseAES, "need AES instructions and misaligned SSE support"); @@ -1158,7 +1158,7 @@ address StubGenerator::generate_aescrypt_encryptBlock() { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address -// c_rarg2 - K (key) in little endian int array +// c_rarg2 - sessionKd (key) in little endian int array // address StubGenerator::generate_aescrypt_decryptBlock() { assert(UseAES, "need AES instructions and misaligned SSE support"); @@ -1255,7 +1255,7 @@ address StubGenerator::generate_aescrypt_decryptBlock() { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address -// c_rarg2 - K (key) in little endian int array +// c_rarg2 - sessionKe (key) in little endian int array // c_rarg3 - r vector byte array address // c_rarg4 - input length // @@ -1407,7 +1407,7 @@ address StubGenerator::generate_cipherBlockChaining_encryptAESCrypt() { // Inputs: // c_rarg0 - source byte array address // c_rarg1 - destination byte array address -// c_rarg2 - K (key) in little endian int array +// c_rarg2 - sessionKd (key) in little endian int array // c_rarg3 - r vector byte array address // c_rarg4 - input length // diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 1d393897bca..42d2e815e45 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -3386,6 +3386,11 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { return false; } break; + case Op_VectorBlend: + if (UseAVX == 0 && size_in_bits < 128) { + return false; + } + break; case Op_VectorTest: if (UseSSE < 4) { return false; // Implementation limitation diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index cf64c22ddff..880dbeccf7d 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4305,7 +4305,7 @@ OSReturn os::get_native_priority(const Thread* const thread, // For reference, please, see IEEE Std 1003.1-2004: // http://www.unix.org/single_unix_specification -jlong os::Linux::total_thread_cpu_time(clockid_t clockid) { +jlong os::Linux::thread_cpu_time(clockid_t clockid) { struct timespec tp; int status = clock_gettime(clockid, &tp); assert(status == 0, "clock_gettime error: %s", os::strerror(errno)); @@ -4960,20 +4960,42 @@ int os::open(const char *path, int oflag, int mode) { return fd; } +// Since kernel v2.6.12 the Linux ABI has had support for encoding the clock +// types in the last three bits. Bit 2 indicates whether a cpu clock refers to a +// thread or a process. Bits 1 and 0 give the type: PROF=0, VIRT=1, SCHED=2, or +// FD=3. The clock CPUCLOCK_VIRT (0b001) reports the thread's consumed user +// time. POSIX compliant implementations of pthread_getcpuclockid return the +// clock CPUCLOCK_SCHED (0b010) which reports the thread's consumed system+user +// time (as mandated by the POSIX standard POSIX.1-2024/IEEE Std 1003.1-2024 +// §3.90). +static bool get_thread_clockid(Thread* thread, clockid_t* clockid, bool total) { + constexpr clockid_t CLOCK_TYPE_MASK = 3; + constexpr clockid_t CPUCLOCK_VIRT = 1; + + int rc = pthread_getcpuclockid(thread->osthread()->pthread_id(), clockid); + if (rc != 0) { + // It's possible to encounter a terminated native thread that failed + // to detach itself from the VM - which should result in ESRCH. + assert_status(rc == ESRCH, rc, "pthread_getcpuclockid failed"); + return false; + } + + if (!total) { + clockid_t clockid_tmp = *clockid; + clockid_tmp = (clockid_tmp & ~CLOCK_TYPE_MASK) | CPUCLOCK_VIRT; + *clockid = clockid_tmp; + } + + return true; +} + static jlong user_thread_cpu_time(Thread *thread); static jlong total_thread_cpu_time(Thread *thread) { - clockid_t clockid; - int rc = pthread_getcpuclockid(thread->osthread()->pthread_id(), - &clockid); - if (rc == 0) { - return os::Linux::total_thread_cpu_time(clockid); - } else { - // It's possible to encounter a terminated native thread that failed - // to detach itself from the VM - which should result in ESRCH. - assert_status(rc == ESRCH, rc, "pthread_getcpuclockid failed"); - return -1; - } + clockid_t clockid; + bool success = get_thread_clockid(thread, &clockid, true); + + return success ? os::Linux::thread_cpu_time(clockid) : -1; } // current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) @@ -4984,7 +5006,7 @@ static jlong total_thread_cpu_time(Thread *thread) { // the fast estimate available on the platform. jlong os::current_thread_cpu_time() { - return os::Linux::total_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); + return os::Linux::thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); } jlong os::thread_cpu_time(Thread* thread) { @@ -4993,7 +5015,7 @@ jlong os::thread_cpu_time(Thread* thread) { jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { if (user_sys_cpu_time) { - return os::Linux::total_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); + return os::Linux::thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); } else { return user_thread_cpu_time(Thread::current()); } @@ -5007,46 +5029,11 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { } } -// -1 on error. static jlong user_thread_cpu_time(Thread *thread) { - pid_t tid = thread->osthread()->thread_id(); - char *s; - char stat[2048]; - size_t statlen; - char proc_name[64]; - int count; - long sys_time, user_time; - char cdummy; - int idummy; - long ldummy; - FILE *fp; + clockid_t clockid; + bool success = get_thread_clockid(thread, &clockid, false); - os::snprintf_checked(proc_name, 64, "/proc/self/task/%d/stat", tid); - fp = os::fopen(proc_name, "r"); - if (fp == nullptr) return -1; - statlen = fread(stat, 1, 2047, fp); - stat[statlen] = '\0'; - fclose(fp); - - // Skip pid and the command string. Note that we could be dealing with - // weird command names, e.g. user could decide to rename java launcher - // to "java 1.4.2 :)", then the stat file would look like - // 1234 (java 1.4.2 :)) R ... ... - // We don't really need to know the command string, just find the last - // occurrence of ")" and then start parsing from there. See bug 4726580. - s = strrchr(stat, ')'); - if (s == nullptr) return -1; - - // Skip blank chars - do { s++; } while (s && isspace((unsigned char) *s)); - - count = sscanf(s,"%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu", - &cdummy, &idummy, &idummy, &idummy, &idummy, &idummy, - &ldummy, &ldummy, &ldummy, &ldummy, &ldummy, - &user_time, &sys_time); - if (count != 13) return -1; - - return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second()); + return success ? os::Linux::thread_cpu_time(clockid) : -1; } void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index dd07cb600b9..43f70b4af56 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -142,7 +142,7 @@ class os::Linux { static bool manually_expand_stack(JavaThread * t, address addr); static void expand_stack_to(address bottom); - static jlong total_thread_cpu_time(clockid_t clockid); + static jlong thread_cpu_time(clockid_t clockid); static jlong sendfile(int out_fd, int in_fd, jlong* offset, jlong count); diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 2c6b7d7e96e..7871134e923 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -90,7 +90,7 @@ typedef CodeBuffer::csize_t csize_t; // file-local definition // External buffer, in a predefined CodeBlob. // Important: The code_start must be taken exactly, and not realigned. -CodeBuffer::CodeBuffer(CodeBlob* blob) DEBUG_ONLY(: Scrubber(this, sizeof(*this))) { +CodeBuffer::CodeBuffer(const CodeBlob* blob) DEBUG_ONLY(: Scrubber(this, sizeof(*this))) { // Provide code buffer with meaningful name initialize_misc(blob->name()); initialize(blob->content_begin(), blob->content_size()); diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 430d4949467..38e151273da 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -672,7 +672,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) { } // (2) CodeBuffer referring to pre-allocated CodeBlob. - CodeBuffer(CodeBlob* blob); + CodeBuffer(const CodeBlob* blob); // (3) code buffer allocating codeBlob memory for code & relocation // info but with lazy initialization. The name must be something diff --git a/src/hotspot/share/cds/aotMappedHeapWriter.cpp b/src/hotspot/share/cds/aotMappedHeapWriter.cpp index 98f400c989c..edd0aede246 100644 --- a/src/hotspot/share/cds/aotMappedHeapWriter.cpp +++ b/src/hotspot/share/cds/aotMappedHeapWriter.cpp @@ -86,9 +86,9 @@ void AOTMappedHeapWriter::init() { if (CDSConfig::is_dumping_heap()) { Universe::heap()->collect(GCCause::_java_lang_system_gc); - _buffer_offset_to_source_obj_table = new BufferOffsetToSourceObjectTable(/*size (prime)*/36137, /*max size*/1 * M); + _buffer_offset_to_source_obj_table = new (mtClassShared) BufferOffsetToSourceObjectTable(/*size (prime)*/36137, /*max size*/1 * M); _dumped_interned_strings = new (mtClass)DumpedInternedStrings(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE); - _fillers = new FillersTable(); + _fillers = new (mtClassShared) FillersTable(); _requested_bottom = nullptr; _requested_top = nullptr; diff --git a/src/hotspot/share/cds/aotStreamedHeapLoader.cpp b/src/hotspot/share/cds/aotStreamedHeapLoader.cpp index 9b6974bb48d..6719f9bf898 100644 --- a/src/hotspot/share/cds/aotStreamedHeapLoader.cpp +++ b/src/hotspot/share/cds/aotStreamedHeapLoader.cpp @@ -184,6 +184,7 @@ static size_t archive_object_size(oopDesc* archive_object) { oop AOTStreamedHeapLoader::allocate_object(oopDesc* archive_object, markWord mark, size_t size, TRAPS) { assert(!archive_object->is_stackChunk(), "no such objects are archived"); + NoJvmtiEventsMark njem; oop heap_object; Klass* klass = archive_object->klass(); diff --git a/src/hotspot/share/cds/aotThread.cpp b/src/hotspot/share/cds/aotThread.cpp index 26a6f4291cd..113a751d2a1 100644 --- a/src/hotspot/share/cds/aotThread.cpp +++ b/src/hotspot/share/cds/aotThread.cpp @@ -63,7 +63,7 @@ void AOTThread::initialize() { // This is important because this thread runs before JVMTI monitors are set up appropriately. // Therefore, callbacks would not work as intended. JVMTI has no business peeking at how we // materialize primordial objects from the AOT cache. - thread->toggle_is_disable_suspend(); + thread->disable_jvmti_events(); #endif JavaThread::vm_exit_on_osthread_failure(thread); diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp index f6da1a34af3..d091067c116 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp @@ -357,7 +357,7 @@ InstanceKlass* LambdaProxyClassDictionary::load_and_init_lambda_proxy_class(Inst InstanceKlass* nest_host = caller_ik->nest_host(THREAD); assert(nest_host == shared_nest_host, "mismatched nest host"); - EventClassLoad class_load_start_event; + EventClassLoad class_load_event; // Add to class hierarchy, and do possible deoptimizations. lambda_ik->add_to_hierarchy(THREAD); @@ -368,8 +368,8 @@ InstanceKlass* LambdaProxyClassDictionary::load_and_init_lambda_proxy_class(Inst if (JvmtiExport::should_post_class_load()) { JvmtiExport::post_class_load(THREAD, lambda_ik); } - if (class_load_start_event.should_commit()) { - SystemDictionary::post_class_load_event(&class_load_start_event, lambda_ik, ClassLoaderData::class_loader_data(class_loader())); + if (class_load_event.should_commit()) { + JFR_ONLY(SystemDictionary::post_class_load_event(&class_load_event, lambda_ik, ClassLoaderData::class_loader_data(class_loader()));) } lambda_ik->initialize(CHECK_NULL); diff --git a/src/hotspot/share/ci/ciInstanceKlass.hpp b/src/hotspot/share/ci/ciInstanceKlass.hpp index 1f887771f54..a1b2d8dd12d 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.hpp +++ b/src/hotspot/share/ci/ciInstanceKlass.hpp @@ -149,6 +149,10 @@ public: assert(is_loaded(), "must be loaded"); return _flags; } + + // Fetch Klass::access_flags. + jint access_flags() { return flags().as_int(); } + bool has_finalizer() { assert(is_loaded(), "must be loaded"); return _has_finalizer; } diff --git a/src/hotspot/share/ci/ciKlass.cpp b/src/hotspot/share/ci/ciKlass.cpp index f3e49634d29..0a0379af97e 100644 --- a/src/hotspot/share/ci/ciKlass.cpp +++ b/src/hotspot/share/ci/ciKlass.cpp @@ -216,15 +216,6 @@ jint ciKlass::modifier_flags() { ) } -// ------------------------------------------------------------------ -// ciKlass::access_flags -jint ciKlass::access_flags() { - assert(is_loaded(), "not loaded"); - GUARDED_VM_ENTRY( - return get_Klass()->access_flags().as_unsigned_short(); - ) -} - // ------------------------------------------------------------------ // ciKlass::misc_flags klass_flags_t ciKlass::misc_flags() { diff --git a/src/hotspot/share/ci/ciKlass.hpp b/src/hotspot/share/ci/ciKlass.hpp index 8d03b910de5..f95602b9717 100644 --- a/src/hotspot/share/ci/ciKlass.hpp +++ b/src/hotspot/share/ci/ciKlass.hpp @@ -122,9 +122,6 @@ public: // Fetch modifier flags. jint modifier_flags(); - // Fetch Klass::access_flags. - jint access_flags(); - // Fetch Klass::misc_flags. klass_flags_t misc_flags(); diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 68890775051..c9d9d3632b5 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -89,9 +89,6 @@ #if INCLUDE_CDS #include "classfile/systemDictionaryShared.hpp" #endif -#if INCLUDE_JFR -#include "jfr/support/jfrTraceIdExtension.hpp" -#endif // We generally try to create the oops directly when parsing, rather than // allocating temporary data structures and copying the bytes twice. A @@ -157,6 +154,8 @@ #define JAVA_26_VERSION 70 +#define JAVA_27_VERSION 71 + void ClassFileParser::set_class_bad_constant_seen(short bad_constant) { assert((bad_constant == JVM_CONSTANT_Module || bad_constant == JVM_CONSTANT_Package) && _major_version >= JAVA_9_VERSION, @@ -5272,8 +5271,6 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, } } - JFR_ONLY(INIT_ID(ik);) - // If we reach here, all is well. // Now remove the InstanceKlass* from the _klass_to_deallocate field // in order for it to not be destroyed in the ClassFileParser destructor. diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index 5d4236132f1..48cdacedc1e 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -500,6 +500,8 @@ class ClassFileParser { InstanceKlass* create_instance_klass(bool cf_changed_in_CFLH, const ClassInstanceInfo& cl_inst_info, TRAPS); + const ClassFileStream& stream() const { return *_stream; } + const ClassFileStream* clone_stream() const; void set_klass_to_deallocate(InstanceKlass* klass); diff --git a/src/hotspot/share/classfile/defaultMethods.cpp b/src/hotspot/share/classfile/defaultMethods.cpp index e5cb5d8f354..2588ebd60ca 100644 --- a/src/hotspot/share/classfile/defaultMethods.cpp +++ b/src/hotspot/share/classfile/defaultMethods.cpp @@ -439,7 +439,7 @@ class MethodFamily : public ResourceObj { StreamIndentor si(str, indent * 2); str->print("Selected method: "); print_method(str, _selected_target); - Klass* method_holder = _selected_target->method_holder(); + InstanceKlass* method_holder = _selected_target->method_holder(); if (!method_holder->is_interface()) { str->print(" : in superclass"); } diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index ee80dbbc45c..77a94c8afa5 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1091,10 +1091,6 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti // Set the modifiers flag. u2 computed_modifiers = k->compute_modifier_flags(); set_modifiers(mirror(), computed_modifiers); - // Set the raw access_flags, this is used by reflection instead of modifier flags. - // The Java code for array classes gets the access flags from the element type. - assert(!k->is_array_klass() || k->access_flags().as_unsigned_short() == 0, "access flags are not set for arrays"); - set_raw_access_flags(mirror(), k->access_flags().as_unsigned_short()); InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass()); assert(oop_size(mirror()) == mk->instance_size(k), "should have been set"); @@ -1103,6 +1099,8 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti // It might also have a component mirror. This mirror must already exist. if (k->is_array_klass()) { + // The Java code for array classes gets the access flags from the element type. + set_raw_access_flags(mirror(), 0); if (k->is_typeArray_klass()) { BasicType type = TypeArrayKlass::cast(k)->element_type(); if (is_scratch) { @@ -1129,6 +1127,8 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti // and java_mirror in this klass. } else { assert(k->is_instance_klass(), "Must be"); + // Set the raw access_flags, this is used by reflection instead of modifier flags. + set_raw_access_flags(mirror(), InstanceKlass::cast(k)->access_flags().as_unsigned_short()); initialize_mirror_fields(InstanceKlass::cast(k), mirror, protection_domain, classData, THREAD); if (HAS_PENDING_EXCEPTION) { // If any of the fields throws an exception like OOM remove the klass field @@ -1684,8 +1684,8 @@ int java_lang_Thread::_name_offset; int java_lang_Thread::_contextClassLoader_offset; int java_lang_Thread::_eetop_offset; int java_lang_Thread::_jvmti_thread_state_offset; -int java_lang_Thread::_jvmti_VTMS_transition_disable_count_offset; -int java_lang_Thread::_jvmti_is_in_VTMS_transition_offset; +int java_lang_Thread::_vthread_transition_disable_count_offset; +int java_lang_Thread::_is_in_vthread_transition_offset; int java_lang_Thread::_interrupted_offset; int java_lang_Thread::_interruptLock_offset; int java_lang_Thread::_tid_offset; @@ -1745,34 +1745,34 @@ void java_lang_Thread::set_jvmti_thread_state(oop java_thread, JvmtiThreadState* java_thread->address_field_put(_jvmti_thread_state_offset, (address)state); } -int java_lang_Thread::VTMS_transition_disable_count(oop java_thread) { - return java_thread->int_field(_jvmti_VTMS_transition_disable_count_offset); +int java_lang_Thread::vthread_transition_disable_count(oop java_thread) { + jint* addr = java_thread->field_addr(_vthread_transition_disable_count_offset); + return AtomicAccess::load(addr); } -void java_lang_Thread::inc_VTMS_transition_disable_count(oop java_thread) { - assert(JvmtiVTMSTransition_lock->owned_by_self(), "Must be locked"); - int val = VTMS_transition_disable_count(java_thread); - java_thread->int_field_put(_jvmti_VTMS_transition_disable_count_offset, val + 1); +void java_lang_Thread::inc_vthread_transition_disable_count(oop java_thread) { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + jint* addr = java_thread->field_addr(_vthread_transition_disable_count_offset); + int val = AtomicAccess::load(addr); + AtomicAccess::store(addr, val + 1); } -void java_lang_Thread::dec_VTMS_transition_disable_count(oop java_thread) { - assert(JvmtiVTMSTransition_lock->owned_by_self(), "Must be locked"); - int val = VTMS_transition_disable_count(java_thread); - assert(val > 0, "VTMS_transition_disable_count should never be negative"); - java_thread->int_field_put(_jvmti_VTMS_transition_disable_count_offset, val - 1); +void java_lang_Thread::dec_vthread_transition_disable_count(oop java_thread) { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + jint* addr = java_thread->field_addr(_vthread_transition_disable_count_offset); + int val = AtomicAccess::load(addr); + AtomicAccess::store(addr, val - 1); } -bool java_lang_Thread::is_in_VTMS_transition(oop java_thread) { - return java_thread->bool_field_volatile(_jvmti_is_in_VTMS_transition_offset); +bool java_lang_Thread::is_in_vthread_transition(oop java_thread) { + jboolean* addr = java_thread->field_addr(_is_in_vthread_transition_offset); + return AtomicAccess::load(addr); } -void java_lang_Thread::set_is_in_VTMS_transition(oop java_thread, bool val) { - assert(is_in_VTMS_transition(java_thread) != val, "already %s transition", val ? "inside" : "outside"); - java_thread->bool_field_put_volatile(_jvmti_is_in_VTMS_transition_offset, val); -} - -int java_lang_Thread::is_in_VTMS_transition_offset() { - return _jvmti_is_in_VTMS_transition_offset; +void java_lang_Thread::set_is_in_vthread_transition(oop java_thread, bool val) { + assert(is_in_vthread_transition(java_thread) != val, "already %s transition", val ? "inside" : "outside"); + jboolean* addr = java_thread->field_addr(_is_in_vthread_transition_offset); + AtomicAccess::store(addr, (jboolean)val); } void java_lang_Thread::clear_scopedValueBindings(oop java_thread) { diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 699dd39b887..33dc912404c 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -375,8 +375,8 @@ class java_lang_Class : AllStatic { #define THREAD_INJECTED_FIELDS(macro) \ macro(java_lang_Thread, jvmti_thread_state, intptr_signature, false) \ - macro(java_lang_Thread, jvmti_VTMS_transition_disable_count, int_signature, false) \ - macro(java_lang_Thread, jvmti_is_in_VTMS_transition, bool_signature, false) \ + macro(java_lang_Thread, vthread_transition_disable_count, int_signature, false) \ + macro(java_lang_Thread, is_in_vthread_transition, bool_signature, false) \ JFR_ONLY(macro(java_lang_Thread, jfr_epoch, short_signature, false)) class java_lang_Thread : AllStatic { @@ -390,8 +390,8 @@ class java_lang_Thread : AllStatic { static int _contextClassLoader_offset; static int _eetop_offset; static int _jvmti_thread_state_offset; - static int _jvmti_VTMS_transition_disable_count_offset; - static int _jvmti_is_in_VTMS_transition_offset; + static int _vthread_transition_disable_count_offset; + static int _is_in_vthread_transition_offset; static int _interrupted_offset; static int _interruptLock_offset; static int _tid_offset; @@ -444,12 +444,15 @@ class java_lang_Thread : AllStatic { static JvmtiThreadState* jvmti_thread_state(oop java_thread); static void set_jvmti_thread_state(oop java_thread, JvmtiThreadState* state); - static int VTMS_transition_disable_count(oop java_thread); - static void inc_VTMS_transition_disable_count(oop java_thread); - static void dec_VTMS_transition_disable_count(oop java_thread); - static bool is_in_VTMS_transition(oop java_thread); - static void set_is_in_VTMS_transition(oop java_thread, bool val); - static int is_in_VTMS_transition_offset(); + + static int vthread_transition_disable_count(oop java_thread); + static void inc_vthread_transition_disable_count(oop java_thread); + static void dec_vthread_transition_disable_count(oop java_thread); + static int vthread_transition_disable_count_offset() { return _vthread_transition_disable_count_offset; } + + static bool is_in_vthread_transition(oop java_thread); + static void set_is_in_vthread_transition(oop java_thread, bool val); + static int is_in_vthread_transition_offset() { return _is_in_vthread_transition_offset; } // Clear all scoped value bindings on error static void clear_scopedValueBindings(oop java_thread); diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp index 50d327d7e8c..4e599feb3ff 100644 --- a/src/hotspot/share/classfile/klassFactory.cpp +++ b/src/hotspot/share/classfile/klassFactory.cpp @@ -37,7 +37,7 @@ #include "runtime/handles.inline.hpp" #include "utilities/macros.hpp" #if INCLUDE_JFR -#include "jfr/support/jfrKlassExtension.hpp" +#include "jfr/jfr.hpp" #endif @@ -99,6 +99,9 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook( new_ik->set_classpath_index(path_index); } + + JFR_ONLY(Jfr::on_klass_creation(new_ik, parser, THREAD);) + return new_ik; } } @@ -213,7 +216,7 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream, result->set_cached_class_file(cached_class_file); } - JFR_ONLY(ON_KLASS_CREATION(result, parser, THREAD);) + JFR_ONLY(Jfr::on_klass_creation(result, parser, THREAD);) #if INCLUDE_CDS if (CDSConfig::is_dumping_archive()) { diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index a17e7e129ce..e03d198eb9f 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -560,15 +560,6 @@ static InstanceKlass* handle_parallel_loading(JavaThread* current, return nullptr; } -void SystemDictionary::post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) { - assert(event != nullptr, "invariant"); - assert(k != nullptr, "invariant"); - event->set_loadedClass(k); - event->set_definingClassLoader(k->class_loader_data()); - event->set_initiatingClassLoader(init_cld); - event->commit(); -} - // SystemDictionary::resolve_instance_class_or_null is the main function for class name resolution. // After checking if the InstanceKlass already exists, it checks for ClassCircularityError and // whether the thread must wait for loading in parallel. It eventually calls load_instance_class, @@ -582,7 +573,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, assert(name != nullptr && !Signature::is_array(name) && !Signature::has_envelope(name), "invalid class name: %s", name == nullptr ? "nullptr" : name->as_C_string()); - EventClassLoad class_load_start_event; + EventClassLoad class_load_event; HandleMark hm(THREAD); @@ -713,8 +704,8 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, return nullptr; } - if (class_load_start_event.should_commit()) { - post_class_load_event(&class_load_start_event, loaded_class, loader_data); + if (class_load_event.should_commit()) { + JFR_ONLY(post_class_load_event(&class_load_event, loaded_class, loader_data);) } // Make sure we have the right class in the dictionary @@ -789,7 +780,7 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream( const ClassLoadInfo& cl_info, TRAPS) { - EventClassLoad class_load_start_event; + EventClassLoad class_load_event; ClassLoaderData* loader_data; // - for hidden classes that are not strong: create a new CLD that has a class holder and @@ -819,15 +810,16 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream( k->add_to_hierarchy(THREAD); // But, do not add to dictionary. + if (class_load_event.should_commit()) { + JFR_ONLY(post_class_load_event(&class_load_event, k, loader_data);) + } + k->link_class(CHECK_NULL); // notify jvmti if (JvmtiExport::should_post_class_load()) { JvmtiExport::post_class_load(THREAD, k); } - if (class_load_start_event.should_commit()) { - post_class_load_event(&class_load_start_event, k, loader_data); - } return k; } @@ -1182,6 +1174,8 @@ void SystemDictionary::preload_class(Handle class_loader, InstanceKlass* ik, TRA } #endif + EventClassLoad class_load_event; + ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader()); oop java_mirror = ik->archived_java_mirror(); precond(java_mirror != nullptr); @@ -1203,11 +1197,26 @@ void SystemDictionary::preload_class(Handle class_loader, InstanceKlass* ik, TRA update_dictionary(THREAD, ik, loader_data); } + if (class_load_event.should_commit()) { + JFR_ONLY(post_class_load_event(&class_load_event, ik, loader_data);) + } + assert(ik->is_loaded(), "Must be in at least loaded state"); } #endif // INCLUDE_CDS +#if INCLUDE_JFR +void SystemDictionary::post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) { + assert(event != nullptr, "invariant"); + assert(k != nullptr, "invariant"); + event->set_loadedClass(k); + event->set_definingClassLoader(k->class_loader_data()); + event->set_initiatingClassLoader(init_cld); + event->commit(); +} +#endif // INCLUDE_JFR + InstanceKlass* SystemDictionary::load_instance_class_impl(Symbol* class_name, Handle class_loader, TRAPS) { if (class_loader.is_null()) { @@ -1380,15 +1389,6 @@ InstanceKlass* SystemDictionary::load_instance_class(Symbol* name, return loaded_class; } -static void post_class_define_event(InstanceKlass* k, const ClassLoaderData* def_cld) { - EventClassDefine event; - if (event.should_commit()) { - event.set_definedClass(k); - event.set_definingClassLoader(def_cld); - event.commit(); - } -} - void SystemDictionary::define_instance_class(InstanceKlass* k, Handle class_loader, TRAPS) { ClassLoaderData* loader_data = k->class_loader_data(); @@ -1440,7 +1440,6 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, Handle class_load if (JvmtiExport::should_post_class_load()) { JvmtiExport::post_class_load(THREAD, k); } - post_class_define_event(k, loader_data); } // Support parallel classloading @@ -2173,9 +2172,10 @@ static bool is_always_visible_class(oop mirror) { return true; // primitive array } assert(klass->is_instance_klass(), "%s", klass->external_name()); - return klass->is_public() && - (InstanceKlass::cast(klass)->is_same_class_package(vmClasses::Object_klass()) || // java.lang - InstanceKlass::cast(klass)->is_same_class_package(vmClasses::MethodHandle_klass())); // java.lang.invoke + InstanceKlass* ik = InstanceKlass::cast(klass); + return ik->is_public() && + (ik->is_same_class_package(vmClasses::Object_klass()) || // java.lang + ik->is_same_class_package(vmClasses::MethodHandle_klass())); // java.lang.invoke } // Find or construct the Java mirror (java.lang.Class instance) for diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index 99cb1d0b5d2..99e13fea61e 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -326,11 +326,10 @@ private: static void restore_archived_method_handle_intrinsics_impl(TRAPS) NOT_CDS_RETURN; protected: - // Used by AOTLinkedClassBulkLoader, LambdaProxyClassDictionary, and SystemDictionaryShared + // Used by AOTLinkedClassBulkLoader, LambdaProxyClassDictionary, VMClasses and SystemDictionaryShared static bool add_loader_constraint(Symbol* name, Klass* klass_being_linked, Handle loader1, Handle loader2); - static void post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld); static InstanceKlass* load_shared_class(InstanceKlass* ik, Handle class_loader, Handle protection_domain, @@ -342,6 +341,9 @@ protected: static InstanceKlass* find_or_define_instance_class(Symbol* class_name, Handle class_loader, InstanceKlass* k, TRAPS); + JFR_ONLY(static void post_class_load_event(EventClassLoad* event, + const InstanceKlass* k, + const ClassLoaderData* init_cld);) public: static bool is_system_class_loader(oop class_loader); diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index 0a3d33f4c5b..00d209a05ca 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -35,6 +35,7 @@ #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" #include "gc/shared/collectedHeap.hpp" +#include "jfr/jfrEvents.hpp" #include "memory/metaspaceClosure.hpp" #include "memory/universe.hpp" #include "oops/instanceKlass.hpp" @@ -240,6 +241,8 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load return; } + EventClassLoad class_load_event; + // add super and interfaces first InstanceKlass* super = klass->super(); if (super != nullptr && super->class_loader_data() == nullptr) { @@ -261,6 +264,10 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load dictionary->add_klass(THREAD, klass->name(), klass); klass->add_to_hierarchy(THREAD); assert(klass->is_loaded(), "Must be in at least loaded state"); + + if (class_load_event.should_commit()) { + JFR_ONLY(SystemDictionary::post_class_load_event(&class_load_event, klass, loader_data);) + } } #endif // INCLUDE_CDS diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 0895418ef84..6f9c2326a45 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -649,10 +649,10 @@ class methodHandle; do_intrinsic(_Continuation_unpin, jdk_internal_vm_Continuation, unpin_name, void_method_signature, F_SN) \ \ /* java/lang/VirtualThread */ \ - do_intrinsic(_notifyJvmtiVThreadStart, java_lang_VirtualThread, notifyJvmtiStart_name, void_method_signature, F_RN) \ - do_intrinsic(_notifyJvmtiVThreadEnd, java_lang_VirtualThread, notifyJvmtiEnd_name, void_method_signature, F_RN) \ - do_intrinsic(_notifyJvmtiVThreadMount, java_lang_VirtualThread, notifyJvmtiMount_name, bool_void_signature, F_RN) \ - do_intrinsic(_notifyJvmtiVThreadUnmount, java_lang_VirtualThread, notifyJvmtiUnmount_name, bool_void_signature, F_RN) \ + do_intrinsic(_vthreadEndFirstTransition, java_lang_VirtualThread, endFirstTransition_name, void_method_signature, F_RN) \ + do_intrinsic(_vthreadStartFinalTransition, java_lang_VirtualThread, startFinalTransition_name, void_method_signature, F_RN) \ + do_intrinsic(_vthreadStartTransition, java_lang_VirtualThread, startTransition_name, bool_void_signature, F_RN) \ + do_intrinsic(_vthreadEndTransition, java_lang_VirtualThread, endTransition_name, bool_void_signature, F_RN) \ do_intrinsic(_notifyJvmtiVThreadDisableSuspend, java_lang_VirtualThread, notifyJvmtiDisableSuspend_name, bool_void_signature, F_SN) \ \ /* support for UnsafeConstants */ \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index d22700b8d1f..8388b98faae 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -395,10 +395,10 @@ class SerializeClosure; template(run_finalization_name, "runFinalization") \ template(dispatchUncaughtException_name, "dispatchUncaughtException") \ template(loadClass_name, "loadClass") \ - template(notifyJvmtiStart_name, "notifyJvmtiStart") \ - template(notifyJvmtiEnd_name, "notifyJvmtiEnd") \ - template(notifyJvmtiMount_name, "notifyJvmtiMount") \ - template(notifyJvmtiUnmount_name, "notifyJvmtiUnmount") \ + template(startTransition_name, "startTransition") \ + template(endTransition_name, "endTransition") \ + template(startFinalTransition_name, "startFinalTransition") \ + template(endFirstTransition_name, "endFirstTransition") \ template(notifyJvmtiDisableSuspend_name, "notifyJvmtiDisableSuspend") \ template(doYield_name, "doYield") \ template(enter_name, "enter") \ @@ -497,8 +497,8 @@ class SerializeClosure; template(java_lang_Boolean_signature, "Ljava/lang/Boolean;") \ template(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \ template(jvmti_thread_state_name, "jvmti_thread_state") \ - template(jvmti_VTMS_transition_disable_count_name, "jvmti_VTMS_transition_disable_count") \ - template(jvmti_is_in_VTMS_transition_name, "jvmti_is_in_VTMS_transition") \ + template(vthread_transition_disable_count_name, "vthread_transition_disable_count") \ + template(is_in_vthread_transition_name, "is_in_vthread_transition") \ template(module_entry_name, "module_entry") \ template(resolved_references_name, "") \ template(init_lock_name, "") \ diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 04776f4c16c..0314c5227d2 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -1346,18 +1346,16 @@ void AOTCodeAddressTable::init_extrs() { SET_ADDRESS(_extrs, OptoRuntime::multianewarray4_C); SET_ADDRESS(_extrs, OptoRuntime::multianewarray5_C); SET_ADDRESS(_extrs, OptoRuntime::multianewarrayN_C); -#if INCLUDE_JVMTI - SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_start); - SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_end); - SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_mount); - SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_unmount); -#endif SET_ADDRESS(_extrs, OptoRuntime::complete_monitor_locking_C); SET_ADDRESS(_extrs, OptoRuntime::monitor_notify_C); SET_ADDRESS(_extrs, OptoRuntime::monitor_notifyAll_C); SET_ADDRESS(_extrs, OptoRuntime::rethrow_C); SET_ADDRESS(_extrs, OptoRuntime::slow_arraycopy_C); SET_ADDRESS(_extrs, OptoRuntime::register_finalizer_C); + SET_ADDRESS(_extrs, OptoRuntime::vthread_end_first_transition_C); + SET_ADDRESS(_extrs, OptoRuntime::vthread_start_final_transition_C); + SET_ADDRESS(_extrs, OptoRuntime::vthread_start_transition_C); + SET_ADDRESS(_extrs, OptoRuntime::vthread_end_transition_C); #if defined(AARCH64) SET_ADDRESS(_extrs, JavaThread::verify_cross_modify_fence_failure); #endif // AARCH64 diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index c2f8b46f00e..edfca5c98ee 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1498,6 +1498,40 @@ nmethod::nmethod(const nmethod &nm) : CodeBlob(nm._name, nm._kind, nm._size, nm. // - OOP table memcpy(consts_begin(), nm.consts_begin(), nm.data_end() - nm.consts_begin()); + // Fix relocation + RelocIterator iter(this); + CodeBuffer src(&nm); + CodeBuffer dst(this); + while (iter.next()) { +#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER + // After an nmethod is moved, some direct call sites may end up out of range. + // CallRelocation::fix_relocation_after_move() assumes the target is always + // reachable and does not check branch range. Calling it without range checks + // could cause us to write an offset too large for the instruction. + // + // If a call site has a trampoline, we skip the normal call relocation. The + // associated trampoline_stub_Relocation will handle the call and the + // trampoline, including range checks and updating the branch as needed. + // + // If no trampoline exists, we can assume the call target is always + // reachable and therefore within direct branch range, so calling + // CallRelocation::fix_relocation_after_move() is safe. + if (iter.reloc()->is_call()) { + address trampoline = trampoline_stub_Relocation::get_trampoline_for(iter.reloc()->addr(), this); + if (trampoline != nullptr) { + continue; + } + } +#endif + + iter.reloc()->fix_relocation_after_move(&src, &dst); + } + + { + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); + clear_inline_caches(); + } + post_init(); } @@ -1521,25 +1555,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { return nullptr; } - // Fix relocation - RelocIterator iter(nm_copy); - CodeBuffer src(this); - CodeBuffer dst(nm_copy); - while (iter.next()) { -#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER - // Direct calls may no longer be in range and the use of a trampoline may now be required. - // Instead, allow trampoline relocations to update their owners and perform the necessary checks. - if (iter.reloc()->is_call()) { - address trampoline = trampoline_stub_Relocation::get_trampoline_for(iter.reloc()->addr(), nm_copy); - if (trampoline != nullptr) { - continue; - } - } -#endif - - iter.reloc()->fix_relocation_after_move(&src, &dst); - } - // To make dependency checking during class loading fast, record // the nmethod dependencies in the classes it is dependent on. // This allows the dependency checking code to simply walk the @@ -1569,8 +1584,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { if (!is_marked_for_deoptimization() && is_in_use()) { assert(method() != nullptr && method()->code() == this, "should be if is in use"); - nm_copy->clear_inline_caches(); - // Attempt to start using the copy if (nm_copy->make_in_use()) { ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); @@ -1578,7 +1591,7 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { methodHandle mh(Thread::current(), nm_copy->method()); nm_copy->method()->set_code(mh, nm_copy); - make_not_used(); + make_not_entrant(InvalidationReason::RELOCATED); nm_copy->post_compiled_method_load_event(); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 0fa9d7fda9e..2391bc6d830 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -499,6 +499,7 @@ public: UNCOMMON_TRAP, WHITEBOX_DEOPTIMIZATION, ZOMBIE, + RELOCATED, INVALIDATION_REASONS_COUNT }; @@ -543,6 +544,8 @@ public: return "whitebox deoptimization"; case InvalidationReason::ZOMBIE: return "zombie"; + case InvalidationReason::RELOCATED: + return "relocated"; default: { assert(false, "Unhandled reason"); return "Unknown"; diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 4d291120e4a..9df3deedf89 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -891,9 +891,23 @@ void ParallelScavengeHeap::resize_after_young_gc(bool is_survivor_overflowing) { // Consider if should shrink old-gen if (!is_survivor_overflowing) { - // Upper bound for a single step shrink - size_t max_shrink_bytes = SpaceAlignment; + assert(old_gen()->capacity_in_bytes() >= old_gen()->min_gen_size(), "inv"); + + // Old gen min_gen_size constraint. + const size_t max_shrink_bytes_gen_size_constraint = old_gen()->capacity_in_bytes() - old_gen()->min_gen_size(); + + // Per-step delta to avoid too aggressive shrinking. + const size_t max_shrink_bytes_per_step_constraint = SpaceAlignment; + + // Combining the above two constraints. + const size_t max_shrink_bytes = MIN2(max_shrink_bytes_gen_size_constraint, + max_shrink_bytes_per_step_constraint); + size_t shrink_bytes = _size_policy->compute_old_gen_shrink_bytes(old_gen()->free_in_bytes(), max_shrink_bytes); + + assert(old_gen()->capacity_in_bytes() >= shrink_bytes, "inv"); + assert(old_gen()->capacity_in_bytes() - shrink_bytes >= old_gen()->min_gen_size(), "inv"); + if (shrink_bytes != 0) { if (MinHeapFreeRatio != 0) { size_t new_capacity = old_gen()->capacity_in_bytes() - shrink_bytes; diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 0b2ba44c780..9ccc7b95529 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -236,7 +236,10 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs, // These values are exported as performance counters. uintx size = _virtual_space.reserved_size(); _max_survivor_size = compute_survivor_size(size, SpaceAlignment); - _max_eden_size = size - (2*_max_survivor_size); + + // Eden might grow to be almost as large as the entire young generation. + // We approximate this as the entire virtual space. + _max_eden_size = size; // allocate the performance counters diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index faef3b89125..932c06b8109 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -147,7 +147,8 @@ GrowableArray SerialHeap::memory_pools() { HeapWord* SerialHeap::allocate_loaded_archive_space(size_t word_size) { MutexLocker ml(Heap_lock); - return old_gen()->allocate(word_size); + HeapWord* const addr = old_gen()->allocate(word_size); + return addr != nullptr ? addr : old_gen()->expand_and_allocate(word_size); } void SerialHeap::complete_loaded_archive_space(MemRegion archive_space) { diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp index 2181e089663..9635ed4d0cb 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp @@ -37,6 +37,7 @@ #include "utilities/copy.hpp" size_t ThreadLocalAllocBuffer::_max_size = 0; +int ThreadLocalAllocBuffer::_reserve_for_allocation_prefetch = 0; unsigned int ThreadLocalAllocBuffer::_target_refills = 0; ThreadLocalAllocBuffer::ThreadLocalAllocBuffer() : @@ -224,6 +225,30 @@ void ThreadLocalAllocBuffer::startup_initialization() { // abort during VM initialization. _target_refills = MAX2(_target_refills, 2U); +#ifdef COMPILER2 + // If the C2 compiler is present, extra space is needed at the end of + // TLABs, otherwise prefetching instructions generated by the C2 + // compiler will fault (due to accessing memory outside of heap). + // The amount of space is the max of the number of lines to + // prefetch for array and for instance allocations. (Extra space must be + // reserved to accommodate both types of allocations.) + // + // Only SPARC-specific BIS instructions are known to fault. (Those + // instructions are generated if AllocatePrefetchStyle==3 and + // AllocatePrefetchInstr==1). To be on the safe side, however, + // extra space is reserved for all combinations of + // AllocatePrefetchStyle and AllocatePrefetchInstr. + // + // If the C2 compiler is not present, no space is reserved. + + // +1 for rounding up to next cache line, +1 to be safe + if (CompilerConfig::is_c2_or_jvmci_compiler_enabled()) { + int lines = MAX2(AllocatePrefetchLines, AllocateInstancePrefetchLines) + 2; + _reserve_for_allocation_prefetch = (AllocatePrefetchDistance + AllocatePrefetchStepSize * lines) / + (int)HeapWordSize; + } +#endif + // During jvm startup, the main thread is initialized // before the heap is initialized. So reinitialize it now. guarantee(Thread::current()->is_Java_thread(), "tlab initialization thread not Java thread"); @@ -429,7 +454,8 @@ void ThreadLocalAllocStats::publish() { } size_t ThreadLocalAllocBuffer::end_reserve() { - return CollectedHeap::lab_alignment_reserve(); + size_t reserve_size = CollectedHeap::lab_alignment_reserve(); + return MAX2(reserve_size, (size_t)_reserve_for_allocation_prefetch); } const HeapWord* ThreadLocalAllocBuffer::start_relaxed() const { diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp index b64fa8d6ad1..59979646395 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp @@ -58,6 +58,7 @@ private: size_t _allocated_before_last_gc; // total bytes allocated up until the last gc static size_t _max_size; // maximum size of any TLAB + static int _reserve_for_allocation_prefetch; // Reserve at the end of the TLAB static unsigned _target_refills; // expected number of refills between GCs unsigned _number_of_refills; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp index 05ecfb254a2..c667048ad47 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp @@ -83,16 +83,15 @@ public: return "PLAB"; default: ShouldNotReachHere(); - return ""; } } private: // When ShenandoahElasticTLAB is enabled, the request cannot be made smaller than _min_size. - size_t _min_size; + size_t const _min_size; // The size of the request in words. - size_t _requested_size; + size_t const _requested_size; // The allocation may be increased for padding or decreased to fit in the remaining space of a region. size_t _actual_size; @@ -104,7 +103,7 @@ private: size_t _waste; // This is the type of the request. - Type _alloc_type; + Type const _alloc_type; #ifdef ASSERT // Check that this is set before being read. @@ -209,6 +208,10 @@ public: return (_alloc_type & bit_old_alloc) == 0; } + inline bool is_cds() const { + return _alloc_type == _alloc_cds; + } + inline ShenandoahAffiliation affiliation() const { return (_alloc_type & bit_old_alloc) == 0 ? YOUNG_GENERATION : OLD_GENERATION ; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp index ec39e0c0ccb..07d339eb32e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp @@ -144,13 +144,12 @@ public: { ShenandoahReentrantLocker locker(nm_data->lock()); - // Heal oops and disarm + // Heal oops if (_bs->is_armed(nm)) { ShenandoahEvacOOMScope oom_evac_scope; ShenandoahNMethod::heal_nmethod_metadata(nm_data); - // Code cache unloading needs to know about on-stack nmethods. Arm the nmethods to get - // mark_as_maybe_on_stack() callbacks when they are used again. - _bs->arm(nm); + // Must remain armed to complete remaining work in nmethod entry barrier + assert(_bs->is_armed(nm), "Should remain armed"); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index ab7985b3d34..eb05bf24028 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -175,7 +175,6 @@ ShenandoahRegionPartitions::ShenandoahRegionPartitions(size_t max_regions, Shena void ShenandoahFreeSet::account_for_pip_regions(size_t mutator_regions, size_t mutator_bytes, size_t collector_regions, size_t collector_bytes) { shenandoah_assert_heaplocked(); - size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); // We have removed all of these regions from their respective partition. Each pip region is "in" the NotFree partition. // We want to account for all pip pad memory as if it had been consumed from within the Mutator partition. @@ -1370,7 +1369,7 @@ template HeapWord* ShenandoahFreeSet::allocate_from_regions(Iter& iterator, ShenandoahAllocRequest &req, bool &in_new_region) { for (idx_t idx = iterator.current(); iterator.has_next(); idx = iterator.next()) { ShenandoahHeapRegion* r = _heap->get_region(idx); - size_t min_size = (req.type() == ShenandoahAllocRequest::_alloc_tlab) ? req.min_size() : req.size(); + size_t min_size = req.is_lab_alloc() ? req.min_size() : req.size(); if (alloc_capacity(r) >= min_size * HeapWordSize) { HeapWord* result = try_allocate_in(r, req, in_new_region); if (result != nullptr) { @@ -1502,7 +1501,7 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah if (in_new_region) { log_debug(gc, free)("Using new region (%zu) for %s (" PTR_FORMAT ").", - r->index(), ShenandoahAllocRequest::alloc_type_to_string(req.type()), p2i(&req)); + r->index(), req.type_string(), p2i(&req)); assert(!r->is_affiliated(), "New region %zu should be unaffiliated", r->index()); r->set_affiliation(req.affiliation()); if (r->is_old()) { @@ -1521,7 +1520,7 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah assert(ctx->is_bitmap_range_within_region_clear(ctx->top_bitmap(r), r->end()), "Bitmap above top_bitmap() must be clear"); #endif log_debug(gc, free)("Using new region (%zu) for %s (" PTR_FORMAT ").", - r->index(), ShenandoahAllocRequest::alloc_type_to_string(req.type()), p2i(&req)); + r->index(), req.type_string(), p2i(&req)); } else { assert(r->is_affiliated(), "Region %zu that is not new should be affiliated", r->index()); if (r->affiliation() != req.affiliation()) { @@ -1535,8 +1534,8 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah if (req.is_lab_alloc()) { size_t adjusted_size = req.size(); size_t free = r->free(); // free represents bytes available within region r - if (req.type() == ShenandoahAllocRequest::_alloc_plab) { - // This is a PLAB allocation + if (req.is_old()) { + // This is a PLAB allocation(lab alloc in old gen) assert(_heap->mode()->is_generational(), "PLABs are only for generational mode"); assert(_partitions.in_free_set(ShenandoahFreeSetPartitionId::OldCollector, r->index()), "PLABS must be allocated in old_collector_free regions"); @@ -1597,26 +1596,19 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah r->set_update_watermark(r->top()); if (r->is_old()) { _partitions.increase_used(ShenandoahFreeSetPartitionId::OldCollector, (req.actual_size() + req.waste()) * HeapWordSize); - assert(req.type() != ShenandoahAllocRequest::_alloc_gclab, "old-gen allocations use PLAB or shared allocation"); - // for plabs, we'll sort the difference between evac and promotion usage when we retire the plab } else { _partitions.increase_used(ShenandoahFreeSetPartitionId::Collector, (req.actual_size() + req.waste()) * HeapWordSize); } } } - size_t ac = alloc_capacity(r); ShenandoahFreeSetPartitionId orig_partition; - ShenandoahGeneration* request_generation = nullptr; if (req.is_mutator_alloc()) { - request_generation = _heap->mode()->is_generational()? _heap->young_generation(): _heap->global_generation(); orig_partition = ShenandoahFreeSetPartitionId::Mutator; } else if (req.is_old()) { - request_generation = _heap->old_generation(); orig_partition = ShenandoahFreeSetPartitionId::OldCollector; } else { // Not old collector alloc, so this is a young collector gclab or shared allocation - request_generation = _heap->mode()->is_generational()? _heap->young_generation(): _heap->global_generation(); orig_partition = ShenandoahFreeSetPartitionId::Collector; } if (alloc_capacity(r) < PLAB::min_size() * HeapWordSize) { @@ -1688,7 +1680,6 @@ HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req, bo idx_t num = ShenandoahHeapRegion::required_regions(words_size * HeapWordSize); assert(req.is_young(), "Humongous regions always allocated in YOUNG"); - ShenandoahGeneration* generation = _heap->generation_for(req.affiliation()); // Check if there are enough regions left to satisfy allocation. if (num > (idx_t) _partitions.count(ShenandoahFreeSetPartitionId::Mutator)) { @@ -1833,107 +1824,7 @@ HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req, bo } class ShenandoahRecycleTrashedRegionClosure final : public ShenandoahHeapRegionClosure { -private: - static const ssize_t SentinelUsed = -1; - static const ssize_t SentinelIndex = -1; - static const size_t MaxSavedRegions = 128; - - ShenandoahRegionPartitions* _partitions; - volatile size_t _recycled_region_count; - ssize_t _region_indices[MaxSavedRegions]; - ssize_t _region_used[MaxSavedRegions]; - - void get_lock_and_flush_buffer(size_t region_count, size_t overflow_region_used, size_t overflow_region_index) { - ShenandoahHeap* heap = ShenandoahHeap::heap(); - ShenandoahHeapLocker locker(heap->lock()); - size_t recycled_regions = AtomicAccess::load(&_recycled_region_count); - size_t region_tallies[int(ShenandoahRegionPartitions::NumPartitions)]; - size_t used_byte_tallies[int(ShenandoahRegionPartitions::NumPartitions)]; - for (int p = 0; p < int(ShenandoahRegionPartitions::NumPartitions); p++) { - region_tallies[p] = 0; - used_byte_tallies[p] = 0; - } - ShenandoahFreeSetPartitionId p = _partitions->membership(overflow_region_index); - used_byte_tallies[int(p)] += overflow_region_used; - if (region_count <= recycled_regions) { - // _recycled_region_count has not been decremented after I incremented it to obtain region_count, so I will - // try to flush the buffer. - - // Multiple worker threads may attempt to flush this buffer. The first thread to acquire the lock does the work. - // _recycled_region_count is only decreased while holding the heap lock. - if (region_count > recycled_regions) { - region_count = recycled_regions; - } - for (size_t i = 0; i < region_count; i++) { - ssize_t used; - // wait for other threads to finish updating their entries within the region buffer before processing entry - do { - used = _region_used[i]; - } while (used == SentinelUsed); - ssize_t index; - do { - index = _region_indices[i]; - } while (index == SentinelIndex); - - ShenandoahFreeSetPartitionId p = _partitions->membership(index); - assert(p != ShenandoahFreeSetPartitionId::NotFree, "Trashed regions should be in a free partition"); - used_byte_tallies[int(p)] += used; - region_tallies[int(p)]++; - } - if (region_count > 0) { - for (size_t i = 0; i < MaxSavedRegions; i++) { - _region_indices[i] = SentinelIndex; - _region_used[i] = SentinelUsed; - } - } - - // The almost last thing we do before releasing the lock is to set the _recycled_region_count to 0. What happens next? - // - // 1. Any worker thread that attempted to buffer a new region while we were flushing the buffer will have seen - // that _recycled_region_count > MaxSavedRegions. All such worker threads will first wait for the lock, then - // discover that the _recycled_region_count is zero, then, while holding the lock, they will process the - // region so it doesn't have to be placed into the buffer. This handles the large majority of cases. - // - // 2. However, there's a race that can happen, which will result in someewhat different behavior. Suppose - // this thread resets _recycled_region_count to 0. Then some other worker thread increments _recycled_region_count - // in order to stores its region into the buffer and suppose this happens before all of the other worker threads - // which are waiting to acquire the heap lock have finished their efforts to flush the buffer. If this happens, - // then the workers who are waiting to acquire the heap lock and flush the buffer will find that _recycled_region_count - // has decreased from the value it held when they last tried to increment its value. In this case, these worker - // threads will process their overflow region while holding the lock, but they will not attempt to process regions - // newly placed into the buffer. Otherwise, confusion could result. - // - // Assumption: all worker threads who are attempting to acquire lock and flush buffer will finish their efforts before - // the buffer once again overflows. - // How could we avoid depending on this assumption? - // 1. Let MaxSavedRegions be as large as number of regions, or at least as large as the collection set. - // 2. Keep a count of how many times the buffer has been flushed per instantation of the - // ShenandoahRecycleTrashedRegionClosure object, and only consult/update this value while holding the heap lock. - // Need to think about how this helps resolve the race. - _recycled_region_count = 0; - } else { - // Some other thread has already processed the buffer, resetting _recycled_region_count to zero. Its current value - // may be greater than zero because other workers may have accumulated entries into the buffer. But it is "extremely" - // unlikely that it will overflow again before all waiting workers have had a chance to clear their state. While I've - // got the heap lock, I'll go ahead and update the global state for my overflow region. I'll let other heap regions - // accumulate in the buffer to be processed when the buffer is once again full. - region_count = 0; - } - for (size_t p = 0; p < int(ShenandoahRegionPartitions::NumPartitions); p++) { - _partitions->decrease_used(ShenandoahFreeSetPartitionId(p), used_byte_tallies[p]); - } - } - public: - ShenandoahRecycleTrashedRegionClosure(ShenandoahRegionPartitions* p): ShenandoahHeapRegionClosure() { - _partitions = p; - _recycled_region_count = 0; - for (size_t i = 0; i < MaxSavedRegions; i++) { - _region_indices[i] = SentinelIndex; - _region_used[i] = SentinelUsed; - } - } - void heap_region_do(ShenandoahHeapRegion* r) { r->try_recycle(); } @@ -1950,14 +1841,12 @@ void ShenandoahFreeSet::recycle_trash() { ShenandoahHeap* heap = ShenandoahHeap::heap(); heap->assert_gc_workers(heap->workers()->active_workers()); - ShenandoahRecycleTrashedRegionClosure closure(&_partitions); + ShenandoahRecycleTrashedRegionClosure closure; heap->parallel_heap_region_iterate(&closure); } bool ShenandoahFreeSet::transfer_one_region_from_mutator_to_old_collector(size_t idx, size_t alloc_capacity) { ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); - ShenandoahYoungGeneration* young_gen = gen_heap->young_generation(); - ShenandoahOldGeneration* old_gen = gen_heap->old_generation(); size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); assert(alloc_capacity == region_size_bytes, "Region must be empty"); if (young_unaffiliated_regions() > 0) { @@ -1985,7 +1874,6 @@ bool ShenandoahFreeSet::flip_to_old_gc(ShenandoahHeapRegion* r) { assert(_partitions.partition_id_matches(idx, ShenandoahFreeSetPartitionId::Mutator), "Should be in mutator view"); assert(can_allocate_from(r), "Should not be allocated"); - ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); const size_t region_alloc_capacity = alloc_capacity(r); if (transfer_one_region_from_mutator_to_old_collector(idx, region_alloc_capacity)) { @@ -2133,7 +2021,6 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r size_t total_mutator_regions = 0; size_t total_old_collector_regions = 0; - bool is_generational = _heap->mode()->is_generational(); size_t num_regions = _heap->num_regions(); for (size_t idx = 0; idx < num_regions; idx++) { ShenandoahHeapRegion* region = _heap->get_region(idx); @@ -2222,7 +2109,6 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r } } else { assert(_partitions.membership(idx) == ShenandoahFreeSetPartitionId::NotFree, "Region should have been retired"); - size_t ac = alloc_capacity(region); size_t humongous_waste_bytes = 0; if (region->is_humongous_start()) { oop obj = cast_to_oop(region->bottom()); @@ -3120,7 +3006,6 @@ void ShenandoahFreeSet::log_status() { size_t total_used = 0; size_t total_free = 0; size_t total_free_ext = 0; - size_t total_trashed_free = 0; for (idx_t idx = _partitions.leftmost(ShenandoahFreeSetPartitionId::Mutator); idx <= _partitions.rightmost(ShenandoahFreeSetPartitionId::Mutator); idx++) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index ea421365614..55d6033b3bc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -76,6 +76,9 @@ public: } } + // Bitmap reset task is heavy-weight and benefits from much smaller tasks than the default. + size_t parallel_region_stride() override { return 8; } + bool is_thread_safe() override { return true; } }; @@ -524,7 +527,6 @@ size_t ShenandoahGeneration::select_aged_regions(const size_t old_promotion_rese assert_no_in_place_promotions(); auto const heap = ShenandoahGenerationalHeap::heap(); - ShenandoahYoungGeneration* young_gen = heap->young_generation(); ShenandoahFreeSet* free_set = heap->free_set(); bool* const candidate_regions_for_promotion_by_copy = heap->collection_set()->preselected_regions(); ShenandoahMarkingContext* const ctx = heap->marking_context(); @@ -562,7 +564,6 @@ size_t ShenandoahGeneration::select_aged_regions(const size_t old_promotion_rese size_t pip_mutator_bytes = 0; size_t pip_collector_bytes = 0; - size_t min_remnant_size = PLAB::min_size() * HeapWordSize; for (idx_t i = 0; i < num_regions; i++) { ShenandoahHeapRegion* const r = heap->get_region(i); if (r->is_empty() || !r->has_live() || !r->is_young() || !r->is_regular()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index 134ae371bce..f887cc9064e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -688,19 +688,6 @@ void ShenandoahGenerationalHeap::reset_generation_reserves() { old_generation()->set_promoted_reserve(0); } -void ShenandoahGenerationalHeap::TransferResult::print_on(const char* when, outputStream* ss) const { - auto heap = ShenandoahGenerationalHeap::heap(); - ShenandoahYoungGeneration* const young_gen = heap->young_generation(); - ShenandoahOldGeneration* const old_gen = heap->old_generation(); - const size_t young_available = young_gen->available(); - const size_t old_available = old_gen->available(); - ss->print_cr("After %s, %s %zu regions to %s to prepare for next gc, old available: " - PROPERFMT ", young_available: " PROPERFMT, - when, - success? "successfully transferred": "failed to transfer", region_count, region_destination, - PROPERFMTARGS(old_available), PROPERFMTARGS(young_available)); -} - void ShenandoahGenerationalHeap::coalesce_and_fill_old_regions(bool concurrent) { class ShenandoahGlobalCoalesceAndFill : public WorkerTask { private: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp index 704c8538397..736026916f7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp @@ -132,24 +132,12 @@ public: bool requires_barriers(stackChunkOop obj) const override; - // Used for logging the result of a region transfer outside the heap lock - struct TransferResult { - bool success; - size_t region_count; - const char* region_destination; - - void print_on(const char* when, outputStream* ss) const; - }; - // Zeros out the evacuation and promotion reserves void reset_generation_reserves(); // Computes the optimal size for the old generation, represented as a surplus or deficit of old regions void compute_old_generation_balance(size_t old_xfer_limit, size_t old_cset_regions); - // Transfers surplus old regions to young, or takes regions from young to satisfy old region deficit - TransferResult balance_generations(); - // Balances generations, coalesces and fills old regions if necessary void complete_degenerated_cycle(); void complete_concurrent_cycle(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 5c4d10ca8a5..3bf53f800a2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -985,7 +985,7 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) { assert (req.is_lab_alloc() || (requested == actual), "Only LAB allocations are elastic: %s, requested = %zu, actual = %zu", - ShenandoahAllocRequest::alloc_type_to_string(req.type()), requested, actual); + req.type_string(), requested, actual); } return result; @@ -1014,8 +1014,9 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req // Record the plab configuration for this result and register the object. if (result != nullptr && req.is_old()) { - old_generation()->configure_plab_for_current_thread(req); - if (!req.is_lab_alloc()) { + if (req.is_lab_alloc()) { + old_generation()->configure_plab_for_current_thread(req); + } else { // Register the newly allocated object while we're holding the global lock since there's no synchronization // built in to the implementation of register_object(). There are potential races when multiple independent // threads are allocating objects, some of which might span the same card region. For example, consider @@ -1035,6 +1036,13 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req // last-start representing object b while first-start represents object c. This is why we need to require all // register_object() invocations to be "mutually exclusive" with respect to each card's memory range. old_generation()->card_scan()->register_object(result); + + if (req.is_promotion()) { + // Shared promotion. + const size_t actual_size = req.actual_size() * HeapWordSize; + log_debug(gc, plab)("Expend shared promotion of %zu bytes", actual_size); + old_generation()->expend_promoted(actual_size); + } } } @@ -1962,7 +1970,7 @@ void ShenandoahHeap::parallel_heap_region_iterate(ShenandoahHeapRegionClosure* b assert(blk->is_thread_safe(), "Only thread-safe closures here"); const uint active_workers = workers()->active_workers(); const size_t n_regions = num_regions(); - size_t stride = ShenandoahParallelRegionStride; + size_t stride = blk->parallel_region_stride(); if (stride == 0 && active_workers > 1) { // Automatically derive the stride to balance the work between threads // evenly. Do not try to split work if below the reasonable threshold. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index cd388ee7cf3..65e3803627c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -113,6 +113,7 @@ public: class ShenandoahHeapRegionClosure : public StackObj { public: virtual void heap_region_do(ShenandoahHeapRegion* r) = 0; + virtual size_t parallel_region_stride() { return ShenandoahParallelRegionStride; } virtual bool is_thread_safe() { return false; } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index 32382f5e594..2ed5614c698 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -447,7 +447,7 @@ public: return (bottom() <= p) && (p < top()); } - inline void adjust_alloc_metadata(ShenandoahAllocRequest::Type type, size_t); + inline void adjust_alloc_metadata(const ShenandoahAllocRequest &req, size_t); void reset_alloc_metadata(); size_t get_shared_allocs() const; size_t get_tlab_allocs() const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp index 636f65e2553..69673eb7a60 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp @@ -71,7 +71,7 @@ HeapWord* ShenandoahHeapRegion::allocate_aligned(size_t size, ShenandoahAllocReq } make_regular_allocation(req.affiliation()); - adjust_alloc_metadata(req.type(), size); + adjust_alloc_metadata(req, size); HeapWord* new_top = aligned_obj + size; assert(new_top <= end(), "PLAB cannot span end of heap region"); @@ -111,7 +111,7 @@ HeapWord* ShenandoahHeapRegion::allocate(size_t size, const ShenandoahAllocReque HeapWord* obj = top(); if (pointer_delta(end(), obj) >= size) { make_regular_allocation(req.affiliation()); - adjust_alloc_metadata(req.type(), size); + adjust_alloc_metadata(req, size); HeapWord* new_top = obj + size; set_top(new_top); @@ -125,26 +125,16 @@ HeapWord* ShenandoahHeapRegion::allocate(size_t size, const ShenandoahAllocReque } } -inline void ShenandoahHeapRegion::adjust_alloc_metadata(ShenandoahAllocRequest::Type type, size_t size) { - switch (type) { - case ShenandoahAllocRequest::_alloc_shared: - case ShenandoahAllocRequest::_alloc_shared_gc: - case ShenandoahAllocRequest::_alloc_shared_gc_old: - case ShenandoahAllocRequest::_alloc_shared_gc_promotion: - case ShenandoahAllocRequest::_alloc_cds: - // Counted implicitly by tlab/gclab allocs - break; - case ShenandoahAllocRequest::_alloc_tlab: +inline void ShenandoahHeapRegion::adjust_alloc_metadata(const ShenandoahAllocRequest &req, size_t size) { + // Only need to update alloc metadata for lab alloc, shared alloc is counted implicitly by tlab/gclab allocs + if (req.is_lab_alloc()) { + if (req.is_mutator_alloc()) { _tlab_allocs += size; - break; - case ShenandoahAllocRequest::_alloc_gclab: - _gclab_allocs += size; - break; - case ShenandoahAllocRequest::_alloc_plab: + } else if (req.is_old()) { _plab_allocs += size; - break; - default: - ShouldNotReachHere(); + } else { + _gclab_allocs += size; + } } } @@ -157,7 +147,7 @@ inline void ShenandoahHeapRegion::increase_live_data_gc_words(size_t s) { } inline void ShenandoahHeapRegion::internal_increase_live_data(size_t s) { - size_t new_live_data = AtomicAccess::add(&_live_data, s, memory_order_relaxed); + AtomicAccess::add(&_live_data, s, memory_order_relaxed); } inline void ShenandoahHeapRegion::clear_live_data() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp index 0daf268628c..3f3b57c9bb2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp @@ -44,6 +44,10 @@ public: } } + size_t parallel_region_stride() override { + return _closure->parallel_region_stride(); + } + bool is_thread_safe() override { return _closure->is_thread_safe(); } @@ -64,6 +68,10 @@ public: } } + size_t parallel_region_stride() override { + return _closure->parallel_region_stride(); + } + bool is_thread_safe() override { return _closure->is_thread_safe(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 838326c0288..6a0f986cde5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -168,7 +168,7 @@ size_t ShenandoahOldGeneration::get_promoted_expended() const { } bool ShenandoahOldGeneration::can_allocate(const ShenandoahAllocRequest &req) const { - assert(req.type() != ShenandoahAllocRequest::_alloc_gclab, "GCLAB pertains only to young-gen memory"); + assert(req.is_old(), "Must be old allocation request"); const size_t requested_bytes = req.size() * HeapWordSize; // The promotion reserve may also be used for evacuations. If we can promote this object, @@ -180,7 +180,7 @@ bool ShenandoahOldGeneration::can_allocate(const ShenandoahAllocRequest &req) co return true; } - if (req.type() == ShenandoahAllocRequest::_alloc_plab) { + if (req.is_lab_alloc()) { // The promotion reserve cannot accommodate this plab request. Check if we still have room for // evacuations. Note that we cannot really know how much of the plab will be used for evacuations, // so here we only check that some evacuation reserve still exists. @@ -195,37 +195,29 @@ bool ShenandoahOldGeneration::can_allocate(const ShenandoahAllocRequest &req) co void ShenandoahOldGeneration::configure_plab_for_current_thread(const ShenandoahAllocRequest &req) { - // Note: Even when a mutator is performing a promotion outside a LAB, we use a 'shared_gc' request. - if (req.is_gc_alloc()) { - const size_t actual_size = req.actual_size() * HeapWordSize; - if (req.type() == ShenandoahAllocRequest::_alloc_plab) { - // We've created a new plab. Now we configure it whether it will be used for promotions - // and evacuations - or just evacuations. - Thread* thread = Thread::current(); - ShenandoahThreadLocalData::reset_plab_promoted(thread); + assert(req.is_gc_alloc() && req.is_old() && req.is_lab_alloc(), "Must be a plab alloc request"); + const size_t actual_size = req.actual_size() * HeapWordSize; + // We've created a new plab. Now we configure it whether it will be used for promotions + // and evacuations - or just evacuations. + Thread* thread = Thread::current(); + ShenandoahThreadLocalData::reset_plab_promoted(thread); - // The actual size of the allocation may be larger than the requested bytes (due to alignment on card boundaries). - // If this puts us over our promotion budget, we need to disable future PLAB promotions for this thread. - if (can_promote(actual_size)) { - // Assume the entirety of this PLAB will be used for promotion. This prevents promotion from overreach. - // When we retire this plab, we'll unexpend what we don't really use. - log_debug(gc, plab)("Thread can promote using PLAB of %zu bytes. Expended: %zu, available: %zu", - actual_size, get_promoted_expended(), get_promoted_reserve()); - expend_promoted(actual_size); - ShenandoahThreadLocalData::enable_plab_promotions(thread); - ShenandoahThreadLocalData::set_plab_actual_size(thread, actual_size); - } else { - // Disable promotions in this thread because entirety of this PLAB must be available to hold old-gen evacuations. - ShenandoahThreadLocalData::disable_plab_promotions(thread); - ShenandoahThreadLocalData::set_plab_actual_size(thread, 0); - log_debug(gc, plab)("Thread cannot promote using PLAB of %zu bytes. Expended: %zu, available: %zu, mixed evacuations? %s", - actual_size, get_promoted_expended(), get_promoted_reserve(), BOOL_TO_STR(ShenandoahHeap::heap()->collection_set()->has_old_regions())); - } - } else if (req.is_promotion()) { - // Shared promotion. - log_debug(gc, plab)("Expend shared promotion of %zu bytes", actual_size); - expend_promoted(actual_size); - } + // The actual size of the allocation may be larger than the requested bytes (due to alignment on card boundaries). + // If this puts us over our promotion budget, we need to disable future PLAB promotions for this thread. + if (can_promote(actual_size)) { + // Assume the entirety of this PLAB will be used for promotion. This prevents promotion from overreach. + // When we retire this plab, we'll unexpend what we don't really use. + log_debug(gc, plab)("Thread can promote using PLAB of %zu bytes. Expended: %zu, available: %zu", + actual_size, get_promoted_expended(), get_promoted_reserve()); + expend_promoted(actual_size); + ShenandoahThreadLocalData::enable_plab_promotions(thread); + ShenandoahThreadLocalData::set_plab_actual_size(thread, actual_size); + } else { + // Disable promotions in this thread because entirety of this PLAB must be available to hold old-gen evacuations. + ShenandoahThreadLocalData::disable_plab_promotions(thread); + ShenandoahThreadLocalData::set_plab_actual_size(thread, 0); + log_debug(gc, plab)("Thread cannot promote using PLAB of %zu bytes. Expended: %zu, available: %zu, mixed evacuations? %s", + actual_size, get_promoted_expended(), get_promoted_reserve(), BOOL_TO_STR(ShenandoahHeap::heap()->collection_set()->has_old_regions())); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp index c23690b15d6..2519025b6fb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp @@ -62,7 +62,6 @@ class ShenandoahRegulatorThread: public ConcurrentGCThread { bool start_old_cycle() const; bool start_young_cycle() const; bool start_global_cycle() const; - bool resume_old_cycle(); // The generational mode can only unload classes in a global cycle. The regulator // thread itself will trigger a global cycle if metaspace is out of memory. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp index 44064dbd1a9..a3c96a7d53b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp @@ -335,7 +335,6 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con if (ctx->is_marked(p)) { oop obj = cast_to_oop(p); assert(oopDesc::is_oop(obj), "Should be an object"); - assert(Klass::is_valid(obj->klass()), "Not a valid klass ptr"); assert(p + obj->size() > left, "This object should span start of card"); assert(p < right, "Result must precede right"); return p; @@ -362,15 +361,15 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con // Recall that we already dealt with the co-initial object case above assert(p < left, "obj should start before left"); - // While it is safe to ask an object its size in the loop that - // follows, the (ifdef'd out) loop should never be needed. + // While it is safe to ask an object its size in the block that + // follows, the (ifdef'd out) block should never be needed. // 1. we ask this question only for regions in the old generation, and those // that are not humongous regions // 2. there is no direct allocation ever by mutators in old generation // regions walked by this code. Only GC will ever allocate in old regions, // and then too only during promotion/evacuation phases. Thus there is no danger // of races between reading from and writing to the object start array, - // or of asking partially initialized objects their size (in the loop below). + // or of asking partially initialized objects their size (in the ifdef below). // Furthermore, humongous regions (and their dirty cards) are never processed // by this code. // 3. only GC asks this question during phases when it is not concurrently @@ -382,15 +381,6 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con #ifdef ASSERT oop obj = cast_to_oop(p); assert(oopDesc::is_oop(obj), "Should be an object"); - while (p + obj->size() < left) { - p += obj->size(); - obj = cast_to_oop(p); - assert(oopDesc::is_oop(obj), "Should be an object"); - assert(Klass::is_valid(obj->klass()), "Not a valid klass ptr"); - // Check assumptions in previous block comment if this assert fires - fatal("Should never need forward walk in block start"); - } - assert(p <= left, "p should start at or before left end of card"); assert(p + obj->size() > left, "obj should end after left end of card"); #endif // ASSERT return p; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp index 9a0d28d2cb7..c758873a040 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -233,8 +233,6 @@ public: inline bool is_write_card_dirty(size_t card_index) const; inline void mark_card_as_dirty(size_t card_index); inline void mark_range_as_dirty(size_t card_index, size_t num_cards); - inline void mark_card_as_clean(size_t card_index); - inline void mark_range_as_clean(size_t card_index, size_t num_cards); inline bool is_card_dirty(HeapWord* p) const; inline bool is_write_card_dirty(HeapWord* p) const; inline void mark_card_as_dirty(HeapWord* p); diff --git a/src/hotspot/share/gc/z/zBarrierSet.cpp b/src/hotspot/share/gc/z/zBarrierSet.cpp index 643eba1947e..15b694b2ecc 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.cpp +++ b/src/hotspot/share/gc/z/zBarrierSet.cpp @@ -217,11 +217,10 @@ static void deoptimize_allocation(JavaThread* thread) { void ZBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) { const ZPage* const page = ZHeap::heap()->page(to_zaddress(new_obj)); - const ZPageAge age = page->age(); - if (age == ZPageAge::old) { + if (!page->allows_raw_null()) { // We promised C2 that its allocations would end up in young gen. This object - // breaks that promise. Take a few steps in the interpreter instead, which has - // no such assumptions about where an object resides. + // is too old to guarantee that. Take a few steps in the interpreter instead, + // which does not elide barriers based on the age of an object. deoptimize_allocation(thread); } } diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 2b632ef29a9..a8c646bf895 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -190,7 +190,8 @@ void ZGeneration::flip_age_pages(const ZRelocationSetSelector* selector) { ZRendezvousHandshakeClosure cl; Handshake::execute(&cl); - _relocate.barrier_flip_promoted_pages(_relocation_set.flip_promoted_pages()); + _relocate.barrier_promoted_pages(_relocation_set.flip_promoted_pages(), + _relocation_set.relocate_promoted_pages()); } static double fragmentation_limit(ZGenerationId generation) { diff --git a/src/hotspot/share/gc/z/zPage.cpp b/src/hotspot/share/gc/z/zPage.cpp index 9f4654a655f..b6e0d162ef0 100644 --- a/src/hotspot/share/gc/z/zPage.cpp +++ b/src/hotspot/share/gc/z/zPage.cpp @@ -41,7 +41,8 @@ ZPage::ZPage(ZPageType type, ZPageAge age, const ZVirtualMemory& vmem, ZMultiPar _top(to_zoffset_end(start())), _livemap(object_max_count()), _remembered_set(), - _multi_partition_tracker(multi_partition_tracker) { + _multi_partition_tracker(multi_partition_tracker), + _relocate_promoted(false) { assert(!_virtual.is_null(), "Should not be null"); assert((_type == ZPageType::small && size() == ZPageSizeSmall) || (_type == ZPageType::medium && ZPageSizeMediumMin <= size() && size() <= ZPageSizeMediumMax) || @@ -70,6 +71,14 @@ ZPage* ZPage::clone_for_promotion() const { return page; } +bool ZPage::allows_raw_null() const { + return is_young() && !AtomicAccess::load(&_relocate_promoted); +} + +void ZPage::set_is_relocate_promoted() { + AtomicAccess::store(&_relocate_promoted, true); +} + ZGeneration* ZPage::generation() { return ZGeneration::generation(_generation_id); } diff --git a/src/hotspot/share/gc/z/zPage.hpp b/src/hotspot/share/gc/z/zPage.hpp index 96900a37680..0fc134e170a 100644 --- a/src/hotspot/share/gc/z/zPage.hpp +++ b/src/hotspot/share/gc/z/zPage.hpp @@ -52,6 +52,7 @@ private: ZLiveMap _livemap; ZRememberedSet _remembered_set; ZMultiPartitionTracker* const _multi_partition_tracker; + volatile bool _relocate_promoted; const char* type_to_string() const; @@ -103,6 +104,9 @@ public: ZPageAge age() const; + bool allows_raw_null() const; + void set_is_relocate_promoted(); + uint32_t seqnum() const; bool is_allocating() const; bool is_relocatable() const; diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 24c4bdeac16..da07f67d859 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -1366,27 +1366,35 @@ public: class ZPromoteBarrierTask : public ZTask { private: - ZArrayParallelIterator _iter; + ZArrayParallelIterator _flip_promoted_iter; + ZArrayParallelIterator _relocate_promoted_iter; public: - ZPromoteBarrierTask(const ZArray* pages) + ZPromoteBarrierTask(const ZArray* flip_promoted_pages, + const ZArray* relocate_promoted_pages) : ZTask("ZPromoteBarrierTask"), - _iter(pages) {} + _flip_promoted_iter(flip_promoted_pages), + _relocate_promoted_iter(relocate_promoted_pages) {} virtual void work() { SuspendibleThreadSetJoiner sts_joiner; - for (ZPage* page; _iter.next(&page);) { - // When promoting an object (and before relocate start), we must ensure that all - // contained zpointers are store good. The marking code ensures that for non-null - // pointers, but null pointers are ignored. This code ensures that even null pointers - // are made store good, for the promoted objects. - page->object_iterate([&](oop obj) { - ZIterator::basic_oop_iterate_safe(obj, ZBarrier::promote_barrier_on_young_oop_field); - }); + auto promote_barriers = [&](ZArrayParallelIterator* iter) { + for (ZPage* page; iter->next(&page);) { + // When promoting an object (and before relocate start), we must ensure that all + // contained zpointers are store good. The marking code ensures that for non-null + // pointers, but null pointers are ignored. This code ensures that even null pointers + // are made store good, for the promoted objects. + page->object_iterate([&](oop obj) { + ZIterator::basic_oop_iterate_safe(obj, ZBarrier::promote_barrier_on_young_oop_field); + }); - SuspendibleThreadSet::yield(); - } + SuspendibleThreadSet::yield(); + } + }; + + promote_barriers(&_flip_promoted_iter); + promote_barriers(&_relocate_promoted_iter); } }; @@ -1395,8 +1403,9 @@ void ZRelocate::flip_age_pages(const ZArray* pages) { workers()->run(&flip_age_task); } -void ZRelocate::barrier_flip_promoted_pages(const ZArray* pages) { - ZPromoteBarrierTask promote_barrier_task(pages); +void ZRelocate::barrier_promoted_pages(const ZArray* flip_promoted_pages, + const ZArray* relocate_promoted_pages) { + ZPromoteBarrierTask promote_barrier_task(flip_promoted_pages, relocate_promoted_pages); workers()->run(&promote_barrier_task); } diff --git a/src/hotspot/share/gc/z/zRelocate.hpp b/src/hotspot/share/gc/z/zRelocate.hpp index 50111f24ee5..038efba83eb 100644 --- a/src/hotspot/share/gc/z/zRelocate.hpp +++ b/src/hotspot/share/gc/z/zRelocate.hpp @@ -119,7 +119,8 @@ public: void relocate(ZRelocationSet* relocation_set); void flip_age_pages(const ZArray* pages); - void barrier_flip_promoted_pages(const ZArray* pages); + void barrier_promoted_pages(const ZArray* flip_promoted_pages, + const ZArray* relocate_promoted_pages); void synchronize(); void desynchronize(); diff --git a/src/hotspot/share/gc/z/zRelocationSet.cpp b/src/hotspot/share/gc/z/zRelocationSet.cpp index fb865934690..95ca6e56c45 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.cpp +++ b/src/hotspot/share/gc/z/zRelocationSet.cpp @@ -38,6 +38,7 @@ class ZRelocationSetInstallTask : public ZTask { private: + ZRelocationSet* _relocation_set; ZForwardingAllocator* const _allocator; ZForwarding** _forwardings; const size_t _nforwardings; @@ -54,16 +55,6 @@ private: page->log_msg(" (relocation selected)"); _forwardings[index] = forwarding; - - if (forwarding->is_promotion()) { - // Before promoting an object (and before relocate start), we must ensure that all - // contained zpointers are store good. The marking code ensures that for non-null - // pointers, but null pointers are ignored. This code ensures that even null pointers - // are made store good, for the promoted objects. - page->object_iterate([&](oop obj) { - ZIterator::basic_oop_iterate_safe(obj, ZBarrier::promote_barrier_on_young_oop_field); - }); - } } void install_small(ZForwarding* forwarding, size_t index) { @@ -78,10 +69,18 @@ private: return ZRelocate::compute_to_age(page->age()); } + void track_if_promoted(ZPage* page, ZForwarding* forwarding, ZArray& relocate_promoted) { + if (forwarding->is_promotion()) { + page->set_is_relocate_promoted(); + relocate_promoted.append(page); + } + } + public: - ZRelocationSetInstallTask(ZForwardingAllocator* allocator, const ZRelocationSetSelector* selector) + ZRelocationSetInstallTask(ZRelocationSet* relocation_set, const ZRelocationSetSelector* selector) : ZTask("ZRelocationSetInstallTask"), - _allocator(allocator), + _relocation_set(relocation_set), + _allocator(&relocation_set->_allocator), _forwardings(nullptr), _nforwardings((size_t)selector->selected_small()->length() + (size_t)selector->selected_medium()->length()), _small(selector->selected_small()), @@ -108,11 +107,14 @@ public: // Join the STS to block out VMThreads while running promote_barrier_on_young_oop_field SuspendibleThreadSetJoiner sts_joiner; + ZArray relocate_promoted; + // Allocate and install forwardings for small pages for (size_t page_index; _small_iter.next_index(&page_index);) { ZPage* page = _small->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_small(forwarding, (size_t)_medium->length() + page_index); + track_if_promoted(page, forwarding, relocate_promoted); SuspendibleThreadSet::yield(); } @@ -122,9 +124,12 @@ public: ZPage* page = _medium->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_medium(forwarding, page_index); + track_if_promoted(page, forwarding, relocate_promoted); SuspendibleThreadSet::yield(); } + + _relocation_set->register_relocate_promoted(relocate_promoted); } ZForwarding** forwardings() const { @@ -143,6 +148,7 @@ ZRelocationSet::ZRelocationSet(ZGeneration* generation) _nforwardings(0), _promotion_lock(), _flip_promoted_pages(), + _relocate_promoted_pages(), _in_place_relocate_promoted_pages() {} ZWorkers* ZRelocationSet::workers() const { @@ -157,9 +163,13 @@ ZArray* ZRelocationSet::flip_promoted_pages() { return &_flip_promoted_pages; } +ZArray* ZRelocationSet::relocate_promoted_pages() { + return &_relocate_promoted_pages; +} + void ZRelocationSet::install(const ZRelocationSetSelector* selector) { // Install relocation set - ZRelocationSetInstallTask task(&_allocator, selector); + ZRelocationSetInstallTask task(this, selector); workers()->run(&task); _forwardings = task.forwardings(); @@ -189,6 +199,7 @@ void ZRelocationSet::reset(ZPageAllocator* page_allocator) { destroy_and_clear(page_allocator, &_in_place_relocate_promoted_pages); destroy_and_clear(page_allocator, &_flip_promoted_pages); + _relocate_promoted_pages.clear(); } void ZRelocationSet::register_flip_promoted(const ZArray& pages) { @@ -199,6 +210,18 @@ void ZRelocationSet::register_flip_promoted(const ZArray& pages) { } } +void ZRelocationSet::register_relocate_promoted(const ZArray& pages) { + if (pages.is_empty()) { + return; + } + + ZLocker locker(&_promotion_lock); + for (ZPage* const page : pages) { + assert(!_relocate_promoted_pages.contains(page), "no duplicates allowed"); + _relocate_promoted_pages.append(page); + } +} + void ZRelocationSet::register_in_place_relocate_promoted(ZPage* page) { ZLocker locker(&_promotion_lock); assert(!_in_place_relocate_promoted_pages.contains(page), "no duplicates allowed"); diff --git a/src/hotspot/share/gc/z/zRelocationSet.hpp b/src/hotspot/share/gc/z/zRelocationSet.hpp index ee1a9447617..5f54df79805 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.hpp +++ b/src/hotspot/share/gc/z/zRelocationSet.hpp @@ -37,6 +37,7 @@ class ZWorkers; class ZRelocationSet { template friend class ZRelocationSetIteratorImpl; + friend class ZRelocationSetInstallTask; private: ZGeneration* _generation; @@ -45,6 +46,7 @@ private: size_t _nforwardings; ZLock _promotion_lock; ZArray _flip_promoted_pages; + ZArray _relocate_promoted_pages; ZArray _in_place_relocate_promoted_pages; ZWorkers* workers() const; @@ -58,8 +60,10 @@ public: void reset(ZPageAllocator* page_allocator); ZGeneration* generation() const; ZArray* flip_promoted_pages(); + ZArray* relocate_promoted_pages(); void register_flip_promoted(const ZArray& pages); + void register_relocate_promoted(const ZArray& pages); void register_in_place_relocate_promoted(ZPage* page); }; diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index ce76a95fda7..dccdcacef71 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -1100,16 +1100,16 @@ JVM_GetEnclosingMethodInfo(JNIEnv* env, jclass ofClass); * Virtual thread support. */ JNIEXPORT void JNICALL -JVM_VirtualThreadStart(JNIEnv* env, jobject vthread); +JVM_VirtualThreadEndFirstTransition(JNIEnv* env, jobject vthread); JNIEXPORT void JNICALL -JVM_VirtualThreadEnd(JNIEnv* env, jobject vthread); +JVM_VirtualThreadStartFinalTransition(JNIEnv* env, jobject vthread); JNIEXPORT void JNICALL -JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide); +JVM_VirtualThreadStartTransition(JNIEnv* env, jobject vthread, jboolean is_mount); JNIEXPORT void JNICALL -JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide); +JVM_VirtualThreadEndTransition(JNIEnv* env, jobject vthread, jboolean is_mount); JNIEXPORT void JNICALL JVM_VirtualThreadDisableSuspend(JNIEnv* env, jclass clazz, jboolean enter); diff --git a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp index d5ef3502fa2..27accac2c00 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp @@ -1427,10 +1427,10 @@ static void transform(InstanceKlass*& ik, ClassFileParser& parser, JavaThread* t } else { JfrClassTransformer::cache_class_file_data(new_ik, stream, thread); } + JfrClassTransformer::copy_traceid(ik, new_ik); if (is_instrumented && JdkJfrEvent::is_subklass(new_ik)) { bless_commit_method(new_ik); } - JfrClassTransformer::copy_traceid(ik, new_ik); JfrClassTransformer::rewrite_klass_pointer(ik, new_ik, parser, thread); } diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index 7abf5c89945..b09a89594ad 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -22,6 +22,7 @@ * */ +#include "classfile/classFileParser.hpp" #include "jfr/instrumentation/jfrEventClassTransformer.hpp" #include "jfr/jfr.hpp" #include "jfr/jni/jfrJavaSupport.hpp" @@ -31,6 +32,7 @@ #include "jfr/recorder/repository/jfrEmergencyDump.hpp" #include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" +#include "jfr/support/jfrClassDefineEvent.hpp" #include "jfr/support/jfrKlassExtension.hpp" #include "jfr/support/jfrResolution.hpp" #include "jfr/support/jfrThreadLocal.hpp" @@ -78,13 +80,15 @@ void Jfr::on_unloading_classes() { } void Jfr::on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS) { + JfrTraceId::assign(ik); if (IS_EVENT_OR_HOST_KLASS(ik)) { JfrEventClassTransformer::on_klass_creation(ik, parser, THREAD); - return; - } - if (JfrMethodTracer::in_use()) { + } else if (JfrMethodTracer::in_use()) { JfrMethodTracer::on_klass_creation(ik, parser, THREAD); } + if (!parser.is_internal()) { + JfrClassDefineEvent::on_creation(ik, parser, THREAD); + } } void Jfr::on_klass_redefinition(const InstanceKlass* ik, const InstanceKlass* scratch_klass) { @@ -168,3 +172,13 @@ bool Jfr::on_flight_recorder_option(const JavaVMOption** option, char* delimiter bool Jfr::on_start_flight_recording_option(const JavaVMOption** option, char* delimiter) { return JfrOptionSet::parse_start_flight_recording_option(option, delimiter); } + +#if INCLUDE_CDS +void Jfr::on_restoration(const Klass* k, JavaThread* jt) { + assert(k != nullptr, "invariant"); + JfrTraceId::restore(k); + if (k->is_instance_klass()) { + JfrClassDefineEvent::on_restoration(InstanceKlass::cast(k), jt); + } +} +#endif diff --git a/src/hotspot/share/jfr/jfr.hpp b/src/hotspot/share/jfr/jfr.hpp index 2e1fc738a61..db567cc9a29 100644 --- a/src/hotspot/share/jfr/jfr.hpp +++ b/src/hotspot/share/jfr/jfr.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_JFR_JFR_HPP #define SHARE_JFR_JFR_HPP +#include "jfr/utilities/jfrTypes.hpp" #include "memory/allStatic.hpp" #include "oops/oopsHierarchy.hpp" #include "utilities/exceptions.hpp" @@ -78,6 +79,7 @@ class Jfr : AllStatic { static void initialize_main_thread(JavaThread* jt); static bool has_sample_request(JavaThread* jt); static void check_and_process_sample_request(JavaThread* jt); + CDS_ONLY(static void on_restoration(const Klass* k, JavaThread* jt);) }; #endif // SHARE_JFR_JFR_HPP diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index eaafef37306..18a74454eb6 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -215,6 +215,7 @@ + diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 375ab4d04e9..b1c502e17f8 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -30,11 +30,12 @@ #include "classfile/vmClasses.hpp" #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp" #include "jfr/recorder/checkpoint/types/jfrTypeSet.hpp" -#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" +#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp" #include "jfr/recorder/jfrRecorder.hpp" #include "jfr/support/jfrKlassUnloading.hpp" +#include "jfr/support/jfrSymbolTable.inline.hpp" #include "jfr/support/methodtracer/jfrInstrumentedClass.hpp" #include "jfr/support/methodtracer/jfrMethodTracer.hpp" #include "jfr/utilities/jfrHashtable.hpp" @@ -1262,7 +1263,7 @@ static size_t teardown() { clear_klasses_and_methods(); clear_method_tracer_klasses(); JfrKlassUnloading::clear(); - _artifacts->increment_checkpoint_id(); + _artifacts->clear(); _initial_type_set = true; } else { _initial_type_set = false; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp index c60556927ad..765bba69105 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp @@ -23,18 +23,19 @@ */ #include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" +#include "jfr/support/jfrSymbolTable.inline.hpp" #include "jfr/utilities/jfrPredicate.hpp" #include "jfr/utilities/jfrRelation.hpp" #include "oops/instanceKlass.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" -JfrArtifactSet::JfrArtifactSet(bool class_unload, bool previous_epoch) : _symbol_table(nullptr), - _klass_set(nullptr), +JfrArtifactSet::JfrArtifactSet(bool class_unload, bool previous_epoch) : _klass_set(nullptr), _klass_loader_set(nullptr), _klass_loader_leakp_set(nullptr), _total_count(0), - _class_unload(class_unload) { + _class_unload(class_unload), + _previous_epoch(previous_epoch) { initialize(class_unload, previous_epoch); assert(!previous_epoch || _klass_loader_leakp_set != nullptr, "invariant"); assert(_klass_loader_set != nullptr, "invariant"); @@ -47,12 +48,7 @@ static unsigned initial_klass_loader_leakp_set_size = 64; void JfrArtifactSet::initialize(bool class_unload, bool previous_epoch) { _class_unload = class_unload; - if (_symbol_table == nullptr) { - _symbol_table = JfrSymbolTable::create(); - assert(_symbol_table != nullptr, "invariant"); - } - assert(_symbol_table != nullptr, "invariant"); - _symbol_table->set_class_unload(class_unload); + _previous_epoch = previous_epoch; _total_count = 0; // Resource allocations. Keep in this allocation order. if (previous_epoch) { @@ -63,45 +59,33 @@ void JfrArtifactSet::initialize(bool class_unload, bool previous_epoch) { } void JfrArtifactSet::clear() { - if (_symbol_table != nullptr) { - _symbol_table->clear(); - } + assert(_previous_epoch, "invariant"); + JfrSymbolTable::clear_previous_epoch(); + assert(_klass_loader_leakp_set != nullptr, "invariant"); + initial_klass_loader_leakp_set_size = MAX2(initial_klass_loader_leakp_set_size, _klass_loader_leakp_set->table_size()); } JfrArtifactSet::~JfrArtifactSet() { - delete _symbol_table; // _klass_loader_set, _klass_loader_leakp_set and // _klass_list will be cleared by a ResourceMark } traceid JfrArtifactSet::bootstrap_name(bool leakp) { - return _symbol_table->bootstrap_name(leakp); -} - -traceid JfrArtifactSet::mark_hidden_klass_name(const Klass* klass, bool leakp) { - assert(klass->is_instance_klass(), "invariant"); - return _symbol_table->mark_hidden_klass_name((const InstanceKlass*)klass, leakp); -} - -traceid JfrArtifactSet::mark(uintptr_t hash, const Symbol* sym, bool leakp) { - return _symbol_table->mark(hash, sym, leakp); + return JfrSymbolTable::bootstrap_name(leakp); } traceid JfrArtifactSet::mark(const Klass* klass, bool leakp) { - return _symbol_table->mark(klass, leakp); + return JfrSymbolTable::mark(klass, leakp, _class_unload, _previous_epoch); } traceid JfrArtifactSet::mark(const Symbol* symbol, bool leakp) { - return _symbol_table->mark(symbol, leakp); -} - -traceid JfrArtifactSet::mark(uintptr_t hash, const char* const str, bool leakp) { - return _symbol_table->mark(hash, str, leakp); + return JfrSymbolTable::mark(symbol, leakp, _class_unload, _previous_epoch); } bool JfrArtifactSet::has_klass_entries() const { return _klass_set->is_nonempty(); } + static inline bool not_in_set(JfrArtifactSet::JfrKlassSet* set, const Klass* k) { assert(set != nullptr, "invariant"); assert(k != nullptr, "invariant"); @@ -129,10 +113,3 @@ size_t JfrArtifactSet::total_count() const { initial_klass_loader_set_size = MAX2(initial_klass_loader_set_size, _klass_loader_set->table_size()); return _total_count; } - -void JfrArtifactSet::increment_checkpoint_id() { - assert(_symbol_table != nullptr, "invariant"); - _symbol_table->increment_checkpoint_id(); - assert(_klass_loader_leakp_set != nullptr, "invariant"); - initial_klass_loader_leakp_set_size = MAX2(initial_klass_loader_leakp_set_size, _klass_loader_leakp_set->table_size()); -} diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp index 74200aef1f1..cc5ebb2be39 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp @@ -207,12 +207,12 @@ class JfrArtifactSet : public JfrCHeapObj { typedef JfrSet JfrKlassSet; private: - JfrSymbolTable* _symbol_table; JfrKlassSet* _klass_set; JfrKlassSet* _klass_loader_set; JfrKlassSet* _klass_loader_leakp_set; size_t _total_count; bool _class_unload; + bool _previous_epoch; public: JfrArtifactSet(bool class_unload, bool previous_epoch); @@ -222,32 +222,20 @@ class JfrArtifactSet : public JfrCHeapObj { void initialize(bool class_unload, bool previous_epoch); void clear(); - traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); traceid mark(const Klass* klass, bool leakp); traceid mark(const Symbol* symbol, bool leakp); - traceid mark(uintptr_t hash, const char* const str, bool leakp); - traceid mark_hidden_klass_name(const Klass* klass, bool leakp); traceid bootstrap_name(bool leakp); - const JfrSymbolTable::SymbolEntry* map_symbol(const Symbol* symbol) const; - const JfrSymbolTable::SymbolEntry* map_symbol(uintptr_t hash) const; - const JfrSymbolTable::StringEntry* map_string(uintptr_t hash) const; - bool has_klass_entries() const; size_t total_count() const; void register_klass(const Klass* k); bool should_do_cld_klass(const Klass* k, bool leakp); - void increment_checkpoint_id(); template - void iterate_symbols(T& functor) { - _symbol_table->iterate_symbols(functor); - } + void iterate_symbols(T& functor); template - void iterate_strings(T& functor) { - _symbol_table->iterate_strings(functor); - } + void iterate_strings(T& functor); template void tally(Writer& writer) { diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp new file mode 100644 index 00000000000..a1a25c4e907 --- /dev/null +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_INLINE_HPP +#define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_INLINE_HPP + +#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" + +#include "jfr/support/jfrSymbolTable.inline.hpp" + +template +inline void JfrArtifactSet::iterate_symbols(T& functor) { + JfrSymbolTable::iterate_symbols(functor, _previous_epoch); +} + +template +inline void JfrArtifactSet::iterate_strings(T& functor) { + JfrSymbolTable::iterate_strings(functor, _previous_epoch); +} + +#endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_INLINE_HPP diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp index 2fcb1a64baf..405fa25baff 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp @@ -109,6 +109,7 @@ static void check_klass(const Klass* klass) { void JfrTraceId::assign(const Klass* klass) { assert(klass != nullptr, "invariant"); + assert(klass->trace_id() == 0, "invariant"); klass->set_trace_id(next_class_id()); check_klass(klass); const Klass* const super = klass->super(); diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp index f5214ff7942..6a6da0f9b04 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp @@ -43,6 +43,7 @@ #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" #include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp" +#include "jfr/support/jfrSymbolTable.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/writers/jfrJavaEventWriter.hpp" @@ -315,6 +316,9 @@ bool JfrRecorder::create_components() { if (!create_thread_group_manager()) { return false; } + if (!create_symbol_table()) { + return false; + } return true; } @@ -413,6 +417,10 @@ bool JfrRecorder::create_thread_group_manager() { return JfrThreadGroupManager::create(); } +bool JfrRecorder::create_symbol_table() { + return JfrSymbolTable::create(); +} + void JfrRecorder::destroy_components() { JfrJvmtiAgent::destroy(); if (_post_box != nullptr) { @@ -453,6 +461,7 @@ void JfrRecorder::destroy_components() { } JfrEventThrottler::destroy(); JfrThreadGroupManager::destroy(); + JfrSymbolTable::destroy(); } bool JfrRecorder::create_recorder_thread() { diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp index 34cc8fda949..8cc4521669d 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp @@ -57,6 +57,7 @@ class JfrRecorder : public JfrCHeapObj { static bool create_thread_sampler(); static bool create_cpu_time_thread_sampling(); static bool create_event_throttler(); + static bool create_symbol_table(); static bool create_components(); static void destroy_components(); static void on_recorder_thread_exit(); diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 3f0b132f1a4..08250a1ae59 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -39,6 +39,7 @@ #include "jfr/recorder/storage/jfrStorageControl.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp" #include "jfr/support/jfrDeprecationManager.hpp" +#include "jfr/support/jfrSymbolTable.inline.hpp" #include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" @@ -450,6 +451,7 @@ void JfrRecorderService::clear() { void JfrRecorderService::pre_safepoint_clear() { _storage.clear(); JfrStackTraceRepository::clear(); + JfrSymbolTable::allocate_next_epoch(); } void JfrRecorderService::invoke_safepoint_clear() { @@ -558,6 +560,7 @@ void JfrRecorderService::pre_safepoint_write() { } write_storage(_storage, _chunkwriter); write_stacktrace(_stack_trace_repository, _chunkwriter, true); + JfrSymbolTable::allocate_next_epoch(); } void JfrRecorderService::invoke_safepoint_write() { diff --git a/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp b/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp new file mode 100644 index 00000000000..5bdc0015a2b --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "cds/aotClassLocation.hpp" +#include "classfile/classFileParser.hpp" +#include "classfile/classFileStream.hpp" +#include "classfile/classLoaderData.inline.hpp" +#include "jfr/instrumentation/jfrClassTransformer.hpp" +#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" +#include "jfr/support/jfrClassDefineEvent.hpp" +#include "jfr/support/jfrSymbolTable.hpp" +#include "jfrfiles/jfrEventClasses.hpp" +#include "oops/instanceKlass.hpp" +#include "runtime/javaThread.hpp" + + /* + * Two cases for JDK modules as outlined by JEP 200: The Modular JDK. + * + * The modular structure of the JDK implements the following principles: + * 1. Standard modules, whose specifications are governed by the JCP, have names starting with the string "java.". + * 2. All other modules are merely part of the JDK, and have names starting with the string "jdk.". + * */ +static inline bool is_jdk_module(const char* module_name) { + assert(module_name != nullptr, "invariant"); + return strstr(module_name, "java.") == module_name || strstr(module_name, "jdk.") == module_name; +} + +static inline bool is_unnamed_module(const ModuleEntry* module) { + return module == nullptr || !module->is_named(); +} + +static inline bool is_jdk_module(const ModuleEntry* module, JavaThread* jt) { + assert(jt != nullptr, "invariant"); + if (is_unnamed_module(module)) { + return false; + } + const Symbol* const module_symbol = module->name(); + assert(module_symbol != nullptr, "invariant"); + return is_jdk_module(module_symbol->as_C_string()); +} + +static inline bool is_jdk_module(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(jt != nullptr, "invariant"); + return is_jdk_module(ik->module(), jt); +} + +static traceid module_path(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + const ModuleEntry* const module_entry = ik->module(); + if (is_unnamed_module(module_entry)) { + return 0; + } + const char* const module_name = module_entry->name()->as_C_string(); + assert(module_name != nullptr, "invariant"); + if (is_jdk_module(module_name)) { + const size_t module_name_len = strlen(module_name); + char* const path = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, module_name_len + 6); // "jrt:/" + jio_snprintf(path, module_name_len + 6, "%s%s", "jrt:/", module_name); + return JfrSymbolTable::add(path); + } + return 0; +} + +static traceid caller_path(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(jt != nullptr, "invariant"); + assert(ik->class_loader_data()->is_the_null_class_loader_data(), "invariant"); + const Klass* const caller = jt->security_get_caller_class(1); + // caller can be null, for example, during a JVMTI VM_Init hook + if (caller != nullptr) { + const char* caller_name = caller->external_name(); + assert(caller_name != nullptr, "invariant"); + const size_t caller_name_len = strlen(caller_name); + char* const path = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, caller_name_len + 13); // "instance of " + jio_snprintf(path, caller_name_len + 13, "%s%s", "instance of ", caller_name); + return JfrSymbolTable::add(path); + } + return 0; +} + +static traceid class_loader_path(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(jt != nullptr, "invariant"); + assert(!ik->class_loader_data()->is_the_null_class_loader_data(), "invariant"); + oop class_loader = ik->class_loader_data()->class_loader(); + const char* class_loader_name = class_loader->klass()->external_name(); + return class_loader_name != nullptr ? JfrSymbolTable::add(class_loader_name) : 0; +} + +static inline bool is_not_retransforming(const InstanceKlass* ik, JavaThread* jt) { + return JfrClassTransformer::find_existing_klass(ik, jt) == nullptr; +} + +static traceid get_source(const InstanceKlass* ik, JavaThread* jt) { + traceid source_id = 0; + if (is_jdk_module(ik, jt)) { + source_id = module_path(ik, jt); + } else if (ik->class_loader_data()->is_the_null_class_loader_data()) { + source_id = caller_path(ik, jt); + } else { + source_id = class_loader_path(ik, jt); + } + return source_id; +} + +static traceid get_source(const AOTClassLocation* cl, JavaThread* jt) { + assert(cl != nullptr, "invariant"); + assert(!cl->is_modules_image(), "invariant"); + const char* const path = cl->path(); + assert(path != nullptr, "invariant"); + size_t len = strlen(path); + const char* file_type = cl->file_type_string(); + assert(file_type != nullptr, "invariant"); + len += strlen(file_type) + 3; // ":/" + null + char* const url = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, len); + jio_snprintf(url, len, "%s%s%s", file_type, ":/", path); + return JfrSymbolTable::add(url); +} + +static inline void send_event(const InstanceKlass* ik, traceid source_id) { + EventClassDefine event; + event.set_definedClass(ik); + event.set_definingClassLoader(ik->class_loader_data()); + event.set_source(source_id); + event.commit(); +} + +void JfrClassDefineEvent::on_creation(const InstanceKlass* ik, const ClassFileParser& parser, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(ik->trace_id() != 0, "invariant"); + assert(!parser.is_internal(), "invariant"); + assert(jt != nullptr, "invariant"); + + if (EventClassDefine::is_enabled() && is_not_retransforming(ik, jt)) { + ResourceMark rm(jt); + traceid source_id = 0; + const ClassFileStream& stream = parser.stream(); + if (stream.source() != nullptr) { + if (stream.from_boot_loader_modules_image()) { + assert(is_jdk_module(ik, jt), "invariant"); + source_id = module_path(ik, jt); + } else { + source_id = JfrSymbolTable::add(stream.source()); + } + } else { + source_id = get_source(ik, jt); + } + send_event(ik, source_id); + } +} + +#if INCLUDE_CDS +void JfrClassDefineEvent::on_restoration(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(ik->trace_id() != 0, "invariant"); + assert(jt != nullptr, "invariant"); + + if (EventClassDefine::is_enabled()) { + ResourceMark rm(jt); + assert(is_not_retransforming(ik, jt), "invariant"); + const int index = ik->shared_classpath_index(); + assert(index >= 0, "invariant"); + const AOTClassLocation* const cl = AOTClassLocationConfig::runtime()->class_location_at(index); + assert(cl != nullptr, "invariant"); + send_event(ik, cl->is_modules_image() ? module_path(ik, jt) : get_source(cl, jt)); + } +} +#endif diff --git a/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp b/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp new file mode 100644 index 00000000000..3e242d8e4f2 --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP +#define SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP + +#include "memory/allStatic.hpp" +#include "utilities/macros.hpp" + +class ClassFileParser; +class InstanceKlass; +class JavaThread; + +class JfrClassDefineEvent : AllStatic { + public: + static void on_creation(const InstanceKlass* ik, const ClassFileParser& parser, JavaThread* jt); + CDS_ONLY(static void on_restoration(const InstanceKlass* ik, JavaThread* jt);) +}; + +#endif // SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP diff --git a/src/hotspot/share/jfr/support/jfrKlassExtension.hpp b/src/hotspot/share/jfr/support/jfrKlassExtension.hpp index dc5f7aa7e90..54f5031dd3b 100644 --- a/src/hotspot/share/jfr/support/jfrKlassExtension.hpp +++ b/src/hotspot/share/jfr/support/jfrKlassExtension.hpp @@ -40,6 +40,5 @@ #define EVENT_STICKY_BIT 8192 #define IS_EVENT_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)) != 0) #define IS_EVENT_OR_HOST_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS | EVENT_HOST_KLASS)) != 0) -#define ON_KLASS_CREATION(k, p, t) Jfr::on_klass_creation(k, p, t) #endif // SHARE_JFR_SUPPORT_JFRKLASSEXTENSION_HPP diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.cpp b/src/hotspot/share/jfr/support/jfrSymbolTable.cpp index 3fc639ffb5c..c791a05f818 100644 --- a/src/hotspot/share/jfr/support/jfrSymbolTable.cpp +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.cpp @@ -24,131 +24,32 @@ #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" -#include "jfr/support/jfrSymbolTable.hpp" +#include "jfr/recorder/jfrRecorder.hpp" +#include "jfr/support/jfrSymbolTable.inline.hpp" #include "oops/klass.hpp" #include "oops/symbol.hpp" +#include "runtime/atomicAccess.hpp" #include "runtime/mutexLocker.hpp" -// incremented on each rotation -static u8 checkpoint_id = 1; +JfrSymbolTable::Impl* JfrSymbolTable::_epoch_0 = nullptr; +JfrSymbolTable::Impl* JfrSymbolTable::_epoch_1 = nullptr; +JfrSymbolTable::StringEntry* JfrSymbolTable::_bootstrap = nullptr; -// creates a unique id by combining a checkpoint relative symbol id (2^24) -// with the current checkpoint id (2^40) -#define CREATE_SYMBOL_ID(sym_id) (((u8)((checkpoint_id << 24) | sym_id))) - -static traceid create_symbol_id(traceid artifact_id) { - return artifact_id != 0 ? CREATE_SYMBOL_ID(artifact_id) : 0; -} - -static uintptr_t string_hash(const char* str) { - return java_lang_String::hash_code(reinterpret_cast(str), static_cast(strlen(str))); -} - -static JfrSymbolTable::StringEntry* bootstrap = nullptr; - -static JfrSymbolTable* _instance = nullptr; - -static JfrSymbolTable& instance() { - assert(_instance != nullptr, "invariant"); - return *_instance; -} - -JfrSymbolTable* JfrSymbolTable::create() { - assert(_instance == nullptr, "invariant"); - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - _instance = new JfrSymbolTable(); - return _instance; -} - -void JfrSymbolTable::destroy() { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - if (_instance != nullptr) { - delete _instance; - _instance = nullptr; - } - assert(_instance == nullptr, "invariant"); -} - -JfrSymbolTable::JfrSymbolTable() : - _symbols(new Symbols(this)), - _strings(new Strings(this)), - _symbol_list(nullptr), - _string_list(nullptr), - _symbol_query(nullptr), - _string_query(nullptr), - _id_counter(1), - _class_unload(false) { - assert(_symbols != nullptr, "invariant"); - assert(_strings != nullptr, "invariant"); - bootstrap = new StringEntry(0, (const char*)&BOOTSTRAP_LOADER_NAME); - assert(bootstrap != nullptr, "invariant"); - bootstrap->set_id(create_symbol_id(1)); - _string_list = bootstrap; -} - -JfrSymbolTable::~JfrSymbolTable() { - clear(); - delete _symbols; - delete _strings; - delete bootstrap; -} - -void JfrSymbolTable::clear() { - assert(_symbols != nullptr, "invariant"); - if (_symbols->has_entries()) { - _symbols->clear_entries(); - } - assert(!_symbols->has_entries(), "invariant"); - - assert(_strings != nullptr, "invariant"); - if (_strings->has_entries()) { - _strings->clear_entries(); - } - assert(!_strings->has_entries(), "invariant"); - - _symbol_list = nullptr; - _id_counter = 1; - - _symbol_query = nullptr; - _string_query = nullptr; - - assert(bootstrap != nullptr, "invariant"); - bootstrap->reset(); - _string_list = bootstrap; -} - -void JfrSymbolTable::set_class_unload(bool class_unload) { - _class_unload = class_unload; -} - -void JfrSymbolTable::increment_checkpoint_id() { - assert_lock_strong(ClassLoaderDataGraph_lock); - clear(); - ++checkpoint_id; -} +JfrSymbolCallback::JfrSymbolCallback() : _id_counter(2) {} // 1 is reserved for "bootstrap" entry template -inline void JfrSymbolTable::assign_id(T* entry) { +inline void JfrSymbolCallback::assign_id(const T* entry) { assert(entry != nullptr, "invariant"); assert(entry->id() == 0, "invariant"); - entry->set_id(create_symbol_id(++_id_counter)); + entry->set_id(AtomicAccess::fetch_then_add(&_id_counter, (traceid)1)); } -void JfrSymbolTable::on_link(const SymbolEntry* entry) { +void JfrSymbolCallback::on_link(const JfrSymbolTable::SymbolEntry* entry) { assign_id(entry); const_cast(entry->literal())->increment_refcount(); - entry->set_list_next(_symbol_list); - _symbol_list = entry; } -bool JfrSymbolTable::on_equals(uintptr_t hash, const SymbolEntry* entry) { - assert(entry != nullptr, "invariant"); - assert(entry->hash() == hash, "invariant"); - assert(_symbol_query != nullptr, "invariant"); - return _symbol_query == entry->literal(); -} - -void JfrSymbolTable::on_unlink(const SymbolEntry* entry) { +void JfrSymbolCallback::on_unlink(const JfrSymbolTable::SymbolEntry* entry) { assert(entry != nullptr, "invariant"); const_cast(entry->literal())->decrement_refcount(); } @@ -162,75 +63,241 @@ static const char* resource_to_c_heap_string(const char* resource_str) { return c_string; } -void JfrSymbolTable::on_link(const StringEntry* entry) { +void JfrSymbolCallback::on_link(const JfrSymbolTable::StringEntry* entry) { assign_id(entry); - const_cast(entry)->set_literal(resource_to_c_heap_string(entry->literal())); - entry->set_list_next(_string_list); - _string_list = entry; + const_cast(entry)->set_literal(resource_to_c_heap_string(entry->literal())); } -static bool string_compare(const char* query, const char* candidate) { - assert(query != nullptr, "invariant"); - assert(candidate != nullptr, "invariant"); - const size_t length = strlen(query); - return strncmp(query, candidate, length) == 0; -} - -bool JfrSymbolTable::on_equals(uintptr_t hash, const StringEntry* entry) { +void JfrSymbolCallback::on_unlink(const JfrSymbolTable::StringEntry* entry) { assert(entry != nullptr, "invariant"); - assert(entry->hash() == hash, "invariant"); - assert(_string_query != nullptr, "invariant"); - return string_compare(_string_query, entry->literal()); + JfrCHeapObj::free(const_cast(entry->literal()), strlen(entry->literal()) + 1); } -void JfrSymbolTable::on_unlink(const StringEntry* entry) { - assert(entry != nullptr, "invariant"); - JfrCHeapObj::free(const_cast(entry->literal()), strlen(entry->literal() + 1)); +static JfrSymbolCallback* _callback = nullptr; + +template +JfrSymbolTableEntry::JfrSymbolTableEntry(unsigned hash, const T& data) : + JfrConcurrentHashtableEntry(hash, data), _serialized(false), _unloading(false), _leakp(false) {} + +template +bool JfrSymbolTableEntry::on_equals(const char* str) { + assert(str != nullptr, "invariant"); + return strcmp((const char*)this->literal(), str) == 0; +} + +static const constexpr unsigned max_capacity = 1 << 30; + +static inline unsigned calculate_capacity(unsigned size, unsigned capacity) { + assert(is_power_of_2(capacity), "invariant"); + assert(capacity <= max_capacity, "invariant"); + double load_factor = (double)size / (double)capacity; + if (load_factor < 0.75) { + return capacity; + } + do { + capacity <<= 1; + assert(is_power_of_2(capacity), "invariant"); + guarantee(capacity <= max_capacity, "overflow"); + load_factor = (double)size / (double)capacity; + } while (load_factor >= 0.75); + return capacity; +} + +bool JfrSymbolTable::create() { + assert(_callback == nullptr, "invariant"); + // Allocate callback instance before tables. + _callback = new JfrSymbolCallback(); + if (_callback == nullptr) { + return false; + } + assert(_bootstrap == nullptr, "invariant"); + _bootstrap = new StringEntry(0, (const char*)&BOOTSTRAP_LOADER_NAME); + if (_bootstrap == nullptr) { + return false; + } + _bootstrap->set_id(1); + assert(this_epoch_table() == nullptr, "invariant"); + Impl* table = new JfrSymbolTable::Impl(); + if (table == nullptr) { + return false; + } + set_this_epoch(table); + assert(previous_epoch_table() == nullptr, "invariant"); + return true; +} + +void JfrSymbolTable::destroy() { + if (_callback != nullptr) { + delete _callback; + _callback = nullptr; + } + if (_bootstrap != nullptr) { + delete _bootstrap; + _bootstrap = nullptr; + } + if (_epoch_0 != nullptr) { + delete _epoch_0; + _epoch_0 = nullptr; + } + if (_epoch_1 != nullptr) { + delete _epoch_1; + _epoch_1 = nullptr; + } +} + +void JfrSymbolTable::allocate_next_epoch() { + assert(nullptr == previous_epoch_table(), "invariant"); + const Impl* const current = this_epoch_table(); + assert(current != nullptr, "invariant"); + const unsigned next_symbols_capacity = calculate_capacity(current->symbols_size(), current->symbols_capacity()); + const unsigned next_strings_capacity = calculate_capacity(current->strings_size(), current->strings_capacity()); + assert(_callback != nullptr, "invariant"); + // previous epoch to become the next epoch. + set_previous_epoch(new JfrSymbolTable::Impl(next_symbols_capacity, next_strings_capacity)); + assert(this_epoch_table() != nullptr, "invariant"); + assert(previous_epoch_table() != nullptr, "invariant"); +} + +void JfrSymbolTable::clear_previous_epoch() { + Impl* const table = previous_epoch_table(); + assert(table != nullptr, "invariant"); + set_previous_epoch(nullptr); + delete table; + assert(_bootstrap != nullptr, "invariant"); + _bootstrap->reset(); + assert(!_bootstrap->is_serialized(), "invariant"); +} + +void JfrSymbolTable::set_this_epoch(JfrSymbolTable::Impl* table) { + assert(table != nullptr, "invariant"); + const u1 epoch = JfrTraceIdEpoch::current(); + if (epoch == 0) { + _epoch_0 = table; + } else { + _epoch_1 = table; + } +} + +void JfrSymbolTable::set_previous_epoch(JfrSymbolTable::Impl* table) { + const u1 epoch = JfrTraceIdEpoch::previous(); + if (epoch == 0) { + _epoch_0 = table; + } else { + _epoch_1 = table; + } +} + +inline bool JfrSymbolTable::Impl::has_symbol_entries() const { + return _symbols->is_nonempty(); +} + +inline bool JfrSymbolTable::Impl::has_string_entries() const { + return _strings->is_nonempty(); +} + +inline bool JfrSymbolTable::Impl::has_entries() const { + return has_symbol_entries() || has_string_entries(); +} + +inline unsigned JfrSymbolTable::Impl::symbols_capacity() const { + return _symbols->capacity(); +} + +inline unsigned JfrSymbolTable::Impl::symbols_size() const { + return _symbols->size(); +} + +inline unsigned JfrSymbolTable::Impl::strings_capacity() const { + return _strings->capacity(); +} + +inline unsigned JfrSymbolTable::Impl::strings_size() const { + return _strings->size(); +} + +bool JfrSymbolTable::has_entries(bool previous_epoch /* false */) { + const Impl* table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->has_entries(); +} + +bool JfrSymbolTable::has_symbol_entries(bool previous_epoch /* false */) { + const Impl* table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->has_symbol_entries(); +} + +bool JfrSymbolTable::has_string_entries(bool previous_epoch /* false */) { + const Impl* table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->has_string_entries(); } traceid JfrSymbolTable::bootstrap_name(bool leakp) { - assert(bootstrap != nullptr, "invariant"); + assert(_bootstrap != nullptr, "invariant"); if (leakp) { - bootstrap->set_leakp(); + _bootstrap->set_leakp(); } - return bootstrap->id(); + return _bootstrap->id(); } -traceid JfrSymbolTable::mark(const Symbol* sym, bool leakp /* false */) { +JfrSymbolTable::Impl::Impl(unsigned symbols_capacity /* 0*/, unsigned strings_capacity /* 0 */) : + _symbols(new Symbols(_callback, symbols_capacity)), _strings(new Strings(_callback, strings_capacity)) {} + +JfrSymbolTable::Impl::~Impl() { + delete _symbols; + delete _strings; +} + +traceid JfrSymbolTable::Impl::mark(const Symbol* sym, bool leakp /* false */, bool class_unload /* false */) { assert(sym != nullptr, "invariant"); - return mark(sym->identity_hash(), sym, leakp); + return mark(sym->identity_hash(), sym, leakp, class_unload); } -traceid JfrSymbolTable::mark(uintptr_t hash, const Symbol* sym, bool leakp) { +traceid JfrSymbolTable::Impl::mark(unsigned hash, const Symbol* sym, bool leakp, bool class_unload /* false */) { assert(sym != nullptr, "invariant"); assert(_symbols != nullptr, "invariant"); - _symbol_query = sym; - const SymbolEntry& entry = _symbols->lookup_put(hash, sym); - if (_class_unload) { - entry.set_unloading(); - } + const SymbolEntry* entry = _symbols->lookup_put(hash, sym); + assert(entry != nullptr, "invariant"); if (leakp) { - entry.set_leakp(); + entry->set_leakp(); + } else if (class_unload) { + entry->set_unloading(); } - return entry.id(); + return entry->id(); } -traceid JfrSymbolTable::mark(const char* str, bool leakp /* false*/) { - return mark(string_hash(str), str, leakp); +traceid JfrSymbolTable::mark(const Symbol* sym, bool leakp /* false */, bool class_unload /* false */, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->mark(sym->identity_hash(), sym, leakp, class_unload); } -traceid JfrSymbolTable::mark(uintptr_t hash, const char* str, bool leakp) { +static inline unsigned string_hash(const char* str) { + return java_lang_String::hash_code(reinterpret_cast(str), static_cast(strlen(str))); +} + +traceid JfrSymbolTable::Impl::mark(const char* str, bool leakp /* false*/, bool class_unload /* false */) { + return mark(string_hash(str), str, leakp, class_unload); +} + +traceid JfrSymbolTable::Impl::mark(unsigned hash, const char* str, bool leakp, bool class_unload /* false */) { assert(str != nullptr, "invariant"); assert(_strings != nullptr, "invariant"); - _string_query = str; - const StringEntry& entry = _strings->lookup_put(hash, str); - if (_class_unload) { - entry.set_unloading(); - } + const StringEntry* entry = _strings->lookup_put(hash, str); + assert(entry != nullptr, "invariant"); if (leakp) { - entry.set_leakp(); + entry->set_leakp(); + } else if (class_unload) { + entry->set_unloading(); } - return entry.id(); + return entry->id(); +} + +traceid JfrSymbolTable::mark(unsigned hash, const char* str, bool leakp, bool class_unload /* false */, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->mark(hash, str, leakp, class_unload); } /* @@ -241,40 +308,47 @@ traceid JfrSymbolTable::mark(uintptr_t hash, const char* str, bool leakp) { * * Caller needs ResourceMark. */ -traceid JfrSymbolTable::mark_hidden_klass_name(const Klass* k, bool leakp) { +inline traceid JfrSymbolTable::Impl::mark_hidden_klass_name(const Klass* k, bool leakp, bool class_unload /* false */) { assert(k != nullptr, "invariant"); assert(k->is_hidden(), "invariant"); - const uintptr_t hash = k->name()->identity_hash(); - return mark(hash, k->external_name(), leakp); + return mark(k->name()->identity_hash(), k->external_name(), leakp, class_unload); } -traceid JfrSymbolTable::mark(const Klass* k, bool leakp) { +traceid JfrSymbolTable::Impl::mark(const Klass* k, bool leakp, bool class_unload /* false */) { assert(k != nullptr, "invariant"); traceid symbol_id = 0; if (k->is_hidden()) { - symbol_id = mark_hidden_klass_name(k, leakp); + symbol_id = mark_hidden_klass_name(k, leakp, class_unload); } else { Symbol* const sym = k->name(); if (sym != nullptr) { - symbol_id = mark(sym, leakp); + symbol_id = mark(sym, leakp, class_unload); } } assert(symbol_id > 0, "a symbol handler must mark the symbol for writing"); return symbol_id; } -template -traceid JfrSymbolTable::add_impl(const T* sym) { - assert(sym != nullptr, "invariant"); - assert(_instance != nullptr, "invariant"); - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - return instance().mark(sym); +traceid JfrSymbolTable::mark(const Klass* k, bool leakp, bool class_unload /* false */, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->mark(k, leakp, class_unload); } -traceid JfrSymbolTable::add(const Symbol* sym) { - return add_impl(sym); +inline traceid JfrSymbolTable::Impl::add(const Symbol* sym) { + assert(sym != nullptr, "invariant"); + return _symbols->lookup_put(sym->identity_hash(), sym)->id(); +} + +traceid JfrSymbolTable::Impl::add(const char* str) { + assert(str != nullptr, "invariant"); + return _strings->lookup_put(string_hash(str), str)->id(); +} + +inline traceid JfrSymbolTable::add(const Symbol* sym) { + return this_epoch_table()->add(sym); } traceid JfrSymbolTable::add(const char* str) { - return add_impl(str); + return this_epoch_table()->add(str); } diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.hpp b/src/hotspot/share/jfr/support/jfrSymbolTable.hpp index 8cefa287c8a..d2ee6cd4bc1 100644 --- a/src/hotspot/share/jfr/support/jfrSymbolTable.hpp +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,32 +25,58 @@ #ifndef SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_HPP #define SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_HPP -#include "jfr/utilities/jfrHashtable.hpp" +#include "jfr/utilities/jfrAllocation.hpp" +#include "jfr/utilities/jfrConcurrentHashtable.hpp" #include "jfr/utilities/jfrTypes.hpp" template -class ListEntry : public JfrHashtableEntry { +class JfrSymbolTableEntry : public JfrConcurrentHashtableEntry { public: - ListEntry(uintptr_t hash, const T& data) : JfrHashtableEntry(hash, data), - _list_next(nullptr), _serialized(false), _unloading(false), _leakp(false) {} - const ListEntry* list_next() const { return _list_next; } - void reset() const { - _list_next = nullptr; _serialized = false; _unloading = false; _leakp = false; - } - void set_list_next(const ListEntry* next) const { _list_next = next; } + JfrSymbolTableEntry(unsigned hash, const T& data); bool is_serialized() const { return _serialized; } void set_serialized() const { _serialized = true; } bool is_unloading() const { return _unloading; } void set_unloading() const { _unloading = true; } bool is_leakp() const { return _leakp; } void set_leakp() const { _leakp = true; } + void reset() const { + _serialized = false; + _unloading = false; + _leakp = false; + } + + bool on_equals(const Symbol* sym) { + assert(sym != nullptr, "invariant"); + return sym == (const Symbol*)this->literal(); + } + + bool on_equals(const char* str); + private: - mutable const ListEntry* _list_next; mutable bool _serialized; mutable bool _unloading; mutable bool _leakp; }; +class JfrSymbolCallback : public JfrCHeapObj { + friend class JfrSymbolTable; + public: + typedef JfrConcurrentHashTableHost Symbols; + typedef JfrConcurrentHashTableHost Strings; + + void on_link(const Symbols::Entry* entry); + void on_unlink(const Symbols::Entry* entry); + void on_link(const Strings::Entry* entry); + void on_unlink(const Strings::Entry* entry); + + private: + traceid _id_counter; + + JfrSymbolCallback(); + template + void assign_id(const T* entry); +}; + /* * This table maps an oop/Symbol* or a char* to the Jfr type 'Symbol'. * @@ -58,88 +84,93 @@ class ListEntry : public JfrHashtableEntry { * which is represented in the binary format as a sequence of checkpoint events. * The returned id can be used as a foreign key, but please note that the id is * epoch-relative, and is therefore only valid in the current epoch / chunk. - * The table is cleared as part of rotation. - * - * Caller must ensure mutual exclusion by means of the ClassLoaderDataGraph_lock or by safepointing. */ -class JfrSymbolTable : public JfrCHeapObj { - template class, typename, size_t> - friend class HashTableHost; - typedef HashTableHost Symbols; - typedef HashTableHost Strings; +class JfrSymbolTable : public AllStatic { friend class JfrArtifactSet; + template class, typename, unsigned> + friend class JfrConcurrentHashTableHost; + friend class JfrRecorder; + friend class JfrRecorderService; + friend class JfrSymbolCallback; + + typedef JfrConcurrentHashTableHost Symbols; + typedef JfrConcurrentHashTableHost Strings; public: - typedef Symbols::HashEntry SymbolEntry; - typedef Strings::HashEntry StringEntry; + typedef Symbols::Entry SymbolEntry; + typedef Strings::Entry StringEntry; static traceid add(const Symbol* sym); static traceid add(const char* str); private: - Symbols* _symbols; - Strings* _strings; - const SymbolEntry* _symbol_list; - const StringEntry* _string_list; - const Symbol* _symbol_query; - const char* _string_query; - traceid _id_counter; - bool _class_unload; + class Impl : public JfrCHeapObj { + friend class JfrSymbolTable; + private: + Symbols* _symbols; + Strings* _strings; - JfrSymbolTable(); - ~JfrSymbolTable(); - static JfrSymbolTable* create(); + Impl(unsigned symbol_capacity = 0, unsigned string_capacity = 0); + ~Impl(); + + void clear(); + + traceid add(const Symbol* sym); + traceid add(const char* str); + + traceid mark(unsigned hash, const Symbol* sym, bool leakp, bool class_unload = false); + traceid mark(const Klass* k, bool leakp, bool class_unload = false); + traceid mark(const Symbol* sym, bool leakp = false, bool class_unload = false); + traceid mark(const char* str, bool leakp = false, bool class_unload = false); + traceid mark(unsigned hash, const char* str, bool leakp, bool class_unload = false); + traceid mark_hidden_klass_name(const Klass* k, bool leakp, bool class_unload = false); + + bool has_entries() const; + bool has_symbol_entries() const; + bool has_string_entries() const; + + unsigned symbols_capacity() const; + unsigned symbols_size() const; + unsigned strings_capacity() const; + unsigned strings_size() const; + + template + void iterate_symbols(Functor& functor); + + template + void iterate_strings(Functor& functor); + }; + + static Impl* _epoch_0; + static Impl* _epoch_1; + static StringEntry* _bootstrap; + + static bool create(); static void destroy(); - void clear(); - void increment_checkpoint_id(); - void set_class_unload(bool class_unload); + static Impl* this_epoch_table(); + static Impl* previous_epoch_table(); + static Impl* epoch_table_selector(u1 epoch); + static void set_this_epoch(Impl* table); + static void set_previous_epoch(Impl* table); - traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); - traceid mark(const Klass* k, bool leakp); - traceid mark(const Symbol* sym, bool leakp = false); - traceid mark(const char* str, bool leakp = false); - traceid mark(uintptr_t hash, const char* str, bool leakp); - traceid mark_hidden_klass_name(const Klass* k, bool leakp); - traceid bootstrap_name(bool leakp); + static void clear_previous_epoch(); + static void allocate_next_epoch(); - bool has_entries() const { return has_symbol_entries() || has_string_entries(); } - bool has_symbol_entries() const { return _symbol_list != nullptr; } - bool has_string_entries() const { return _string_list != nullptr; } + static bool has_entries(bool previous_epoch = false); + static bool has_symbol_entries(bool previous_epoch = false); + static bool has_string_entries(bool previous_epoch = false); - // hashtable(s) callbacks - void on_link(const SymbolEntry* entry); - bool on_equals(uintptr_t hash, const SymbolEntry* entry); - void on_unlink(const SymbolEntry* entry); - void on_link(const StringEntry* entry); - bool on_equals(uintptr_t hash, const StringEntry* entry); - void on_unlink(const StringEntry* entry); - - template - static traceid add_impl(const T* sym); - - template - void assign_id(T* entry); + static traceid mark(const Klass* k, bool leakp, bool class_unload = false, bool previous_epoch = false); + static traceid mark(const Symbol* sym, bool leakp = false, bool class_unload = false, bool previous_epoch = false); + static traceid mark(unsigned hash, const char* str, bool leakp, bool class_unload = false, bool previous_epoch = false); + static traceid bootstrap_name(bool leakp); template - void iterate_symbols(Functor& functor) { - iterate(functor, _symbol_list); - } + static void iterate_symbols(Functor& functor, bool previous_epoch = false); template - void iterate_strings(Functor& functor) { - iterate(functor, _string_list); - } - - template - void iterate(Functor& functor, const T* list) { - const T* symbol = list; - while (symbol != nullptr) { - const T* next = symbol->list_next(); - functor(symbol); - symbol = next; - } - } + static void iterate_strings(Functor& functor, bool previous_epoch = false); }; #endif // SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_HPP diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.inline.hpp b/src/hotspot/share/jfr/support/jfrSymbolTable.inline.hpp new file mode 100644 index 00000000000..9e7ac8c9d47 --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.inline.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_INLINE_HPP +#define SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_INLINE_HPP + +#include "jfr/support/jfrSymbolTable.hpp" + +#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp" +#include "jfr/utilities/jfrConcurrentHashtable.inline.hpp" + +inline JfrSymbolTable::Impl* JfrSymbolTable::epoch_table_selector(u1 epoch) { + return epoch == 0 ? _epoch_0 : _epoch_1; +} + +inline JfrSymbolTable::Impl* JfrSymbolTable::this_epoch_table() { + return epoch_table_selector(JfrTraceIdEpoch::current()); +} + +inline JfrSymbolTable::Impl* JfrSymbolTable::previous_epoch_table() { + return epoch_table_selector(JfrTraceIdEpoch::previous()); +} + +template +inline void JfrSymbolTable::Impl::iterate_symbols(Functor& functor) { + _symbols->iterate_entry(functor); +} + +template +inline void JfrSymbolTable::iterate_symbols(Functor& functor, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + table->iterate_symbols(functor); +} + +template +inline void JfrSymbolTable::Impl::iterate_strings(Functor& functor) { + _strings->iterate_entry(functor); +} + +template +inline void JfrSymbolTable::iterate_strings(Functor& functor, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + if (!functor(_bootstrap)) { + return; + } + table->iterate_strings(functor); +} + +#endif // SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_INLINE_HPP diff --git a/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp b/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp index bb0e3e082fe..46b4d973ce4 100644 --- a/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp +++ b/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp @@ -42,7 +42,6 @@ #define ASSIGN_PRIMITIVE_CLASS_ID(data) JfrTraceId::assign_primitive_klass_id() #define REMOVE_ID(k) JfrTraceId::remove(k); #define REMOVE_METHOD_ID(method) JfrTraceId::remove(method); -#define RESTORE_ID(k) JfrTraceId::restore(k); static constexpr const uint16_t cleared_epoch_bits = 512 | 256; diff --git a/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.hpp b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.hpp new file mode 100644 index 00000000000..5434023e636 --- /dev/null +++ b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.hpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_HPP +#define SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_HPP + +#include "jfr/utilities/jfrLinkedList.hpp" +#include "memory/allocation.hpp" + +template class TableEntry> +class JfrConcurrentAscendingId { +private: + IdType _id; +public: + JfrConcurrentAscendingId() : _id(1) {} + // Callbacks. + void on_link(TableEntry* entry); + bool on_equals(unsigned hash, const TableEntry* entry); +}; + +template +class JfrConcurrentHashtableEntry : public CHeapObj { + template + friend class JfrLinkedList; + private: + typedef JfrConcurrentHashtableEntry Entry; + Entry* _next; + T _literal; // ref to item in table. + mutable IdType _id; + unsigned _hash; + + public: + JfrConcurrentHashtableEntry(unsigned hash, const T& data) : _next(nullptr), _literal(data), _id(0), _hash(hash) {} + unsigned hash() const { return _hash; } + T literal() const { return _literal; } + T* literal_addr() { return &_literal; } + void set_literal(T s) { _literal = s; } + void set_next(Entry* next) { _next = next; } + Entry* next() const { return _next; } + Entry** next_addr() { return &_next; } + IdType id() const { return _id; } + void set_id(IdType id) const { _id = id; } + T& value() const { return *const_cast(this)->literal_addr(); } + const T* value_addr() const { return const_cast(this)->literal_addr(); } +}; + +template class TableEntry> +class JfrConcurrentHashtable : public CHeapObj { + public: + typedef TableEntry Entry; + typedef JfrLinkedList Bucket; + + unsigned capacity() const { return _capacity; } + unsigned size() const; + + protected: + JfrConcurrentHashtable(unsigned size); + ~JfrConcurrentHashtable(); + + unsigned index(unsigned hash) const { + return hash & _mask; + } + + Bucket& bucket(unsigned idx) { return _buckets[idx]; } + Bucket* bucket_addr(unsigned idx) { return &_buckets[idx]; } + Entry* head(unsigned idx) { return bucket(idx).head(); } + + bool try_add(unsigned idx, Entry* entry, Entry* next); + + template + void iterate(Callback& cb); + + template + void iterate(unsigned idx, Callback& cb); + + template + static void iterate(Entry* entry, Callback& cb); + + void unlink_entry(Entry* entry); + + private: + Bucket* _buckets; + unsigned _capacity; + unsigned _mask; + unsigned _size; +}; + +template class TableEntry, + typename Callback = JfrConcurrentAscendingId, unsigned TABLE_CAPACITY = 1024> +class JfrConcurrentHashTableHost : public JfrConcurrentHashtable { + public: + typedef TableEntry Entry; + JfrConcurrentHashTableHost(unsigned initial_capacity = 0); + JfrConcurrentHashTableHost(Callback* cb, unsigned initial_capacity = 0); + ~JfrConcurrentHashTableHost(); + + // lookup entry, will put if not found + Entry* lookup_put(unsigned hash, const T& data); + + // id retrieval + IdType id(unsigned hash, const T& data); + + bool is_empty() const; + bool is_nonempty() const { return !is_empty(); } + + template + void iterate_value(Functor& f); + + template + void iterate_entry(Functor& f); + + private: + Callback* _callback; + + Entry* new_entry(unsigned hash, const T& data); +}; + +#endif // SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_HPP diff --git a/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp new file mode 100644 index 00000000000..6d6908234a3 --- /dev/null +++ b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_INLINE_HPP +#define SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_INLINE_HPP + +#include "jfr/utilities/jfrConcurrentHashtable.hpp" + +#include "jfr/utilities/jfrLinkedList.inline.hpp" +#include "memory/allocation.inline.hpp" +#include "nmt/memTracker.hpp" +#include "runtime/atomicAccess.hpp" +#include "utilities/debug.hpp" +#include "utilities/macros.hpp" + +template class TableEntry> +inline void JfrConcurrentAscendingId::on_link(TableEntry* entry) { + assert(entry != nullptr, "invariant"); + assert(entry->id() == 0, "invariant"); + entry->set_id(AtomicAccess::fetch_then_add(&_id, static_cast(1))); +} + +template class TableEntry> +inline bool JfrConcurrentAscendingId::on_equals(unsigned hash, const TableEntry* entry) { + assert(entry != nullptr, "invariant"); + assert(entry->hash() == hash, "invariant"); + return true; +} + +template class TableEntry> +inline JfrConcurrentHashtable::JfrConcurrentHashtable(unsigned initial_capacity) : + _buckets(nullptr), _capacity(initial_capacity), _mask(initial_capacity - 1), _size(0) { + assert(initial_capacity >= 2, "invariant"); + assert(is_power_of_2(initial_capacity), "invariant"); + _buckets = NEW_C_HEAP_ARRAY2(Bucket, initial_capacity, mtTracing, CURRENT_PC); + memset((void*)_buckets, 0, initial_capacity * sizeof(Bucket)); +} + +template class TableEntry> +inline JfrConcurrentHashtable::~JfrConcurrentHashtable() { + FREE_C_HEAP_ARRAY(Bucket, _buckets); +} + +template class TableEntry> +inline unsigned JfrConcurrentHashtable::size() const { + return AtomicAccess::load(&_size); +} + +template class TableEntry> +template +inline void JfrConcurrentHashtable::iterate(unsigned idx, Callback& cb) { + assert(idx < _capacity, "invariant"); + bucket(idx).iterate(cb); +} + +template class TableEntry> +template +inline void JfrConcurrentHashtable::iterate(Callback& cb) { + for (unsigned i = 0; i < _capacity; ++i) { + iterate(i, cb); + } +} + +template class TableEntry> +template +inline void JfrConcurrentHashtable::iterate(TableEntry* entry, Callback& cb) { + Bucket::iterate(entry, cb); +} + +template class TableEntry> +inline bool JfrConcurrentHashtable::try_add(unsigned idx, TableEntry* entry, TableEntry* next) { + assert(entry != nullptr, "invariant"); + entry->set_next(next); + const bool added = bucket(idx).try_add(entry, next); + if (added) { + AtomicAccess::inc(&_size); + } + return added; +} + +template class TableEntry> +inline void JfrConcurrentHashtable::unlink_entry(TableEntry* entry) { + AtomicAccess::dec(&_size); +} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline JfrConcurrentHashTableHost::JfrConcurrentHashTableHost(unsigned initial_capacity /* 0 */) : + JfrConcurrentHashtable(initial_capacity == 0 ? TABLE_CAPACITY : initial_capacity), _callback(new Callback()) {} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline JfrConcurrentHashTableHost::JfrConcurrentHashTableHost(Callback* cb, unsigned initial_capacity /* 0 */) : + JfrConcurrentHashtable(initial_capacity == 0 ? TABLE_CAPACITY : initial_capacity), _callback(cb) {} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline bool JfrConcurrentHashTableHost::is_empty() const { + return this->size() == 0; +} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline TableEntry* JfrConcurrentHashTableHost::new_entry(unsigned hash, const T& data) { + Entry* const entry = new Entry(hash, data); + assert(entry != nullptr, "invariant"); + assert(0 == entry->id(), "invariant"); + _callback->on_link(entry); + assert(0 != entry->id(), "invariant"); + return entry; +} + +template +class JfrConcurrentHashtableLookup { + private: + Callback* const _cb; + const T& _data; + Entry* _found; + unsigned _hash; + public: + JfrConcurrentHashtableLookup(unsigned hash, const T& data, Callback* cb) : _cb(cb), _data(data), _found(nullptr), _hash(hash) {} + + bool process(Entry* entry) { + assert(entry != nullptr, "invariant"); + if (entry->hash() == _hash && entry->on_equals(_data)) { + _found = entry; + return false; + } + return true; + } + + bool found() const { return _found != nullptr; } + Entry* result() const { return _found; } +}; + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline TableEntry* JfrConcurrentHashTableHost::lookup_put(unsigned hash, const T& data) { + JfrConcurrentHashtableLookup lookup(hash, data, _callback); + const unsigned idx = this->index(hash); + Entry* entry = nullptr; + while (true) { + assert(!lookup.found(), "invariant"); + Entry* next = this->head(idx); + if (next != nullptr) { + JfrConcurrentHashtable::iterate(next, lookup); + if (lookup.found()) { + if (entry != nullptr) { + _callback->on_unlink(entry); + delete entry; + } + entry = lookup.result(); + break; + } + } + if (entry == nullptr) { + entry = new_entry(hash, data); + } + assert(entry != nullptr, "invariant"); + if (this->try_add(idx, entry, next)) { + break; + } + // Concurrent insertion to this bucket. Retry. + } + assert(entry != nullptr, "invariant"); + return entry; +} + +// id retrieval +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline IdType JfrConcurrentHashTableHost::id(unsigned hash, const T& data) { + assert(data != nullptr, "invariant"); + const Entry* const entry = lookup_put(hash, data); + assert(entry != nullptr, "invariant"); + assert(entry->id() > 0, "invariant"); + return entry->id(); +} + +template +class JfrConcurrentHashtableClear { + private: + Callback* const _cb; + public: + JfrConcurrentHashtableClear(Callback* cb) : _cb(cb) {} + + bool process(const Entry* entry) { + assert(entry != nullptr, "invariant"); + _cb->on_unlink(entry); + delete entry; + return true; + } +}; + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline JfrConcurrentHashTableHost::~JfrConcurrentHashTableHost() { + JfrConcurrentHashtableClear cls(_callback); + this->iterate(cls); +} + +template +class JfrConcurrentHashtableValueDelegator { + private: + Functor& _f; + public: + JfrConcurrentHashtableValueDelegator(Functor& f) : _f(f) {} + bool process(const Entry* entry) { + assert(entry != nullptr, "invariant"); + return _f(entry->value()); + } +}; + +template +class JfrConcurrentHashtableEntryDelegator { + private: + Functor& _f; + public: + JfrConcurrentHashtableEntryDelegator(Functor& f) : _f(f) {} + bool process(const Entry* entry) { + assert(entry != nullptr, "invariant"); + return _f(entry); + } +}; + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +template +inline void JfrConcurrentHashTableHost::iterate_value(Functor& f) { + JfrConcurrentHashtableValueDelegator delegator(f); + this->iterate(delegator); +} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +template +inline void JfrConcurrentHashTableHost::iterate_entry(Functor& f) { + JfrConcurrentHashtableEntryDelegator delegator(f); + this->iterate(delegator); +} + +#endif // SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_INLINE_HPP diff --git a/src/hotspot/share/jfr/utilities/jfrLinkedList.hpp b/src/hotspot/share/jfr/utilities/jfrLinkedList.hpp index 96e3acc0daa..a0d18bd383c 100644 --- a/src/hotspot/share/jfr/utilities/jfrLinkedList.hpp +++ b/src/hotspot/share/jfr/utilities/jfrLinkedList.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,10 +43,13 @@ class JfrLinkedList : public AllocPolicy { bool is_empty() const; bool is_nonempty() const; void add(NodePtr node); + bool try_add(NodePtr node, NodePtr next); void add_list(NodePtr first); NodePtr remove(); template void iterate(Callback& cb); + template + static void iterate(NodePtr node, Callback& cb); NodePtr head() const; NodePtr excise(NodePtr prev, NodePtr node); bool in_list(const NodeType* node) const; diff --git a/src/hotspot/share/jfr/utilities/jfrLinkedList.inline.hpp b/src/hotspot/share/jfr/utilities/jfrLinkedList.inline.hpp index fed379672dc..f481caa6528 100644 --- a/src/hotspot/share/jfr/utilities/jfrLinkedList.inline.hpp +++ b/src/hotspot/share/jfr/utilities/jfrLinkedList.inline.hpp @@ -30,10 +30,10 @@ #include "runtime/atomicAccess.hpp" template -JfrLinkedList::JfrLinkedList() : _head(nullptr) {} +inline JfrLinkedList::JfrLinkedList() : _head(nullptr) {} template -bool JfrLinkedList::initialize() { +inline bool JfrLinkedList::initialize() { return true; } @@ -62,6 +62,13 @@ inline void JfrLinkedList::add(NodeType* node) { } while (AtomicAccess::cmpxchg(&_head, next, node) != next); } +template +inline bool JfrLinkedList::try_add(NodeType* node, NodeType* next) { + assert(node != nullptr, "invariant"); + assert(node->_next == next, "invariant"); + return head() == next && AtomicAccess::cmpxchg(&_head, next, node) == next; +} + template inline NodeType* JfrLinkedList::remove() { NodePtr node; @@ -76,19 +83,24 @@ inline NodeType* JfrLinkedList::remove() { template template -void JfrLinkedList::iterate(Callback& cb) { - NodePtr current = head(); - while (current != nullptr) { - NodePtr next = (NodePtr)current->_next; - if (!cb.process(current)) { +inline void JfrLinkedList::iterate(Callback& cb) { + JfrLinkedList::iterate(head(), cb); +} + +template +template +inline void JfrLinkedList::iterate(NodeType* node, Callback& cb) { + while (node != nullptr) { + NodePtr next = (NodePtr)node->_next; + if (!cb.process(node)) { return; } - current = next; + node = next; } } template -NodeType* JfrLinkedList::excise(NodeType* prev, NodeType* node) { +inline NodeType* JfrLinkedList::excise(NodeType* prev, NodeType* node) { NodePtr next = (NodePtr)node->_next; if (prev == nullptr) { prev = AtomicAccess::cmpxchg(&_head, node, next); @@ -106,7 +118,7 @@ NodeType* JfrLinkedList::excise(NodeType* prev, NodeType* } template -bool JfrLinkedList::in_list(const NodeType* node) const { +inline bool JfrLinkedList::in_list(const NodeType* node) const { assert(node != nullptr, "invariant"); const NodeType* current = head(); while (current != nullptr) { @@ -119,7 +131,7 @@ bool JfrLinkedList::in_list(const NodeType* node) const { } template -NodeType* JfrLinkedList::cut() { +inline NodeType* JfrLinkedList::cut() { NodePtr node; do { node = head(); @@ -128,7 +140,7 @@ NodeType* JfrLinkedList::cut() { } template -void JfrLinkedList::clear() { +inline void JfrLinkedList::clear() { cut(); } diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 7ef16f6e32c..91482e825cd 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -37,6 +37,7 @@ #include "runtime/continuationEntry.hpp" #include "runtime/deoptimization.hpp" #include "runtime/flags/jvmFlag.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/osThread.hpp" #include "runtime/sharedRuntime.hpp" @@ -222,6 +223,7 @@ volatile_nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \ volatile_nonstatic_field(InstanceKlass, _init_thread, JavaThread*) \ nonstatic_field(InstanceKlass, _misc_flags._flags, u2) \ + nonstatic_field(InstanceKlass, _access_flags, AccessFlags) \ nonstatic_field(InstanceKlass, _annotations, Annotations*) \ \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_sp, intptr_t*) \ @@ -259,13 +261,13 @@ nonstatic_field(JavaThread, _om_cache, OMCache) \ nonstatic_field(JavaThread, _cont_entry, ContinuationEntry*) \ nonstatic_field(JavaThread, _unlocked_inflated_monitor, ObjectMonitor*) \ - JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_VTMS_transition, bool)) \ + nonstatic_field(JavaThread, _is_in_vthread_transition, bool) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_disable_suspend, bool)) \ \ nonstatic_field(ContinuationEntry, _pin_count, uint32_t) \ nonstatic_field(LockStack, _top, uint32_t) \ \ - JVMTI_ONLY(static_field(JvmtiVTMSTransitionDisabler, _VTMS_notify_jvmti_events, bool)) \ + static_field(MountUnmountDisabler, _notify_jvmti_events, bool) \ \ static_field(java_lang_Class, _klass_offset, int) \ static_field(java_lang_Class, _array_klass_offset, int) \ @@ -281,7 +283,6 @@ nonstatic_field(Klass, _name, Symbol*) \ volatile_nonstatic_field(Klass, _next_sibling, Klass*) \ nonstatic_field(Klass, _java_mirror, OopHandle) \ - nonstatic_field(Klass, _access_flags, AccessFlags) \ nonstatic_field(Klass, _class_loader_data, ClassLoaderData*) \ nonstatic_field(Klass, _secondary_supers_bitmap, uintx) \ nonstatic_field(Klass, _hash_slot, uint8_t) \ @@ -435,7 +436,7 @@ JFR_ONLY(nonstatic_field(Thread, _jfr_thread_local, JfrThreadLocal)) \ \ static_field(java_lang_Thread, _tid_offset, int) \ - static_field(java_lang_Thread, _jvmti_is_in_VTMS_transition_offset, int) \ + static_field(java_lang_Thread, _is_in_vthread_transition_offset, int) \ JFR_ONLY(static_field(java_lang_Thread, _jfr_epoch_offset, int)) \ \ JFR_ONLY(nonstatic_field(JfrThreadLocal, _vthread_id, traceid)) \ @@ -585,6 +586,7 @@ declare_constant(nmethod::InvalidationReason::UNCOMMON_TRAP) \ declare_constant(nmethod::InvalidationReason::WHITEBOX_DEOPTIMIZATION) \ declare_constant(nmethod::InvalidationReason::ZOMBIE) \ + declare_constant(nmethod::InvalidationReason::RELOCATED) \ \ declare_constant(CodeInstaller::VERIFIED_ENTRY) \ declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ @@ -877,10 +879,6 @@ declare_function(SharedRuntime::enable_stack_reserved_zone) \ declare_function(SharedRuntime::frem) \ declare_function(SharedRuntime::drem) \ - JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_start)) \ - JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_end)) \ - JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_mount)) \ - JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_unmount)) \ \ declare_function(os::dll_load) \ declare_function(os::dll_lookup) \ diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 4d2897be5eb..cfbab1b8afb 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -544,7 +544,7 @@ void Universe::genesis(TRAPS) { // Only modify the global variable inside the mutex. // If we had a race to here, the other dummy_array instances // and their elements just get dropped on the floor, which is fine. - MutexLocker ml(THREAD, FullGCALot_lock); + MutexLocker ml(THREAD, FullGCALot_lock, Mutex::_no_safepoint_check_flag); if (_fullgc_alot_dummy_array.is_empty()) { _fullgc_alot_dummy_array = OopHandle(vm_global(), dummy_array()); } @@ -1458,7 +1458,7 @@ uintptr_t Universe::verify_mark_bits() { #ifdef ASSERT // Release dummy object(s) at bottom of heap bool Universe::release_fullgc_alot_dummy() { - MutexLocker ml(FullGCALot_lock); + MutexLocker ml(FullGCALot_lock, Mutex::_no_safepoint_check_flag); objArrayOop fullgc_alot_dummy_array = (objArrayOop)_fullgc_alot_dummy_array.resolve(); if (fullgc_alot_dummy_array != nullptr) { if (_fullgc_alot_dummy_next >= fullgc_alot_dummy_array->length()) { diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp index cd929a3bfe1..30a2bc5102a 100644 --- a/src/hotspot/share/oops/arrayKlass.cpp +++ b/src/hotspot/share/oops/arrayKlass.cpp @@ -99,7 +99,8 @@ ArrayKlass::ArrayKlass(Symbol* name, KlassKind kind) : set_name(name); set_super(Universe::is_bootstrapping() ? nullptr : vmClasses::Object_klass()); set_layout_helper(Klass::_lh_neutral_value); - set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5) + // All arrays are considered to be cloneable (See JLS 20.1.5) + set_is_cloneable_fast(); JFR_ONLY(INIT_ID(this);) log_array_class_load(this); } diff --git a/src/hotspot/share/oops/fieldInfo.hpp b/src/hotspot/share/oops/fieldInfo.hpp index a98895da9cf..b6d9c4d34e5 100644 --- a/src/hotspot/share/oops/fieldInfo.hpp +++ b/src/hotspot/share/oops/fieldInfo.hpp @@ -27,6 +27,7 @@ #include "memory/allocation.hpp" #include "oops/typeArrayOop.hpp" +#include "utilities/accessFlags.hpp" #include "utilities/unsigned5.hpp" #include "utilities/vmEnums.hpp" diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 24358f662bc..e74bc80d893 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -552,6 +552,17 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind, Refe assert(size_helper() == parser.layout_size(), "incorrect size_helper?"); } +void InstanceKlass::set_is_cloneable() { + if (name() == vmSymbols::java_lang_invoke_MemberName()) { + assert(is_final(), "no subclasses allowed"); + // MemberName cloning should not be intrinsified and always happen in JVM_Clone. + } else if (reference_type() != REF_NONE) { + // Reference cloning should not be intrinsified and always happen in JVM_Clone. + } else { + set_is_cloneable_fast(); + } +} + void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data, Array* methods) { if (methods != nullptr && methods != Universe::the_empty_method_array() && diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 8bb9741af9f..a03e6c05b54 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -229,7 +229,9 @@ class InstanceKlass: public Klass { // _idnum_allocated_count. volatile ClassState _init_state; // state of class - u1 _reference_type; // reference type + u1 _reference_type; // reference type + + AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. // State is set either at parse time or while executing, atomically to not disturb other state InstanceKlassFlags _misc_flags; @@ -305,6 +307,22 @@ class InstanceKlass: public Klass { // Sets finalization state static void set_finalization_enabled(bool val) { _finalization_enabled = val; } + // Access flags + AccessFlags access_flags() const { return _access_flags; } + void set_access_flags(AccessFlags flags) { _access_flags = flags; } + + bool is_public() const { return _access_flags.is_public(); } + bool is_final() const { return _access_flags.is_final(); } + bool is_interface() const { return _access_flags.is_interface(); } + bool is_abstract() const { return _access_flags.is_abstract(); } + bool is_super() const { return _access_flags.is_super(); } + bool is_synthetic() const { return _access_flags.is_synthetic(); } + void set_is_synthetic() { _access_flags.set_is_synthetic(); } + + static ByteSize access_flags_offset() { return byte_offset_of(InstanceKlass, _access_flags); } + + void set_is_cloneable(); + // Quick checks for the loader that defined this class (without switching on this->class_loader()) bool defined_by_boot_loader() const { return _misc_flags.defined_by_boot_loader(); } bool defined_by_platform_loader() const { return _misc_flags.defined_by_platform_loader(); } diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index b30ec2f4887..001e9eba790 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -57,6 +57,10 @@ #include "utilities/rotate_bits.hpp" #include "utilities/stack.inline.hpp" +#if INCLUDE_JFR +#include "jfr/jfr.hpp" +#endif + void Klass::set_java_mirror(Handle m) { assert(!m.is_null(), "New mirror should never be null."); assert(_java_mirror.is_empty(), "should only be used to initialize mirror"); @@ -68,17 +72,6 @@ bool Klass::is_cloneable() const { is_subtype_of(vmClasses::Cloneable_klass()); } -void Klass::set_is_cloneable() { - if (name() == vmSymbols::java_lang_invoke_MemberName()) { - assert(is_final(), "no subclasses allowed"); - // MemberName cloning should not be intrinsified and always happen in JVM_Clone. - } else if (is_instance_klass() && InstanceKlass::cast(this)->reference_type() != REF_NONE) { - // Reference cloning should not be intrinsified and always happen in JVM_Clone. - } else { - _misc_flags.set_is_cloneable_fast(true); - } -} - uint8_t Klass::compute_hash_slot(Symbol* n) { uint hash_code; // Special cases for the two superclasses of all Array instances. @@ -862,7 +855,6 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec assert(is_klass(), "ensure C++ vtable is restored"); assert(in_aot_cache(), "must be set"); assert(secondary_supers()->length() >= (int)population_count(_secondary_supers_bitmap), "must be"); - JFR_ONLY(RESTORE_ID(this);) if (log_is_enabled(Trace, aot, unshareable)) { ResourceMark rm(THREAD); oop class_loader = loader_data->class_loader(); @@ -876,10 +868,13 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec if (class_loader_data() == nullptr) { set_class_loader_data(loader_data); } + // Add to class loader list first before creating the mirror // (same order as class file parsing) loader_data->add_class(this); + JFR_ONLY(Jfr::on_restoration(this, THREAD);) + Handle loader(THREAD, loader_data->class_loader()); ModuleEntry* module_entry = nullptr; Klass* k = this; diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 5ac393d7614..25fb900e7d6 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -30,7 +30,6 @@ #include "oops/metadata.hpp" #include "oops/oop.hpp" #include "oops/oopHandle.hpp" -#include "utilities/accessFlags.hpp" #include "utilities/macros.hpp" #if INCLUDE_JFR #include "jfr/support/jfrTraceIdExtension.hpp" @@ -120,9 +119,8 @@ class Klass : public Metadata { // - Various type checking in the JVM const KlassKind _kind; - AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. - // Some flags created by the JVM, not in the class file itself, - // are in _misc_flags below. + // Some flags created by the JVM, not in the class file itself, + // are in _misc_flags below. KlassFlags _misc_flags; // The fields _super_check_offset, _secondary_super_cache, _secondary_supers @@ -453,7 +451,6 @@ protected: static ByteSize java_mirror_offset() { return byte_offset_of(Klass, _java_mirror); } static ByteSize class_loader_data_offset() { return byte_offset_of(Klass, _class_loader_data); } static ByteSize layout_helper_offset() { return byte_offset_of(Klass, _layout_helper); } - static ByteSize access_flags_offset() { return byte_offset_of(Klass, _access_flags); } #if INCLUDE_JVMCI static ByteSize subklass_offset() { return byte_offset_of(Klass, _subklass); } static ByteSize next_sibling_offset() { return byte_offset_of(Klass, _next_sibling); } @@ -707,17 +704,10 @@ public: bool is_typeArray_klass() const { return assert_same_query( _kind == TypeArrayKlassKind, is_typeArray_klass_slow()); } #undef assert_same_query - // Access flags - AccessFlags access_flags() const { return _access_flags; } - void set_access_flags(AccessFlags flags) { _access_flags = flags; } - bool is_public() const { return _access_flags.is_public(); } - bool is_final() const { return _access_flags.is_final(); } - bool is_interface() const { return _access_flags.is_interface(); } - bool is_abstract() const { return _access_flags.is_abstract(); } - bool is_super() const { return _access_flags.is_super(); } - bool is_synthetic() const { return _access_flags.is_synthetic(); } - void set_is_synthetic() { _access_flags.set_is_synthetic(); } + virtual bool is_interface() const { return false; } + virtual bool is_abstract() const { return false; } + bool has_finalizer() const { return _misc_flags.has_finalizer(); } void set_has_finalizer() { _misc_flags.set_has_finalizer(true); } bool is_hidden() const { return _misc_flags.is_hidden_class(); } @@ -730,7 +720,7 @@ public: inline bool is_non_strong_hidden() const; bool is_cloneable() const; - void set_is_cloneable(); + void set_is_cloneable_fast() { _misc_flags.set_is_cloneable_fast(true); } inline markWord prototype_header() const; inline void set_prototype_header(markWord header); diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index cb1c8ea37e8..1a2e5f0bee4 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -168,11 +168,17 @@ address Method::get_c2i_entry() { } address Method::get_c2i_unverified_entry() { + if (is_abstract()) { + return SharedRuntime::get_handle_wrong_method_abstract_stub(); + } assert(adapter() != nullptr, "must have"); return adapter()->get_c2i_unverified_entry(); } address Method::get_c2i_no_clinit_check_entry() { + if (is_abstract()) { + return nullptr; + } assert(VM_Version::supports_fast_class_init_checks(), ""); assert(adapter() != nullptr, "must have"); return adapter()->get_c2i_no_clinit_check_entry(); diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index acc28964627..ead1b78cdea 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -859,11 +859,11 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_VectorBinaryLibOp: return EnableVectorSupport && Matcher::supports_vector_calling_convention(); case vmIntrinsics::_blackhole: + case vmIntrinsics::_vthreadEndFirstTransition: + case vmIntrinsics::_vthreadStartFinalTransition: + case vmIntrinsics::_vthreadStartTransition: + case vmIntrinsics::_vthreadEndTransition: #if INCLUDE_JVMTI - case vmIntrinsics::_notifyJvmtiVThreadStart: - case vmIntrinsics::_notifyJvmtiVThreadEnd: - case vmIntrinsics::_notifyJvmtiVThreadMount: - case vmIntrinsics::_notifyJvmtiVThreadUnmount: case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: #endif break; diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 483cb731103..db03dd9d80c 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -420,7 +420,6 @@ bool LateInlineMHCallGenerator::do_late_inline_check(Compile* C, JVMState* jvms) } assert(!cg->is_late_inline() || cg->is_mh_late_inline() || AlwaysIncrementalInline || StressIncrementalInlining, "we're doing late inlining"); _inline_cg = cg; - C->dec_number_of_mh_late_inlines(); return true; } else { // Method handle call which has a constant appendix argument should be either inlined or replaced with a direct call @@ -432,7 +431,7 @@ bool LateInlineMHCallGenerator::do_late_inline_check(Compile* C, JVMState* jvms) CallGenerator* CallGenerator::for_mh_late_inline(ciMethod* caller, ciMethod* callee, bool input_not_const) { assert(IncrementalInlineMH, "required"); - Compile::current()->inc_number_of_mh_late_inlines(); + Compile::current()->mark_has_mh_late_inlines(); CallGenerator* cg = new LateInlineMHCallGenerator(caller, callee, input_not_const); return cg; } diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index 24744bf3bdd..b19c707e456 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1147,7 +1147,6 @@ Node* CallStaticJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) { assert(callee->has_member_arg(), "wrong type of call?"); if (in(TypeFunc::Parms + callee->arg_size() - 1)->Opcode() == Op_ConP) { register_for_late_inline(); - phase->C->inc_number_of_mh_late_inlines(); } } } else { diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 9029a009989..90a86d76679 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -730,9 +730,10 @@ public: // for some macro nodes whose expansion does not have a safepoint on the fast path. virtual bool guaranteed_safepoint() { return true; } // For macro nodes, the JVMState gets modified during expansion. If calls - // use MachConstantBase, it gets modified during matching. So when cloning - // the node the JVMState must be deep cloned. Default is to shallow clone. - virtual bool needs_deep_clone_jvms(Compile* C) { return C->needs_deep_clone_jvms(); } + // use MachConstantBase, it gets modified during matching. If the call is + // late inlined, it also needs the full JVMState. So when cloning the + // node the JVMState must be deep cloned. Default is to shallow clone. + virtual bool needs_deep_clone_jvms(Compile* C) { return _generator != nullptr || C->needs_deep_clone_jvms(); } // Returns true if the call may modify n virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase); diff --git a/src/hotspot/share/opto/chaitin.hpp b/src/hotspot/share/opto/chaitin.hpp index ac072e94e2b..2d4f7eeb3f2 100644 --- a/src/hotspot/share/opto/chaitin.hpp +++ b/src/hotspot/share/opto/chaitin.hpp @@ -144,7 +144,7 @@ public: private: // Number of registers this live range uses when it colors - uint16_t _num_regs; // 2 for Longs and Doubles, 1 for all else + uint16_t _num_regs; // byte size of the value divided by slot size which is 4 // except _num_regs is kill count for fat_proj // For scalable register, num_regs may not be the actual physical register size. diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 89b5e36b120..bf7feeed0a2 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -686,7 +686,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, _boxing_late_inlines(comp_arena(), 2, 0, nullptr), _vector_reboxing_late_inlines(comp_arena(), 2, 0, nullptr), _late_inlines_pos(0), - _number_of_mh_late_inlines(0), + _has_mh_late_inlines(false), _oom(false), _replay_inline_data(nullptr), _inline_printer(this), @@ -948,7 +948,7 @@ Compile::Compile(ciEnv* ci_env, _igvn_worklist(nullptr), _types(nullptr), _node_hash(nullptr), - _number_of_mh_late_inlines(0), + _has_mh_late_inlines(false), _oom(false), _replay_inline_data(nullptr), _inline_printer(this), @@ -1726,8 +1726,6 @@ Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_cr } if (flat->offset() == in_bytes(Klass::super_check_offset_offset())) alias_type(idx)->set_rewritable(false); - if (flat->offset() == in_bytes(Klass::access_flags_offset())) - alias_type(idx)->set_rewritable(false); if (flat->offset() == in_bytes(Klass::misc_flags_offset())) alias_type(idx)->set_rewritable(false); if (flat->offset() == in_bytes(Klass::java_mirror_offset())) @@ -1735,6 +1733,12 @@ Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_cr if (flat->offset() == in_bytes(Klass::secondary_super_cache_offset())) alias_type(idx)->set_rewritable(false); } + + if (flat->isa_instklassptr()) { + if (flat->offset() == in_bytes(InstanceKlass::access_flags_offset())) { + alias_type(idx)->set_rewritable(false); + } + } // %%% (We would like to finalize JavaThread::threadObj_offset(), // but the base pointer type is not distinctive enough to identify // references into JavaThread.) diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 845dcf07512..f5611062f2c 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -478,7 +478,9 @@ private: GrowableArray _vector_reboxing_late_inlines; // same but for vector reboxing operations int _late_inlines_pos; // Where in the queue should the next late inlining candidate go (emulate depth first inlining) - uint _number_of_mh_late_inlines; // number of method handle late inlining still pending + bool _has_mh_late_inlines; // Can there still be a method handle late inlining pending? + // false: there can't be one + // true: we've enqueued one at some point so there may still be one // "MemLimit" directive was specified and the memory limit was hit during compilation bool _oom; @@ -1096,9 +1098,8 @@ public: } } - void inc_number_of_mh_late_inlines() { _number_of_mh_late_inlines++; } - void dec_number_of_mh_late_inlines() { assert(_number_of_mh_late_inlines > 0, "_number_of_mh_late_inlines < 0 !"); _number_of_mh_late_inlines--; } - bool has_mh_late_inlines() const { return _number_of_mh_late_inlines > 0; } + void mark_has_mh_late_inlines() { _has_mh_late_inlines = true; } + bool has_mh_late_inlines() const { return _has_mh_late_inlines; } bool inline_incrementally_one(); void inline_incrementally_cleanup(PhaseIterGVN& igvn); diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index 91bb743618b..5533b19897b 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -1059,14 +1059,19 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) { assert(!stopped(), "you should return if you finish the chain"); // Oops, need to call into the VM to resolve the klasses at runtime. - // Note: This call must not deoptimize, since it is not a real at this bci! kill_dead_locals(); - make_runtime_call(RC_NO_LEAF | RC_MUST_THROW, - OptoRuntime::rethrow_Type(), - OptoRuntime::rethrow_stub(), - nullptr, nullptr, - ex_node); + { PreserveReexecuteState preexecs(this); + // When throwing an exception, set the reexecute flag for deoptimization. + // This is mostly needed to pass -XX:+VerifyStack sanity checks. + jvms()->set_should_reexecute(true); + + make_runtime_call(RC_NO_LEAF | RC_MUST_THROW, + OptoRuntime::rethrow_Type(), + OptoRuntime::rethrow_stub(), + nullptr, nullptr, + ex_node); + } // Rethrow is a pure call, no side effects, only a result. // The result cannot be allocated, so we use I_O diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 2b511a5214f..55a8a5032f2 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -55,6 +55,7 @@ #include "prims/jvmtiThreadState.hpp" #include "prims/unsafe.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" @@ -479,15 +480,15 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_Continuation_pin: return inline_native_Continuation_pinning(false); case vmIntrinsics::_Continuation_unpin: return inline_native_Continuation_pinning(true); + case vmIntrinsics::_vthreadEndFirstTransition: return inline_native_vthread_end_transition(CAST_FROM_FN_PTR(address, OptoRuntime::vthread_end_first_transition_Java()), + "endFirstTransition", true); + case vmIntrinsics::_vthreadStartFinalTransition: return inline_native_vthread_start_transition(CAST_FROM_FN_PTR(address, OptoRuntime::vthread_start_final_transition_Java()), + "startFinalTransition", true); + case vmIntrinsics::_vthreadStartTransition: return inline_native_vthread_start_transition(CAST_FROM_FN_PTR(address, OptoRuntime::vthread_start_transition_Java()), + "startTransition", false); + case vmIntrinsics::_vthreadEndTransition: return inline_native_vthread_end_transition(CAST_FROM_FN_PTR(address, OptoRuntime::vthread_end_transition_Java()), + "endTransition", false); #if INCLUDE_JVMTI - case vmIntrinsics::_notifyJvmtiVThreadStart: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_start()), - "notifyJvmtiStart", true, false); - case vmIntrinsics::_notifyJvmtiVThreadEnd: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_end()), - "notifyJvmtiEnd", false, true); - case vmIntrinsics::_notifyJvmtiVThreadMount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_mount()), - "notifyJvmtiMount", false, false); - case vmIntrinsics::_notifyJvmtiVThreadUnmount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_unmount()), - "notifyJvmtiUnmount", false, false); case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: return inline_native_notify_jvmti_sync(); #endif @@ -3042,48 +3043,82 @@ bool LibraryCallKit::inline_native_time_funcs(address funcAddr, const char* func return true; } - -#if INCLUDE_JVMTI - -// When notifications are disabled then just update the VTMS transition bit and return. -// Otherwise, the bit is updated in the given function call implementing JVMTI notification protocol. -bool LibraryCallKit::inline_native_notify_jvmti_funcs(address funcAddr, const char* funcName, bool is_start, bool is_end) { - if (!DoJVMTIVirtualThreadTransitions) { - return true; - } +//--------------------inline_native_vthread_start_transition-------------------- +// inline void startTransition(boolean is_mount); +// inline void startFinalTransition(); +// Pseudocode of implementation: +// +// java_lang_Thread::set_is_in_vthread_transition(vthread, true); +// carrier->set_is_in_vthread_transition(true); +// OrderAccess::storeload(); +// int disable_requests = java_lang_Thread::vthread_transition_disable_count(vthread) +// + global_vthread_transition_disable_count(); +// if (disable_requests > 0) { +// slow path: runtime call +// } +bool LibraryCallKit::inline_native_vthread_start_transition(address funcAddr, const char* funcName, bool is_final_transition) { Node* vt_oop = _gvn.transform(must_be_not_null(argument(0), true)); // VirtualThread this argument IdealKit ideal(this); - Node* ONE = ideal.ConI(1); - Node* hide = is_start ? ideal.ConI(0) : (is_end ? ideal.ConI(1) : _gvn.transform(argument(1))); - Node* addr = makecon(TypeRawPtr::make((address)&JvmtiVTMSTransitionDisabler::_VTMS_notify_jvmti_events)); + Node* thread = ideal.thread(); + Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_vthread_transition_offset())); + Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_vthread_transition_offset()); + access_store_at(nullptr, jt_addr, ideal.ConI(1), TypeInt::BOOL, T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + access_store_at(nullptr, vt_addr, ideal.ConI(1), TypeInt::BOOL, T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + insert_mem_bar(Op_MemBarVolatile); + ideal.sync_kit(this); - assert(C->get_alias_index(gvn().type(addr)->isa_ptr()) == Compile::AliasIdxRaw, "Computed slice mismatch"); - Node* notify_jvmti_enabled = ideal.load(ideal.ctrl(), addr, TypeInt::BOOL, T_BOOLEAN); + Node* global_disable_addr = makecon(TypeRawPtr::make((address)MountUnmountDisabler::global_vthread_transition_disable_count_address())); + assert(C->get_alias_index(gvn().type(global_disable_addr)->isa_ptr()) == Compile::AliasIdxRaw, "Computed slice mismatch"); + Node* global_disable = ideal.load(ideal.ctrl(), global_disable_addr, TypeInt::INT, T_INT, true /*require_atomic_access*/); + Node* vt_disable_addr = basic_plus_adr(vt_oop, java_lang_Thread::vthread_transition_disable_count_offset()); + assert(C->get_alias_index(gvn().type(vt_disable_addr)->isa_ptr()) == Compile::AliasIdxRaw, "Computed slice mismatch"); + Node* vt_disable = ideal.load(ideal.ctrl(), vt_disable_addr, TypeInt::INT, T_INT, true /*require_atomic_access*/); + Node* disabled = _gvn.transform(new AddINode(global_disable, vt_disable)); - ideal.if_then(notify_jvmti_enabled, BoolTest::eq, ONE); { + ideal.if_then(disabled, BoolTest::ne, ideal.ConI(0)); { sync_kit(ideal); - // if notifyJvmti enabled then make a call to the given SharedRuntime function - const TypeFunc* tf = OptoRuntime::notify_jvmti_vthread_Type(); - make_runtime_call(RC_NO_LEAF, tf, funcAddr, funcName, TypePtr::BOTTOM, vt_oop, hide); + Node* is_mount = is_final_transition ? ideal.ConI(0) : _gvn.transform(argument(1)); + const TypeFunc* tf = OptoRuntime::vthread_transition_Type(); + make_runtime_call(RC_NO_LEAF, tf, funcAddr, funcName, TypePtr::BOTTOM, vt_oop, is_mount); ideal.sync_kit(this); - } ideal.else_(); { - // set hide value to the VTMS transition bit in current JavaThread and VirtualThread object - Node* thread = ideal.thread(); - Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_VTMS_transition_offset())); - Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_VTMS_transition_offset()); + } + ideal.end_if(); - sync_kit(ideal); - access_store_at(nullptr, jt_addr, hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); - access_store_at(nullptr, vt_addr, hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); - - ideal.sync_kit(this); - } ideal.end_if(); final_sync(ideal); - return true; } +bool LibraryCallKit::inline_native_vthread_end_transition(address funcAddr, const char* funcName, bool is_first_transition) { + Node* vt_oop = _gvn.transform(must_be_not_null(argument(0), true)); // VirtualThread this argument + IdealKit ideal(this); + + Node* _notify_jvmti_addr = makecon(TypeRawPtr::make((address)MountUnmountDisabler::notify_jvmti_events_address())); + Node* _notify_jvmti = ideal.load(ideal.ctrl(), _notify_jvmti_addr, TypeInt::BOOL, T_BOOLEAN, Compile::AliasIdxRaw); + + ideal.if_then(_notify_jvmti, BoolTest::eq, ideal.ConI(1)); { + sync_kit(ideal); + Node* is_mount = is_first_transition ? ideal.ConI(1) : _gvn.transform(argument(1)); + const TypeFunc* tf = OptoRuntime::vthread_transition_Type(); + make_runtime_call(RC_NO_LEAF, tf, funcAddr, funcName, TypePtr::BOTTOM, vt_oop, is_mount); + ideal.sync_kit(this); + } ideal.else_(); { + Node* thread = ideal.thread(); + Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_vthread_transition_offset())); + Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_vthread_transition_offset()); + + sync_kit(ideal); + access_store_at(nullptr, jt_addr, ideal.ConI(0), TypeInt::BOOL, T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + access_store_at(nullptr, vt_addr, ideal.ConI(0), TypeInt::BOOL, T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + ideal.sync_kit(this); + } ideal.end_if(); + + final_sync(ideal); + return true; +} + +#if INCLUDE_JVMTI + // Always update the is_disable_suspend bit. bool LibraryCallKit::inline_native_notify_jvmti_sync() { if (!DoJVMTIVirtualThreadTransitions) { @@ -3992,7 +4027,7 @@ Node* LibraryCallKit::generate_klass_flags_guard(Node* kls, int modifier_mask, i } Node* LibraryCallKit::generate_interface_guard(Node* kls, RegionNode* region) { return generate_klass_flags_guard(kls, JVM_ACC_INTERFACE, 0, region, - Klass::access_flags_offset(), TypeInt::CHAR, T_CHAR); + InstanceKlass::access_flags_offset(), TypeInt::CHAR, T_CHAR); } // Use this for testing if Klass is_hidden, has_finalizer, and is_cloneable_fast. @@ -4104,12 +4139,16 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) { // Arrays store an intermediate super as _super, but must report Object. // Other types can report the actual _super. // (To verify this code sequence, check the asserts in JVM_IsInterface.) - if (generate_interface_guard(kls, region) != nullptr) - // A guard was added. If the guard is taken, it was an interface. - phi->add_req(null()); - if (generate_array_guard(kls, region) != nullptr) + if (generate_array_guard(kls, region) != nullptr) { // A guard was added. If the guard is taken, it was an array. phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror()))); + } + // Check for interface after array since this checks AccessFlags offset into InstanceKlass. + // In other words, we are accessing subtype-specific information, so we need to determine the subtype first. + if (generate_interface_guard(kls, region) != nullptr) { + // A guard was added. If the guard is taken, it was an interface. + phi->add_req(null()); + } // If we fall through, it's a plain class. Get its _super. p = basic_plus_adr(kls, in_bytes(Klass::super_offset())); kls = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeInstKlassPtr::OBJECT_OR_NULL)); @@ -7177,6 +7216,7 @@ Node * LibraryCallKit::field_address_from_object(Node * fromObj, const char * fi bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) { address stubAddr = nullptr; const char *stubName; + bool is_decrypt = false; assert(UseAES, "need AES instruction support"); switch(id) { @@ -7187,6 +7227,7 @@ bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) { case vmIntrinsics::_aescrypt_decryptBlock: stubAddr = StubRoutines::aescrypt_decryptBlock(); stubName = "aescrypt_decryptBlock"; + is_decrypt = true; break; default: break; @@ -7220,7 +7261,7 @@ bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) { // now need to get the start of its expanded key array // this requires a newer class file that has this array as littleEndian ints, otherwise we revert to java - Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); + Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, is_decrypt); if (k_start == nullptr) return false; // Call the stub. @@ -7235,7 +7276,7 @@ bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) { bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) { address stubAddr = nullptr; const char *stubName = nullptr; - + bool is_decrypt = false; assert(UseAES, "need AES instruction support"); switch(id) { @@ -7246,6 +7287,7 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) { case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: stubAddr = StubRoutines::cipherBlockChaining_decryptAESCrypt(); stubName = "cipherBlockChaining_decryptAESCrypt"; + is_decrypt = true; break; default: break; @@ -7299,7 +7341,7 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) { aescrypt_object = _gvn.transform(aescrypt_object); // we need to get the start of the aescrypt_object's expanded key array - Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); + Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, is_decrypt); if (k_start == nullptr) return false; // similarly, get the start address of the r vector @@ -7323,7 +7365,7 @@ bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) { bool LibraryCallKit::inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id) { address stubAddr = nullptr; const char *stubName = nullptr; - + bool is_decrypt = false; assert(UseAES, "need AES instruction support"); switch (id) { @@ -7334,6 +7376,7 @@ bool LibraryCallKit::inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id) { case vmIntrinsics::_electronicCodeBook_decryptAESCrypt: stubAddr = StubRoutines::electronicCodeBook_decryptAESCrypt(); stubName = "electronicCodeBook_decryptAESCrypt"; + is_decrypt = true; break; default: break; @@ -7385,7 +7428,7 @@ bool LibraryCallKit::inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id) { aescrypt_object = _gvn.transform(aescrypt_object); // we need to get the start of the aescrypt_object's expanded key array - Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); + Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, is_decrypt); if (k_start == nullptr) return false; // Call the stub, passing src_start, dest_start, k_start, r_start and src_len @@ -7453,7 +7496,7 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) { Node* aescrypt_object = new CheckCastPPNode(control(), embeddedCipherObj, xtype); aescrypt_object = _gvn.transform(aescrypt_object); // we need to get the start of the aescrypt_object's expanded key array - Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); + Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, /* is_decrypt */ false); if (k_start == nullptr) return false; // similarly, get the start address of the r vector Node* obj_counter = load_field_from_object(counterMode_object, "counter", "[B"); @@ -7478,25 +7521,21 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) { } //------------------------------get_key_start_from_aescrypt_object----------------------- -Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) { -#if defined(PPC64) || defined(S390) || defined(RISCV64) +Node* LibraryCallKit::get_key_start_from_aescrypt_object(Node* aescrypt_object, bool is_decrypt) { // MixColumns for decryption can be reduced by preprocessing MixColumns with round keys. // Intel's extension is based on this optimization and AESCrypt generates round keys by preprocessing MixColumns. // However, ppc64 vncipher processes MixColumns and requires the same round keys with encryption. - // The ppc64 and riscv64 stubs of encryption and decryption use the same round keys (sessionK[0]). - Node* objSessionK = load_field_from_object(aescrypt_object, "sessionK", "[[I"); - assert (objSessionK != nullptr, "wrong version of com.sun.crypto.provider.AES_Crypt"); - if (objSessionK == nullptr) { - return (Node *) nullptr; - } - Node* objAESCryptKey = load_array_element(objSessionK, intcon(0), TypeAryPtr::OOPS, /* set_ctrl */ true); + // The following platform specific stubs of encryption and decryption use the same round keys. +#if defined(PPC64) || defined(S390) || defined(RISCV64) + bool use_decryption_key = false; #else - Node* objAESCryptKey = load_field_from_object(aescrypt_object, "K", "[I"); -#endif // PPC64 - assert (objAESCryptKey != nullptr, "wrong version of com.sun.crypto.provider.AES_Crypt"); + bool use_decryption_key = is_decrypt; +#endif + Node* objAESCryptKey = load_field_from_object(aescrypt_object, use_decryption_key ? "sessionKd" : "sessionKe", "[I"); + assert(objAESCryptKey != nullptr, "wrong version of com.sun.crypto.provider.AES_Crypt"); if (objAESCryptKey == nullptr) return (Node *) nullptr; - // now have the array, need to get the start address of the K array + // now have the array, need to get the start address of the selected key array Node* k_start = array_element_address(objAESCryptKey, intcon(0), T_INT); return k_start; } @@ -8632,7 +8671,7 @@ bool LibraryCallKit::inline_galoisCounterMode_AESCrypt() { Node* aescrypt_object = new CheckCastPPNode(control(), embeddedCipherObj, xtype); aescrypt_object = _gvn.transform(aescrypt_object); // we need to get the start of the aescrypt_object's expanded key array - Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); + Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object, /* is_decrypt */ false); if (k_start == nullptr) return false; // similarly, get the start address of the r vector Node* cnt_start = array_element_address(counter, intcon(0), T_BYTE); diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index fbac1363dae..bfe29814dec 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -275,9 +275,11 @@ class LibraryCallKit : public GraphKit { bool inline_native_Continuation_pinning(bool unpin); bool inline_native_time_funcs(address method, const char* funcName); + + bool inline_native_vthread_start_transition(address funcAddr, const char* funcName, bool is_final_transition); + bool inline_native_vthread_end_transition(address funcAddr, const char* funcName, bool is_first_transition); + #if INCLUDE_JVMTI - bool inline_native_notify_jvmti_funcs(address funcAddr, const char* funcName, bool is_start, bool is_end); - bool inline_native_notify_jvmti_hide(); bool inline_native_notify_jvmti_sync(); #endif @@ -338,7 +340,7 @@ class LibraryCallKit : public GraphKit { Node* inline_cipherBlockChaining_AESCrypt_predicate(bool decrypting); Node* inline_electronicCodeBook_AESCrypt_predicate(bool decrypting); Node* inline_counterMode_AESCrypt_predicate(); - Node* get_key_start_from_aescrypt_object(Node* aescrypt_object); + Node* get_key_start_from_aescrypt_object(Node* aescrypt_object, bool is_decrypt); bool inline_ghash_processBlocks(); bool inline_chacha20Block(); bool inline_kyberNtt(); diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 9674daf23fa..a48c8e5c06c 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -1913,7 +1913,8 @@ Node* PhaseMacroExpand::prefetch_allocation(Node* i_o, Node*& needgc_false, transform_later(cache_adr); cache_adr = new CastP2XNode(needgc_false, cache_adr); transform_later(cache_adr); - // Address is aligned to execute prefetch to the beginning of cache line size. + // Address is aligned to execute prefetch to the beginning of cache line size + // (it is important when BIS instruction is used on SPARC as prefetch). Node* mask = _igvn.MakeConX(~(intptr_t)(step_size-1)); cache_adr = new AndXNode(cache_adr, mask); transform_later(cache_adr); diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index 159e13d8d23..69098befa38 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -285,13 +285,12 @@ void Matcher::match( ) { _parm_regs[i].set_pair(reg2, reg1); } - // Finally, make sure the incoming arguments take up an even number of - // words, in case the arguments or locals need to contain doubleword stack - // slots. The rest of the system assumes that stack slot pairs (in - // particular, in the spill area) which look aligned will in fact be - // aligned relative to the stack pointer in the target machine. Double - // stack slots will always be allocated aligned. - _new_SP = OptoReg::Name(align_up(_in_arg_limit, (int)RegMask::SlotsPerLong)); + // Allocated register sets are aligned to their size. Offsets to the stack + // pointer have to be aligned to the size of the access. For this _new_SP is + // aligned to the size of the largest register set with the stack alignment as + // limit and a minimum of SlotsPerLong (2). + int vector_aligment = MIN2(C->max_vector_size(), stack_alignment_in_bytes()) / VMRegImpl::stack_slot_size; + _new_SP = OptoReg::Name(align_up(_in_arg_limit, MAX2((int)RegMask::SlotsPerLong, vector_aligment))); // Compute highest outgoing stack argument as // _new_SP + out_preserve_stack_slots + max(outgoing argument size). diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index c42064b342c..dd34982692d 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1980,10 +1980,12 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, ciKlass* klass) const { assert(!UseCompactObjectHeaders || tkls->offset() != in_bytes(Klass::prototype_header_offset()), "must not happen"); - if (tkls->offset() == in_bytes(Klass::access_flags_offset())) { - // The field is Klass::_access_flags. Return its (constant) value. + + if (tkls->isa_instklassptr() && tkls->offset() == in_bytes(InstanceKlass::access_flags_offset())) { + // The field is InstanceKlass::_access_flags. Return its (constant) value. assert(Opcode() == Op_LoadUS, "must load an unsigned short from _access_flags"); - return TypeInt::make(klass->access_flags()); + ciInstanceKlass* iklass = tkls->is_instklassptr()->instance_klass(); + return TypeInt::make(iklass->access_flags()); } if (tkls->offset() == in_bytes(Klass::misc_flags_offset())) { // The field is Klass::_misc_flags. Return its (constant) value. diff --git a/src/hotspot/share/opto/regmask.hpp b/src/hotspot/share/opto/regmask.hpp index 453fbb45d33..421031fdf61 100644 --- a/src/hotspot/share/opto/regmask.hpp +++ b/src/hotspot/share/opto/regmask.hpp @@ -354,16 +354,12 @@ public: } // SlotsPerLong is 2, since slots are 32 bits and longs are 64 bits. - // Also, consider the maximum alignment size for a normally allocated - // value. Since we allocate register pairs but not register quads (at - // present), this alignment is SlotsPerLong (== 2). A normally - // aligned allocated register is either a single register, or a pair - // of adjacent registers, the lower-numbered being even. - // See also is_aligned_Pairs() below, and the padding added before - // Matcher::_new_SP to keep allocated pairs aligned properly. - // If we ever go to quad-word allocations, SlotsPerQuad will become - // the controlling alignment constraint. Note that this alignment - // requirement is internal to the allocator, and independent of any + // We allocate single registers for 32 bit values and register pairs for 64 + // bit values. The number of registers allocated for vectors match their size. E.g. for 128 bit + // vectors (VecX) we allocate a set of 4 registers. Allocated sets are adjacent and aligned. + // See RegMask::find_first_set(), is_aligned_pairs(), is_aligned_sets(), and the padding added before + // Matcher::_new_SP to keep allocated pairs and sets aligned properly. + // Note that this alignment requirement is internal to the allocator, and independent of any // particular platform. enum { SlotsPerLong = 2, SlotsPerVecA = 4, diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 32acbe57951..6dbbfb0a130 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -66,6 +66,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaCalls.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stackWatermarkSet.hpp" @@ -92,12 +93,9 @@ #define C2_STUB_FIELD_NAME(name) _ ## name ## _Java #define C2_STUB_FIELD_DEFINE(name, f, t, r) \ address OptoRuntime:: C2_STUB_FIELD_NAME(name) = nullptr; -#define C2_JVMTI_STUB_FIELD_DEFINE(name) \ - address OptoRuntime:: STUB_FIELD_NAME(name) = nullptr; -C2_STUBS_DO(C2_BLOB_FIELD_DEFINE, C2_STUB_FIELD_DEFINE, C2_JVMTI_STUB_FIELD_DEFINE) +C2_STUBS_DO(C2_BLOB_FIELD_DEFINE, C2_STUB_FIELD_DEFINE) #undef C2_BLOB_FIELD_DEFINE #undef C2_STUB_FIELD_DEFINE -#undef C2_JVMTI_STUB_FIELD_DEFINE // This should be called in an assertion at the start of OptoRuntime routines // which are entered from compiled code (all of them) @@ -153,23 +151,9 @@ static bool check_compiled_frame(JavaThread* thread) { pass_retpc); \ if (C2_STUB_FIELD_NAME(name) == nullptr) { return false; } \ -#define C2_JVMTI_STUB_C_FUNC(name) CAST_FROM_FN_PTR(address, SharedRuntime::name) - -#define GEN_C2_JVMTI_STUB(name) \ - STUB_FIELD_NAME(name) = \ - generate_stub(env, \ - notify_jvmti_vthread_Type, \ - C2_JVMTI_STUB_C_FUNC(name), \ - C2_STUB_NAME(name), \ - C2_STUB_ID(name), \ - 0, \ - true, \ - false); \ - if (STUB_FIELD_NAME(name) == nullptr) { return false; } \ - bool OptoRuntime::generate(ciEnv* env) { - C2_STUBS_DO(GEN_C2_BLOB, GEN_C2_STUB, GEN_C2_JVMTI_STUB) + C2_STUBS_DO(GEN_C2_BLOB, GEN_C2_STUB) return true; } @@ -182,8 +166,6 @@ bool OptoRuntime::generate(ciEnv* env) { #undef C2_STUB_NAME #undef GEN_C2_STUB -#undef C2_JVMTI_STUB_C_FUNC -#undef GEN_C2_JVMTI_STUB // #undef gen const TypeFunc* OptoRuntime::_new_instance_Type = nullptr; @@ -257,12 +239,10 @@ const TypeFunc* OptoRuntime::_updateBytesCRC32C_Type = nullptr; const TypeFunc* OptoRuntime::_updateBytesAdler32_Type = nullptr; const TypeFunc* OptoRuntime::_osr_end_Type = nullptr; const TypeFunc* OptoRuntime::_register_finalizer_Type = nullptr; +const TypeFunc* OptoRuntime::_vthread_transition_Type = nullptr; #if INCLUDE_JFR const TypeFunc* OptoRuntime::_class_id_load_barrier_Type = nullptr; #endif // INCLUDE_JFR -#if INCLUDE_JVMTI -const TypeFunc* OptoRuntime::_notify_jvmti_vthread_Type = nullptr; -#endif // INCLUDE_JVMTI const TypeFunc* OptoRuntime::_dtrace_method_entry_exit_Type = nullptr; const TypeFunc* OptoRuntime::_dtrace_object_alloc_Type = nullptr; @@ -572,6 +552,26 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::monitor_notifyAll_C(oopDesc* obj, JavaThread* JRT_BLOCK_END; JRT_END +JRT_ENTRY(void, OptoRuntime::vthread_end_first_transition_C(oopDesc* vt, jboolean is_mount, JavaThread* current)) + MountUnmountDisabler::end_transition(current, vt, true /*is_mount*/, true /*is_thread_start*/); +JRT_END + +JRT_ENTRY(void, OptoRuntime::vthread_start_final_transition_C(oopDesc* vt, jboolean is_mount, JavaThread* current)) + java_lang_Thread::set_is_in_vthread_transition(vt, false); + current->set_is_in_vthread_transition(false); + MountUnmountDisabler::start_transition(current, vt, false /*is_mount */, true /*is_thread_end*/); +JRT_END + +JRT_ENTRY(void, OptoRuntime::vthread_start_transition_C(oopDesc* vt, jboolean is_mount, JavaThread* current)) + java_lang_Thread::set_is_in_vthread_transition(vt, false); + current->set_is_in_vthread_transition(false); + MountUnmountDisabler::start_transition(current, vt, is_mount, false /*is_thread_end*/); +JRT_END + +JRT_ENTRY(void, OptoRuntime::vthread_end_transition_C(oopDesc* vt, jboolean is_mount, JavaThread* current)) + MountUnmountDisabler::end_transition(current, vt, is_mount, false /*is_thread_start*/); +JRT_END + static const TypeFunc* make_new_instance_Type() { // create input type (domain) const Type **fields = TypeTuple::fields(1); @@ -587,8 +587,7 @@ static const TypeFunc* make_new_instance_Type() { return TypeFunc::make(domain, range); } -#if INCLUDE_JVMTI -static const TypeFunc* make_notify_jvmti_vthread_Type() { +static const TypeFunc* make_vthread_transition_Type() { // create input type (domain) const Type **fields = TypeTuple::fields(2); fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // VirtualThread oop @@ -602,7 +601,6 @@ static const TypeFunc* make_notify_jvmti_vthread_Type() { return TypeFunc::make(domain,range); } -#endif static const TypeFunc* make_athrow_Type() { // create input type (domain) @@ -2336,12 +2334,10 @@ void OptoRuntime::initialize_types() { _updateBytesAdler32_Type = make_updateBytesAdler32_Type(); _osr_end_Type = make_osr_end_Type(); _register_finalizer_Type = make_register_finalizer_Type(); + _vthread_transition_Type = make_vthread_transition_Type(); JFR_ONLY( _class_id_load_barrier_Type = make_class_id_load_barrier_Type(); ) -#if INCLUDE_JVMTI - _notify_jvmti_vthread_Type = make_notify_jvmti_vthread_Type(); -#endif // INCLUDE_JVMTI _dtrace_method_entry_exit_Type = make_dtrace_method_entry_exit_Type(); _dtrace_object_alloc_Type = make_dtrace_object_alloc_Type(); } diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index eb2b49311cf..b8cdd9a962a 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -115,15 +115,12 @@ class OptoRuntime : public AllStatic { #define C2_STUB_FIELD_NAME(name) _ ## name ## _Java #define C2_STUB_FIELD_DECLARE(name, f, t, r) \ static address C2_STUB_FIELD_NAME(name) ; -#define C2_JVMTI_STUB_FIELD_DECLARE(name) \ - static address STUB_FIELD_NAME(name); - C2_STUBS_DO(C2_BLOB_FIELD_DECLARE, C2_STUB_FIELD_DECLARE, C2_JVMTI_STUB_FIELD_DECLARE) + C2_STUBS_DO(C2_BLOB_FIELD_DECLARE, C2_STUB_FIELD_DECLARE) #undef C2_BLOB_FIELD_DECLARE #undef C2_STUB_FIELD_NAME #undef C2_STUB_FIELD_DECLARE -#undef C2_JVMTI_STUB_FIELD_DECLARE // static TypeFunc* data members static const TypeFunc* _new_instance_Type; @@ -197,12 +194,10 @@ class OptoRuntime : public AllStatic { static const TypeFunc* _updateBytesAdler32_Type; static const TypeFunc* _osr_end_Type; static const TypeFunc* _register_finalizer_Type; + static const TypeFunc* _vthread_transition_Type; #if INCLUDE_JFR static const TypeFunc* _class_id_load_barrier_Type; #endif // INCLUDE_JFR -#if INCLUDE_JVMTI - static const TypeFunc* _notify_jvmti_vthread_Type; -#endif // INCLUDE_JVMTI static const TypeFunc* _dtrace_method_entry_exit_Type; static const TypeFunc* _dtrace_object_alloc_Type; @@ -239,6 +234,11 @@ public: static void monitor_notify_C(oopDesc* obj, JavaThread* current); static void monitor_notifyAll_C(oopDesc* obj, JavaThread* current); + static void vthread_end_first_transition_C(oopDesc* vt, jboolean hide, JavaThread* current); + static void vthread_start_final_transition_C(oopDesc* vt, jboolean hide, JavaThread* current); + static void vthread_start_transition_C(oopDesc* vt, jboolean hide, JavaThread* current); + static void vthread_end_transition_C(oopDesc* vt, jboolean hide, JavaThread* current); + private: // Implicit exception support @@ -293,12 +293,11 @@ private: static address slow_arraycopy_Java() { return _slow_arraycopy_Java; } static address register_finalizer_Java() { return _register_finalizer_Java; } -#if INCLUDE_JVMTI - static address notify_jvmti_vthread_start() { return _notify_jvmti_vthread_start; } - static address notify_jvmti_vthread_end() { return _notify_jvmti_vthread_end; } - static address notify_jvmti_vthread_mount() { return _notify_jvmti_vthread_mount; } - static address notify_jvmti_vthread_unmount() { return _notify_jvmti_vthread_unmount; } -#endif + + static address vthread_end_first_transition_Java() { return _vthread_end_first_transition_Java; } + static address vthread_start_final_transition_Java() { return _vthread_start_final_transition_Java; } + static address vthread_start_transition_Java() { return _vthread_start_transition_Java; } + static address vthread_end_transition_Java() { return _vthread_end_transition_Java; } static UncommonTrapBlob* uncommon_trap_blob() { return _uncommon_trap_blob; } static ExceptionBlob* exception_blob() { return _exception_blob; } @@ -718,6 +717,27 @@ private: return _register_finalizer_Type; } + static inline const TypeFunc* vthread_transition_Type() { + assert(_vthread_transition_Type != nullptr, "should be initialized"); + return _vthread_transition_Type; + } + + static inline const TypeFunc* vthread_end_first_transition_Type() { + return vthread_transition_Type(); + } + + static inline const TypeFunc* vthread_start_final_transition_Type() { + return vthread_transition_Type(); + } + + static inline const TypeFunc* vthread_start_transition_Type() { + return vthread_transition_Type(); + } + + static inline const TypeFunc* vthread_end_transition_Type() { + return vthread_transition_Type(); + } + #if INCLUDE_JFR static inline const TypeFunc* class_id_load_barrier_Type() { assert(_class_id_load_barrier_Type != nullptr, "should be initialized"); @@ -725,13 +745,6 @@ private: } #endif // INCLUDE_JFR -#if INCLUDE_JVMTI - static inline const TypeFunc* notify_jvmti_vthread_Type() { - assert(_notify_jvmti_vthread_Type != nullptr, "should be initialized"); - return _notify_jvmti_vthread_Type; - } -#endif - // Dtrace support. entry and exit probes have the same signature static inline const TypeFunc* dtrace_method_entry_exit_Type() { assert(_dtrace_method_entry_exit_Type != nullptr, "should be initialized"); diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index a49f3d24fd4..57b94205e5e 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -22,6 +22,8 @@ */ #include "memory/allocation.inline.hpp" +#include "opto/c2_globals.hpp" +#include "opto/compile.hpp" #include "opto/connode.hpp" #include "opto/convertnode.hpp" #include "opto/mulnode.hpp" @@ -1145,7 +1147,14 @@ Node* LoadVectorMaskedNode::Ideal(PhaseGVN* phase, bool can_reshape) { if (ty && ty->is_con()) { BasicType mask_bt = Matcher::vector_element_basic_type(in(3)); int load_sz = type2aelembytes(mask_bt) * ty->get_con(); - assert(load_sz <= MaxVectorSize, "Unexpected load size"); + if (load_sz > MaxVectorSize) { + // After loop opts, cast nodes are aggressively removed, if the input is then transformed + // into a constant that is outside the range of the removed cast, we may encounter it here. + // This should be a dead node then. + assert(Compile::current()->post_loop_opts_phase(), "Unexpected load size"); + return phase->C->top(); + } + if (load_sz == MaxVectorSize) { Node* ctr = in(MemNode::Control); Node* mem = in(MemNode::Memory); @@ -1164,7 +1173,14 @@ Node* StoreVectorMaskedNode::Ideal(PhaseGVN* phase, bool can_reshape) { if (ty && ty->is_con()) { BasicType mask_bt = Matcher::vector_element_basic_type(in(4)); int load_sz = type2aelembytes(mask_bt) * ty->get_con(); - assert(load_sz <= MaxVectorSize, "Unexpected store size"); + if (load_sz > MaxVectorSize) { + // After loop opts, cast nodes are aggressively removed, if the input is then transformed + // into a constant that is outside the range of the removed cast, we may encounter it here. + // This should be a dead node then. + assert(Compile::current()->post_loop_opts_phase(), "Unexpected store size"); + return phase->C->top(); + } + if (load_sz == MaxVectorSize) { Node* ctr = in(MemNode::Control); Node* mem = in(MemNode::Memory); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index a868f6337e2..16d9efde410 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -84,6 +84,7 @@ #include "runtime/javaThread.hpp" #include "runtime/jfieldIDWorkaround.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/os.inline.hpp" #include "runtime/osThread.hpp" #include "runtime/perfData.hpp" @@ -3661,68 +3662,24 @@ JVM_LEAF(jint, JVM_FindSignal(const char *name)) return os::get_signal_number(name); JVM_END -JVM_ENTRY(void, JVM_VirtualThreadStart(JNIEnv* env, jobject vthread)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_start(vthread); - } else { - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, false); - } -#endif +JVM_ENTRY(void, JVM_VirtualThreadEndFirstTransition(JNIEnv* env, jobject vthread)) + oop vt = JNIHandles::resolve_external_guard(vthread); + MountUnmountDisabler::end_transition(thread, vt, true /*is_mount*/, true /*is_thread_start*/); JVM_END -JVM_ENTRY(void, JVM_VirtualThreadEnd(JNIEnv* env, jobject vthread)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_end(vthread); - } else { - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, true); - } -#endif +JVM_ENTRY(void, JVM_VirtualThreadStartFinalTransition(JNIEnv* env, jobject vthread)) + oop vt = JNIHandles::resolve_external_guard(vthread); + MountUnmountDisabler::start_transition(thread, vt, false /*is_mount */, true /*is_thread_end*/); JVM_END -// If notifications are disabled then just update the VTMS transition bit and return. -// Otherwise, the bit is updated in the given jvmtiVTMSTransitionDisabler function call. -JVM_ENTRY(void, JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount(vthread, hide); - } else { - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide); - } -#endif +JVM_ENTRY(void, JVM_VirtualThreadStartTransition(JNIEnv* env, jobject vthread, jboolean is_mount)) + oop vt = JNIHandles::resolve_external_guard(vthread); + MountUnmountDisabler::start_transition(thread, vt, is_mount, false /*is_thread_end*/); JVM_END -// If notifications are disabled then just update the VTMS transition bit and return. -// Otherwise, the bit is updated in the given jvmtiVTMSTransitionDisabler function call below. -JVM_ENTRY(void, JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount(vthread, hide); - } else { - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide); - } -#endif +JVM_ENTRY(void, JVM_VirtualThreadEndTransition(JNIEnv* env, jobject vthread, jboolean is_mount)) + oop vt = JNIHandles::resolve_external_guard(vthread); + MountUnmountDisabler::end_transition(thread, vt, is_mount, false /*is_thread_start*/); JVM_END // Notification from VirtualThread about disabling JVMTI Suspend in a sync critical section. @@ -3772,6 +3729,7 @@ JVM_ENTRY(jobject, JVM_TakeVirtualThreadListToUnblock(JNIEnv* env, jclass ignore parkEvent->park(); } JVM_END + /* * Return the current class's class file version. The low order 16 bits of the * returned jint contain the class's major version. The high order 16 bits diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 5642cd9ff8f..e0863c07f4f 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -66,6 +66,7 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/jfieldIDWorkaround.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" @@ -147,7 +148,7 @@ jvmtiError JvmtiEnv::SetThreadLocalStorage(jthread thread, const void* data) { JavaThread* current = JavaThread::current(); JvmtiThreadState* state = nullptr; - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current); JavaThread* java_thread = nullptr; @@ -200,7 +201,7 @@ JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) { VM_ENTRY_BASE(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread) DEBUG_ONLY(VMNativeEntryWrapper __vew;) - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -561,7 +562,7 @@ JvmtiEnv::SetNativeMethodPrefixes(jint prefix_count, char** prefixes) { // size_of_callbacks - pre-checked to be greater than or equal to 0 jvmtiError JvmtiEnv::SetEventCallbacks(const jvmtiEventCallbacks* callbacks, jint size_of_callbacks) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; JvmtiEventController::set_event_callbacks(this, callbacks, size_of_callbacks); return JVMTI_ERROR_NONE; } /* end SetEventCallbacks */ @@ -585,7 +586,7 @@ JvmtiEnv::SetEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event_type, j if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) { record_class_file_load_hook_enabled(); } - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; if (event_thread == nullptr) { // Can be called at Agent_OnLoad() time with event_thread == nullptr @@ -867,7 +868,7 @@ JvmtiEnv::GetJLocationFormat(jvmtiJlocationFormat* format_ptr) { jvmtiError JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) { JavaThread* current_thread = JavaThread::current(); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -939,7 +940,7 @@ JvmtiEnv::SuspendThread(jthread thread) { jvmtiError err; { - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); ThreadsListHandle tlh(current); JavaThread* java_thread = nullptr; oop thread_oop = nullptr; @@ -949,7 +950,7 @@ JvmtiEnv::SuspendThread(jthread thread) { return err; } - // Do not use JvmtiVTMSTransitionDisabler in context of self suspend to avoid deadlocks. + // Do not use MountUnmountDisabler in context of self suspend to avoid deadlocks. if (java_thread != current) { err = suspend_thread(thread_oop, java_thread, /* single_suspend */ true); return err; @@ -974,7 +975,7 @@ JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvm int self_idx = -1; { - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); ThreadsListHandle tlh(current); for (int i = 0; i < request_count; i++) { @@ -1007,7 +1008,7 @@ JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvm } } // Self suspend after all other suspends if necessary. - // Do not use JvmtiVTMSTransitionDisabler in context of self suspend to avoid deadlocks. + // Do not use MountUnmountDisabler in context of self suspend to avoid deadlocks. if (self_tobj() != nullptr) { // there should not be any error for current java_thread results[self_idx] = suspend_thread(self_tobj(), current, /* single_suspend */ true); @@ -1028,7 +1029,7 @@ JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list { ResourceMark rm(current); - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); ThreadsListHandle tlh(current); GrowableArray* elist = new GrowableArray(except_count); @@ -1078,7 +1079,7 @@ JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list } } // Self suspend after all other suspends if necessary. - // Do not use JvmtiVTMSTransitionDisabler in context of self suspend to avoid deadlocks. + // Do not use MountUnmountDisabler in context of self suspend to avoid deadlocks. if (self_tobj() != nullptr) { suspend_thread(self_tobj(), current, /* single_suspend */ false); } @@ -1089,7 +1090,7 @@ JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list // thread - NOT protected by ThreadsListHandle and NOT pre-checked jvmtiError JvmtiEnv::ResumeThread(jthread thread) { - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); JavaThread* current = JavaThread::current(); ThreadsListHandle tlh(current); @@ -1111,7 +1112,7 @@ jvmtiError JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmtiError* results) { oop thread_oop = nullptr; JavaThread* java_thread = nullptr; - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); ThreadsListHandle tlh; for (int i = 0; i < request_count; i++) { @@ -1150,7 +1151,7 @@ JvmtiEnv::ResumeAllVirtualThreads(jint except_count, const jthread* except_list) return err; } ResourceMark rm; - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); GrowableArray* elist = new GrowableArray(except_count); // Collect threads from except_list for which suspended status must be restored (only for VirtualThread case) @@ -1196,7 +1197,7 @@ jvmtiError JvmtiEnv::StopThread(jthread thread, jobject exception) { JavaThread* current_thread = JavaThread::current(); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; oop thread_oop = nullptr; @@ -1234,7 +1235,7 @@ JvmtiEnv::InterruptThread(jthread thread) { JavaThread* current_thread = JavaThread::current(); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -1280,7 +1281,7 @@ JvmtiEnv::GetThreadInfo(jthread thread, jvmtiThreadInfo* info_ptr) { JavaThread* java_thread = nullptr; oop thread_oop = nullptr; - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); // if thread is null the current thread is used @@ -1369,7 +1370,7 @@ JvmtiEnv::GetOwnedMonitorInfo(jthread thread, jint* owned_monitor_count_ptr, job JavaThread* calling_thread = JavaThread::current(); HandleMark hm(calling_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(calling_thread); JavaThread* java_thread = nullptr; @@ -1424,7 +1425,7 @@ JvmtiEnv::GetOwnedMonitorStackDepthInfo(jthread thread, jint* monitor_info_count JavaThread* calling_thread = JavaThread::current(); HandleMark hm(calling_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(calling_thread); JavaThread* java_thread = nullptr; @@ -1707,7 +1708,7 @@ JvmtiEnv::GetThreadListStackTraces(jint thread_count, const jthread* thread_list *stack_info_ptr = op.stack_info(); } } else { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // JVMTI get stack traces at safepoint. VM_GetThreadListStackTraces op(this, thread_count, thread_list, max_frame_count); @@ -1740,7 +1741,7 @@ JvmtiEnv::PopFrame(jthread thread) { if (thread == nullptr) { return JVMTI_ERROR_INVALID_THREAD; } - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -1795,7 +1796,7 @@ JvmtiEnv::GetFrameLocation(jthread thread, jint depth, jmethodID* method_ptr, jl jvmtiError JvmtiEnv::NotifyFramePop(jthread thread, jint depth) { ResourceMark rm; - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); JavaThread* current = JavaThread::current(); ThreadsListHandle tlh(current); @@ -1823,7 +1824,7 @@ JvmtiEnv::NotifyFramePop(jthread thread, jint depth) { jvmtiError JvmtiEnv::ClearAllFramePops(jthread thread) { ResourceMark rm; - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); JavaThread* current = JavaThread::current(); ThreadsListHandle tlh(current); @@ -2084,7 +2085,7 @@ JvmtiEnv::GetLocalObject(jthread thread, jint depth, jint slot, jobject* value_p // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2125,7 +2126,7 @@ JvmtiEnv::GetLocalInstance(jthread thread, jint depth, jobject* value_ptr){ // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2167,7 +2168,7 @@ JvmtiEnv::GetLocalInt(jthread thread, jint depth, jint slot, jint* value_ptr) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2209,7 +2210,7 @@ JvmtiEnv::GetLocalLong(jthread thread, jint depth, jint slot, jlong* value_ptr) // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2251,7 +2252,7 @@ JvmtiEnv::GetLocalFloat(jthread thread, jint depth, jint slot, jfloat* value_ptr // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2293,7 +2294,7 @@ JvmtiEnv::GetLocalDouble(jthread thread, jint depth, jint slot, jdouble* value_p // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2334,7 +2335,7 @@ JvmtiEnv::SetLocalObject(jthread thread, jint depth, jint slot, jobject value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2371,7 +2372,7 @@ JvmtiEnv::SetLocalInt(jthread thread, jint depth, jint slot, jint value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2408,7 +2409,7 @@ JvmtiEnv::SetLocalLong(jthread thread, jint depth, jint slot, jlong value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2445,7 +2446,7 @@ JvmtiEnv::SetLocalFloat(jthread thread, jint depth, jint slot, jfloat value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2482,7 +2483,7 @@ JvmtiEnv::SetLocalDouble(jthread thread, jint depth, jint slot, jdouble value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2574,7 +2575,7 @@ JvmtiEnv::ClearBreakpoint(Method* method, jlocation location) { jvmtiError JvmtiEnv::SetFieldAccessWatch(fieldDescriptor* fdesc_ptr) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // make sure we haven't set this watch before if (fdesc_ptr->is_field_access_watched()) return JVMTI_ERROR_DUPLICATE; fdesc_ptr->set_is_field_access_watched(true); @@ -2587,7 +2588,7 @@ JvmtiEnv::SetFieldAccessWatch(fieldDescriptor* fdesc_ptr) { jvmtiError JvmtiEnv::ClearFieldAccessWatch(fieldDescriptor* fdesc_ptr) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // make sure we have a watch to clear if (!fdesc_ptr->is_field_access_watched()) return JVMTI_ERROR_NOT_FOUND; fdesc_ptr->set_is_field_access_watched(false); @@ -2600,7 +2601,7 @@ JvmtiEnv::ClearFieldAccessWatch(fieldDescriptor* fdesc_ptr) { jvmtiError JvmtiEnv::SetFieldModificationWatch(fieldDescriptor* fdesc_ptr) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // make sure we haven't set this watch before if (fdesc_ptr->is_field_modification_watched()) return JVMTI_ERROR_DUPLICATE; fdesc_ptr->set_is_field_modification_watched(true); @@ -2613,7 +2614,7 @@ JvmtiEnv::SetFieldModificationWatch(fieldDescriptor* fdesc_ptr) { jvmtiError JvmtiEnv::ClearFieldModificationWatch(fieldDescriptor* fdesc_ptr) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // make sure we have a watch to clear if (!fdesc_ptr->is_field_modification_watched()) return JVMTI_ERROR_NOT_FOUND; fdesc_ptr->set_is_field_modification_watched(false); diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 2b17eddbe94..4894a4dd21a 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -51,6 +51,7 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/jfieldIDWorkaround.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/osThread.hpp" #include "runtime/signature.hpp" @@ -697,7 +698,7 @@ JvmtiEnvBase::check_and_skip_hidden_frames(bool is_in_VTMS_transition, javaVFram javaVFrame* JvmtiEnvBase::check_and_skip_hidden_frames(JavaThread* jt, javaVFrame* jvf) { - jvf = check_and_skip_hidden_frames(jt->is_in_VTMS_transition(), jvf); + jvf = check_and_skip_hidden_frames(jt->is_in_vthread_transition(), jvf); return jvf; } @@ -719,7 +720,7 @@ JvmtiEnvBase::get_vthread_jvf(oop vthread) { return nullptr; } vframeStream vfs(java_thread); - assert(!java_thread->is_in_VTMS_transition(), "invariant"); + assert(!java_thread->is_in_vthread_transition(), "invariant"); jvf = vfs.at_end() ? nullptr : vfs.asJavaVFrame(); jvf = check_and_skip_hidden_frames(false, jvf); } else { @@ -1693,8 +1694,7 @@ private: // jt->jvmti_vthread() for VTMS transition protocol. void correct_jvmti_thread_states() { for (JavaThread* jt : ThreadsListHandle()) { - if (jt->is_in_VTMS_transition()) { - jt->set_VTMS_transition_mark(true); + if (jt->is_in_vthread_transition()) { continue; // no need in JvmtiThreadState correction below if in transition } correct_jvmti_thread_state(jt); @@ -1711,7 +1711,7 @@ public: if (_enable) { correct_jvmti_thread_states(); } - JvmtiVTMSTransitionDisabler::set_VTMS_notify_jvmti_events(_enable); + MountUnmountDisabler::set_notify_jvmti_events(_enable); } }; @@ -1722,7 +1722,7 @@ JvmtiEnvBase::enable_virtual_threads_notify_jvmti() { if (!Continuations::enabled()) { return false; } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { + if (MountUnmountDisabler::notify_jvmti_events()) { return false; // already enabled } VM_SetNotifyJvmtiEventsMode op(true); @@ -1738,10 +1738,10 @@ JvmtiEnvBase::disable_virtual_threads_notify_jvmti() { if (!Continuations::enabled()) { return false; } - if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { + if (!MountUnmountDisabler::notify_jvmti_events()) { return false; // already disabled } - JvmtiVTMSTransitionDisabler disabler(true); // ensure there are no other disablers + MountUnmountDisabler disabler(true); // ensure there are no other disablers VM_SetNotifyJvmtiEventsMode op(false); VMThread::execute(&op); return true; @@ -1769,7 +1769,6 @@ JvmtiEnvBase::suspend_thread(oop thread_oop, JavaThread* java_thread, bool singl // Platform thread or mounted vthread cases. assert(java_thread != nullptr, "sanity check"); - assert(!java_thread->is_in_VTMS_transition(), "sanity check"); // Don't allow hidden thread suspend request. if (java_thread->is_hidden_from_external_view()) { @@ -1828,7 +1827,6 @@ JvmtiEnvBase::resume_thread(oop thread_oop, JavaThread* java_thread, bool single // Platform thread or mounted vthread cases. assert(java_thread != nullptr, "sanity check"); - assert(!java_thread->is_in_VTMS_transition(), "sanity check"); // Don't allow hidden thread resume request. if (java_thread->is_hidden_from_external_view()) { @@ -2008,12 +2006,12 @@ class AdapterClosure : public HandshakeClosure { }; // Supports platform and virtual threads. -// JvmtiVTMSTransitionDisabler is always set by this function. +// MountUnmountDisabler is always set by this function. void JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, jthread target) { JavaThread* current = JavaThread::current(); HandleMark hm(current); - JvmtiVTMSTransitionDisabler disabler(target); + MountUnmountDisabler disabler(target); ThreadsListHandle tlh(current); JavaThread* java_thread = nullptr; oop thread_obj = nullptr; @@ -2030,7 +2028,7 @@ JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, jthread target) { // Supports platform and virtual threads. // A virtual thread is always identified by the target_h oop handle. // The target_jt is always nullptr for an unmounted virtual thread. -// JvmtiVTMSTransitionDisabler has to be set before call to this function. +// MountUnmountDisabler has to be set before call to this function. void JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, ThreadsListHandle* tlh, JavaThread* target_jt, Handle target_h) { @@ -2038,7 +2036,7 @@ JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, ThreadsListHandle* t bool is_virtual = java_lang_VirtualThread::is_instance(target_h()); bool self = target_jt == current; - assert(!Continuations::enabled() || self || !is_virtual || current->is_VTMS_transition_disabler(), "sanity check"); + assert(!Continuations::enabled() || self || !is_virtual || current->is_vthread_transition_disabler(), "sanity check"); hs_cl->set_target_jt(target_jt); // can be needed in the virtual thread case hs_cl->set_is_virtual(is_virtual); // can be needed in the virtual thread case @@ -2211,7 +2209,7 @@ JvmtiEnvBase::force_early_return(jthread thread, jvalue value, TosState tos) { JavaThread* current_thread = JavaThread::current(); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2612,7 +2610,7 @@ PrintStackTraceClosure::do_thread_impl(Thread *target) { "is_VTMS_transition_disabler: %d, is_in_VTMS_transition = %d\n", tname, java_thread->name(), java_thread->is_exiting(), java_thread->is_suspended(), java_thread->is_carrier_thread_suspended(), is_vt_suspended, - java_thread->is_VTMS_transition_disabler(), java_thread->is_in_VTMS_transition()); + java_thread->is_vthread_transition_disabler(), java_thread->is_in_vthread_transition()); if (java_thread->has_last_Java_frame()) { RegisterMap reg_map(java_thread, diff --git a/src/hotspot/share/prims/jvmtiEventController.cpp b/src/hotspot/share/prims/jvmtiEventController.cpp index 169ccbe035f..9df3bbb4b3e 100644 --- a/src/hotspot/share/prims/jvmtiEventController.cpp +++ b/src/hotspot/share/prims/jvmtiEventController.cpp @@ -1077,10 +1077,6 @@ JvmtiEventController::is_global_event(jvmtiEvent event_type) { void JvmtiEventController::set_user_enabled(JvmtiEnvBase *env, JavaThread *thread, oop thread_oop, jvmtiEvent event_type, bool enabled) { - if (event_type == JVMTI_EVENT_OBJECT_FREE) { - JvmtiEventControllerPrivate::flush_object_free_events(env); - } - if (Threads::number_of_threads() == 0) { // during early VM start-up locks don't exist, but we are safely single threaded, // call the functionality without holding the JvmtiThreadState_lock. @@ -1089,6 +1085,11 @@ JvmtiEventController::set_user_enabled(JvmtiEnvBase *env, JavaThread *thread, oo Thread* current = Thread::current(); HandleMark hmi(current); Handle thread_oop_h = Handle(current, thread_oop); + + if (event_type == JVMTI_EVENT_OBJECT_FREE) { + JvmtiEventControllerPrivate::flush_object_free_events(env); + } + MutexLocker mu(JvmtiThreadState_lock); JvmtiEventControllerPrivate::set_user_enabled(env, thread, thread_oop_h, event_type, enabled); } @@ -1238,4 +1239,4 @@ JvmtiEventController::vm_death() { break; } } -} \ No newline at end of file +} diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 69d1fa2c974..02f39460ff6 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -61,6 +61,7 @@ #include "runtime/javaThread.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/keepStackGCProcessed.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" @@ -412,7 +413,7 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { if (Continuations::enabled()) { // Virtual threads support for agents loaded into running VM. // There is a performance impact when VTMS transitions are enabled. - if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { + if (!MountUnmountDisabler::notify_jvmti_events()) { JvmtiEnvBase::enable_virtual_threads_notify_jvmti(); } } @@ -426,7 +427,7 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { if (Continuations::enabled()) { // Virtual threads support for agents loaded at startup. // There is a performance impact when VTMS transitions are enabled. - JvmtiVTMSTransitionDisabler::set_VTMS_notify_jvmti_events(true); + MountUnmountDisabler::set_notify_jvmti_events(true, true /*is_onload*/); } return JNI_OK; @@ -1639,7 +1640,7 @@ void JvmtiExport::post_vthread_end(jobject vthread) { JVMTI_JAVA_THREAD_EVENT_CALLBACK_BLOCK(thread) jvmtiEventVirtualThreadEnd callback = env->callbacks()->VirtualThreadEnd; if (callback != nullptr) { - (*callback)(env->jvmti_external(), jem.jni_env(), vthread); + (*callback)(env->jvmti_external(), jem.jni_env(), jem.jni_thread()); } } } @@ -2924,13 +2925,13 @@ void JvmtiExport::vthread_post_monitor_waited(JavaThread *current, ObjectMonitor Handle vthread(current, current->vthread()); // Finish the VTMS transition temporarily to post the event. - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount((jthread)vthread.raw_value(), false); + MountUnmountDisabler::end_transition(current, vthread(), true /*is_mount*/, false /*is_thread_start*/); // Post event. JvmtiExport::post_monitor_waited(current, obj_mntr, timed_out); // Go back to VTMS transition state. - JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount((jthread)vthread.raw_value(), true); + MountUnmountDisabler::start_transition(current, vthread(), false /*is_mount*/, false /*is_thread_start*/); } void JvmtiExport::post_vm_object_alloc(JavaThread *thread, oop object) { @@ -3159,31 +3160,19 @@ void JvmtiObjectAllocEventCollector::record_allocation(oop obj) { _allocated->push(OopHandle(JvmtiExport::jvmti_oop_storage(), obj)); } -// Disable collection of VMObjectAlloc events -NoJvmtiVMObjectAllocMark::NoJvmtiVMObjectAllocMark() : _collector(nullptr) { - // a no-op if VMObjectAlloc event is not enabled - if (!JvmtiExport::should_post_vm_object_alloc()) { - return; - } +NoJvmtiEventsMark::NoJvmtiEventsMark() { Thread* thread = Thread::current_or_null(); if (thread != nullptr && thread->is_Java_thread()) { JavaThread* current_thread = JavaThread::cast(thread); - JvmtiThreadState *state = current_thread->jvmti_thread_state(); - if (state != nullptr) { - JvmtiVMObjectAllocEventCollector *collector; - collector = state->get_vm_object_alloc_event_collector(); - if (collector != nullptr && collector->is_enabled()) { - _collector = collector; - _collector->set_enabled(false); - } - } + current_thread->disable_jvmti_events(); } } -// Re-Enable collection of VMObjectAlloc events (if previously enabled) -NoJvmtiVMObjectAllocMark::~NoJvmtiVMObjectAllocMark() { - if (was_enabled()) { - _collector->set_enabled(true); +NoJvmtiEventsMark::~NoJvmtiEventsMark() { + Thread* thread = Thread::current_or_null(); + if (thread != nullptr && thread->is_Java_thread()) { + JavaThread* current_thread = JavaThread::cast(thread); + current_thread->enable_jvmti_events(); } }; diff --git a/src/hotspot/share/prims/jvmtiExport.hpp b/src/hotspot/share/prims/jvmtiExport.hpp index 66f5413c8f6..f6c9f3a74d5 100644 --- a/src/hotspot/share/prims/jvmtiExport.hpp +++ b/src/hotspot/share/prims/jvmtiExport.hpp @@ -585,29 +585,12 @@ class JvmtiSampledObjectAllocEventCollector : public JvmtiObjectAllocEventCollec static bool object_alloc_is_safe_to_sample() NOT_JVMTI_RETURN_(false); }; -// Marker class to disable the posting of VMObjectAlloc events -// within its scope. -// -// Usage :- -// -// { -// NoJvmtiVMObjectAllocMark njm; -// : -// // VMObjAlloc event will not be posted -// JvmtiExport::vm_object_alloc_event_collector(obj); -// : -// } - -class NoJvmtiVMObjectAllocMark : public StackObj { - private: - // enclosing collector if enabled, null otherwise - JvmtiVMObjectAllocEventCollector *_collector; - - bool was_enabled() { return _collector != nullptr; } +// Marker class to temporary disable posting of jvmti events. +class NoJvmtiEventsMark : public StackObj { public: - NoJvmtiVMObjectAllocMark() NOT_JVMTI_RETURN; - ~NoJvmtiVMObjectAllocMark() NOT_JVMTI_RETURN; + NoJvmtiEventsMark() NOT_JVMTI_RETURN; + ~NoJvmtiEventsMark() NOT_JVMTI_RETURN; }; diff --git a/src/hotspot/share/prims/jvmtiExtensions.cpp b/src/hotspot/share/prims/jvmtiExtensions.cpp index 603d62eff85..855c7bd4eba 100644 --- a/src/hotspot/share/prims/jvmtiExtensions.cpp +++ b/src/hotspot/share/prims/jvmtiExtensions.cpp @@ -29,6 +29,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" // the list of extension functions GrowableArray* JvmtiExtensions::_ext_functions; @@ -77,7 +78,7 @@ static jvmtiError JNICALL GetVirtualThread(const jvmtiEnv* env, ...) { va_end(ap); ThreadInVMfromNative tiv(current_thread); - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; ThreadsListHandle tlh(current_thread); jvmtiError err; @@ -135,7 +136,7 @@ static jvmtiError JNICALL GetCarrierThread(const jvmtiEnv* env, ...) { MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current_thread)); ThreadInVMfromNative tiv(current_thread); - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; ThreadsListHandle tlh(current_thread); JavaThread* java_thread; diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index c923f91f69d..90a3461f321 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -57,6 +57,7 @@ #include "runtime/javaCalls.hpp" #include "runtime/javaThread.inline.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/mutex.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" @@ -3028,7 +3029,7 @@ void JvmtiTagMap::iterate_over_reachable_objects(jvmtiHeapRootCallback heap_root jvmtiObjectReferenceCallback object_ref_callback, const void* user_data) { // VTMS transitions must be disabled before the EscapeBarrier. - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; JavaThread* jt = JavaThread::current(); EscapeBarrier eb(true, jt); @@ -3056,7 +3057,7 @@ void JvmtiTagMap::iterate_over_objects_reachable_from_object(jobject object, Arena dead_object_arena(mtServiceability); GrowableArray dead_objects(&dead_object_arena, 10, 0, 0); - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; { MutexLocker ml(Heap_lock); @@ -3076,7 +3077,7 @@ void JvmtiTagMap::follow_references(jint heap_filter, const void* user_data) { // VTMS transitions must be disabled before the EscapeBarrier. - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; oop obj = JNIHandles::resolve(object); JavaThread* jt = JavaThread::current(); diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp index 00a48dec111..fc965e568f7 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiThreadState.cpp @@ -209,479 +209,6 @@ JvmtiThreadState::periodic_clean_up() { } } -// -// Virtual Threads Mount State transition (VTMS transition) mechanism -// - -// VTMS transitions for one virtual thread are disabled while it is positive -volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_one_count = 0; - -// VTMS transitions for all virtual threads are disabled while it is positive -volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_all_count = 0; - -// There is an active suspender or resumer. -volatile bool JvmtiVTMSTransitionDisabler::_SR_mode = false; - -// Notifications from VirtualThread about VTMS events are enabled. -bool JvmtiVTMSTransitionDisabler::_VTMS_notify_jvmti_events = false; - -// The JvmtiVTMSTransitionDisabler sync protocol is enabled if this count > 0. -volatile int JvmtiVTMSTransitionDisabler::_sync_protocol_enabled_count = 0; - -// JvmtiVTMSTraansitionDisabler sync protocol is enabled permanently after seeing a suspender. -volatile bool JvmtiVTMSTransitionDisabler::_sync_protocol_enabled_permanently = false; - -#ifdef ASSERT -void -JvmtiVTMSTransitionDisabler::print_info() { - log_error(jvmti)("_VTMS_transition_disable_for_one_count: %d\n", _VTMS_transition_disable_for_one_count); - log_error(jvmti)("_VTMS_transition_disable_for_all_count: %d\n\n", _VTMS_transition_disable_for_all_count); - int attempts = 10000; - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *java_thread = jtiwh.next(); ) { - if (java_thread->VTMS_transition_mark()) { - log_error(jvmti)("jt: %p VTMS_transition_mark: %d\n", - (void*)java_thread, java_thread->VTMS_transition_mark()); - } - ResourceMark rm; - // Handshake with target. - PrintStackTraceClosure pstc; - Handshake::execute(&pstc, java_thread); - } -} -#endif - -// disable VTMS transitions for one virtual thread -// disable VTMS transitions for all threads if thread is nullptr or a platform thread -JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(jthread thread) - : _is_SR(false), - _is_virtual(false), - _is_self(false), - _thread(thread) -{ - if (!Continuations::enabled()) { - return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads - } - if (Thread::current_or_null() == nullptr) { - return; // Detached thread, can be a call from Agent_OnLoad. - } - JavaThread* current = JavaThread::current(); - oop thread_oop = JNIHandles::resolve_external_guard(thread); - _is_virtual = java_lang_VirtualThread::is_instance(thread_oop); - - if (thread == nullptr || - (!_is_virtual && thread_oop == current->threadObj()) || - (_is_virtual && thread_oop == current->vthread())) { - _is_self = true; - return; // no need for current thread to disable and enable transitions for itself - } - if (!sync_protocol_enabled_permanently()) { - JvmtiVTMSTransitionDisabler::inc_sync_protocol_enabled_count(); - } - - // Target can be virtual or platform thread. - // If target is a platform thread then we have to disable VTMS transitions for all threads. - // It is by several reasons: - // - carrier threads can mount virtual threads which may cause incorrect behavior - // - there is no mechanism to disable transitions for a specific carrier thread yet - if (_is_virtual) { - VTMS_transition_disable_for_one(); // disable VTMS transitions for one virtual thread - } else { - VTMS_transition_disable_for_all(); // disable VTMS transitions for all virtual threads - } -} - -// disable VTMS transitions for all virtual threads -JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(bool is_SR) - : _is_SR(is_SR), - _is_virtual(false), - _is_self(false), - _thread(nullptr) -{ - if (!Continuations::enabled()) { - return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads - } - if (Thread::current_or_null() == nullptr) { - return; // Detached thread, can be a call from Agent_OnLoad. - } - if (!sync_protocol_enabled_permanently()) { - JvmtiVTMSTransitionDisabler::inc_sync_protocol_enabled_count(); - if (is_SR) { - AtomicAccess::store(&_sync_protocol_enabled_permanently, true); - } - } - VTMS_transition_disable_for_all(); -} - -JvmtiVTMSTransitionDisabler::~JvmtiVTMSTransitionDisabler() { - if (!Continuations::enabled()) { - return; // JvmtiVTMSTransitionDisabler is a no-op without virtual threads - } - if (Thread::current_or_null() == nullptr) { - return; // Detached thread, can be a call from Agent_OnLoad. - } - if (_is_self) { - return; // no need for current thread to disable and enable transitions for itself - } - if (_is_virtual) { - VTMS_transition_enable_for_one(); // enable VTMS transitions for one virtual thread - } else { - VTMS_transition_enable_for_all(); // enable VTMS transitions for all virtual threads - } - if (!sync_protocol_enabled_permanently()) { - JvmtiVTMSTransitionDisabler::dec_sync_protocol_enabled_count(); - } -} - -// disable VTMS transitions for one virtual thread -void -JvmtiVTMSTransitionDisabler::VTMS_transition_disable_for_one() { - assert(_thread != nullptr, "sanity check"); - JavaThread* thread = JavaThread::current(); - HandleMark hm(thread); - Handle vth = Handle(thread, JNIHandles::resolve_external_guard(_thread)); - assert(java_lang_VirtualThread::is_instance(vth()), "sanity check"); - - MonitorLocker ml(JvmtiVTMSTransition_lock); - - while (_SR_mode) { // suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist - ml.wait(10); // wait while there is an active suspender or resumer - } - AtomicAccess::inc(&_VTMS_transition_disable_for_one_count); - java_lang_Thread::inc_VTMS_transition_disable_count(vth()); - - while (java_lang_Thread::is_in_VTMS_transition(vth())) { - ml.wait(10); // wait while the virtual thread is in transition - } -#ifdef ASSERT - thread->set_is_VTMS_transition_disabler(true); -#endif -} - -// disable VTMS transitions for all virtual threads -void -JvmtiVTMSTransitionDisabler::VTMS_transition_disable_for_all() { - JavaThread* thread = JavaThread::current(); - int attempts = 50000; - { - MonitorLocker ml(JvmtiVTMSTransition_lock); - - assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check"); - while (_SR_mode) { // Suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist. - ml.wait(10); // Wait while there is an active suspender or resumer. - } - if (_is_SR) { - _SR_mode = true; - while (_VTMS_transition_disable_for_all_count > 0 || - _VTMS_transition_disable_for_one_count > 0) { - ml.wait(10); // Wait while there is any active jvmtiVTMSTransitionDisabler. - } - } - AtomicAccess::inc(&_VTMS_transition_disable_for_all_count); - - // Block while some mount/unmount transitions are in progress. - // Debug version fails and prints diagnostic information. - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { - while (jt->VTMS_transition_mark()) { - if (ml.wait(10)) { - attempts--; - } - DEBUG_ONLY(if (attempts == 0) break;) - } - } - assert(!thread->is_VTMS_transition_disabler(), "VTMS_transition sanity check"); -#ifdef ASSERT - if (attempts > 0) { - thread->set_is_VTMS_transition_disabler(true); - } -#endif - } -#ifdef ASSERT - if (attempts == 0) { - print_info(); - fatal("stuck in JvmtiVTMSTransitionDisabler::VTMS_transition_disable"); - } -#endif -} - -// enable VTMS transitions for one virtual thread -void -JvmtiVTMSTransitionDisabler::VTMS_transition_enable_for_one() { - JavaThread* thread = JavaThread::current(); - HandleMark hm(thread); - Handle vth = Handle(thread, JNIHandles::resolve_external_guard(_thread)); - if (!java_lang_VirtualThread::is_instance(vth())) { - return; // no-op if _thread is not a virtual thread - } - MonitorLocker ml(JvmtiVTMSTransition_lock); - java_lang_Thread::dec_VTMS_transition_disable_count(vth()); - AtomicAccess::dec(&_VTMS_transition_disable_for_one_count); - if (_VTMS_transition_disable_for_one_count == 0) { - ml.notify_all(); - } -#ifdef ASSERT - thread->set_is_VTMS_transition_disabler(false); -#endif -} - -// enable VTMS transitions for all virtual threads -void -JvmtiVTMSTransitionDisabler::VTMS_transition_enable_for_all() { - JavaThread* current = JavaThread::current(); - { - MonitorLocker ml(JvmtiVTMSTransition_lock); - assert(_VTMS_transition_disable_for_all_count > 0, "VTMS_transition sanity check"); - - if (_is_SR) { // Disabler is suspender or resumer. - _SR_mode = false; - } - AtomicAccess::dec(&_VTMS_transition_disable_for_all_count); - if (_VTMS_transition_disable_for_all_count == 0 || _is_SR) { - ml.notify_all(); - } -#ifdef ASSERT - current->set_is_VTMS_transition_disabler(false); -#endif - } -} - -void -JvmtiVTMSTransitionDisabler::start_VTMS_transition(jthread vthread, bool is_mount) { - JavaThread* thread = JavaThread::current(); - oop vt = JNIHandles::resolve_external_guard(vthread); - assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check"); - - // Avoid using MonitorLocker on performance critical path, use - // two-level synchronization with lock-free operations on state bits. - assert(!thread->VTMS_transition_mark(), "sanity check"); - thread->set_VTMS_transition_mark(true); // Try to enter VTMS transition section optmistically. - java_lang_Thread::set_is_in_VTMS_transition(vt, true); - - if (!sync_protocol_enabled()) { - thread->set_is_in_VTMS_transition(true); - return; - } - HandleMark hm(thread); - Handle vth = Handle(thread, vt); - int attempts = 50000; - - // Do not allow suspends inside VTMS transitions. - // Block while transitions are disabled or there are suspend requests. - int64_t thread_id = java_lang_Thread::thread_id(vth()); // Cannot use oops while blocked. - - if (_VTMS_transition_disable_for_all_count > 0 || - java_lang_Thread::VTMS_transition_disable_count(vth()) > 0 || - thread->is_suspended() || - JvmtiVTSuspender::is_vthread_suspended(thread_id) - ) { - // Slow path: undo unsuccessful optimistic set of the VTMS_transition_mark. - // It can cause an extra waiting cycle for VTMS transition disablers. - thread->set_VTMS_transition_mark(false); - java_lang_Thread::set_is_in_VTMS_transition(vth(), false); - - while (true) { - MonitorLocker ml(JvmtiVTMSTransition_lock); - - // Do not allow suspends inside VTMS transitions. - // Block while transitions are disabled or there are suspend requests. - if (_VTMS_transition_disable_for_all_count > 0 || - java_lang_Thread::VTMS_transition_disable_count(vth()) > 0 || - thread->is_suspended() || - JvmtiVTSuspender::is_vthread_suspended(thread_id) - ) { - // Block while transitions are disabled or there are suspend requests. - if (ml.wait(200)) { - attempts--; - } - DEBUG_ONLY(if (attempts == 0) break;) - continue; // ~ThreadBlockInVM has handshake-based suspend point. - } - thread->set_VTMS_transition_mark(true); - java_lang_Thread::set_is_in_VTMS_transition(vth(), true); - break; - } - } -#ifdef ASSERT - if (attempts == 0) { - log_error(jvmti)("start_VTMS_transition: thread->is_suspended: %d is_vthread_suspended: %d\n\n", - thread->is_suspended(), JvmtiVTSuspender::is_vthread_suspended(thread_id)); - print_info(); - fatal("stuck in JvmtiVTMSTransitionDisabler::start_VTMS_transition"); - } -#endif - // Enter VTMS transition section. - thread->set_is_in_VTMS_transition(true); -} - -void -JvmtiVTMSTransitionDisabler::finish_VTMS_transition(jthread vthread, bool is_mount) { - JavaThread* thread = JavaThread::current(); - - assert(thread->is_in_VTMS_transition(), "sanity check"); - thread->set_is_in_VTMS_transition(false); - oop vt = JNIHandles::resolve_external_guard(vthread); - java_lang_Thread::set_is_in_VTMS_transition(vt, false); - assert(thread->VTMS_transition_mark(), "sanity check"); - thread->set_VTMS_transition_mark(false); - - if (!sync_protocol_enabled()) { - return; - } - int64_t thread_id = java_lang_Thread::thread_id(vt); - - // Unblock waiting VTMS transition disablers. - if (_VTMS_transition_disable_for_one_count > 0 || - _VTMS_transition_disable_for_all_count > 0) { - MonitorLocker ml(JvmtiVTMSTransition_lock); - ml.notify_all(); - } - // In unmount case the carrier thread is attached after unmount transition. - // Check and block it if there was external suspend request. - int attempts = 10000; - if (!is_mount && thread->is_carrier_thread_suspended()) { - while (true) { - MonitorLocker ml(JvmtiVTMSTransition_lock); - - // Block while there are suspend requests. - if ((!is_mount && thread->is_carrier_thread_suspended()) || - (is_mount && JvmtiVTSuspender::is_vthread_suspended(thread_id)) - ) { - // Block while there are suspend requests. - if (ml.wait(200)) { - attempts--; - } - DEBUG_ONLY(if (attempts == 0) break;) - continue; - } - break; - } - } -#ifdef ASSERT - if (attempts == 0) { - log_error(jvmti)("finish_VTMS_transition: thread->is_suspended: %d is_vthread_suspended: %d\n\n", - thread->is_suspended(), JvmtiVTSuspender::is_vthread_suspended(thread_id)); - print_info(); - fatal("stuck in JvmtiVTMSTransitionDisabler::finish_VTMS_transition"); - } -#endif -} - -// set VTMS transition bit value in JavaThread and java.lang.VirtualThread object -void JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(JavaThread* thread, jobject vthread, bool in_trans) { - oop vt = JNIHandles::resolve_external_guard(vthread); - java_lang_Thread::set_is_in_VTMS_transition(vt, in_trans); - thread->set_is_in_VTMS_transition(in_trans); -} - -void -JvmtiVTMSTransitionDisabler::VTMS_vthread_start(jobject vthread) { - VTMS_mount_end(vthread); - JavaThread* thread = JavaThread::current(); - - assert(!thread->is_in_VTMS_transition(), "sanity check"); - - // If interp_only_mode has been enabled then we must eagerly create JvmtiThreadState - // objects for globally enabled virtual thread filtered events. Otherwise, - // it is an important optimization to create JvmtiThreadState objects lazily. - // This optimization is disabled when watchpoint capabilities are present. It is to - // work around a bug with virtual thread frames which can be not deoptimized in time. - if (JvmtiThreadState::seen_interp_only_mode() || - JvmtiExport::should_post_field_access() || - JvmtiExport::should_post_field_modification()){ - JvmtiEventController::thread_started(thread); - } - if (JvmtiExport::should_post_vthread_start()) { - JvmtiExport::post_vthread_start(vthread); - } - // post VirtualThreadMount event after VirtualThreadStart - if (JvmtiExport::should_post_vthread_mount()) { - JvmtiExport::post_vthread_mount(vthread); - } -} - -void -JvmtiVTMSTransitionDisabler::VTMS_vthread_end(jobject vthread) { - JavaThread* thread = JavaThread::current(); - - assert(!thread->is_in_VTMS_transition(), "sanity check"); - - // post VirtualThreadUnmount event before VirtualThreadEnd - if (JvmtiExport::should_post_vthread_unmount()) { - JvmtiExport::post_vthread_unmount(vthread); - } - if (JvmtiExport::should_post_vthread_end()) { - JvmtiExport::post_vthread_end(vthread); - } - VTMS_unmount_begin(vthread, /* last_unmount */ true); - if (thread->jvmti_thread_state() != nullptr) { - JvmtiExport::cleanup_thread(thread); - assert(thread->jvmti_thread_state() == nullptr, "should be null"); - assert(java_lang_Thread::jvmti_thread_state(JNIHandles::resolve(vthread)) == nullptr, "should be null"); - } - thread->rebind_to_jvmti_thread_state_of(thread->threadObj()); -} - -void -JvmtiVTMSTransitionDisabler::VTMS_vthread_mount(jobject vthread, bool hide) { - if (hide) { - VTMS_mount_begin(vthread); - } else { - VTMS_mount_end(vthread); - if (JvmtiExport::should_post_vthread_mount()) { - JvmtiExport::post_vthread_mount(vthread); - } - } -} - -void -JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount(jobject vthread, bool hide) { - if (hide) { - if (JvmtiExport::should_post_vthread_unmount()) { - JvmtiExport::post_vthread_unmount(vthread); - } - VTMS_unmount_begin(vthread, /* last_unmount */ false); - } else { - VTMS_unmount_end(vthread); - } -} - -void -JvmtiVTMSTransitionDisabler::VTMS_mount_begin(jobject vthread) { - JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_VTMS_transition(), "sanity check"); - start_VTMS_transition(vthread, /* is_mount */ true); -} - -void -JvmtiVTMSTransitionDisabler::VTMS_mount_end(jobject vthread) { - JavaThread* thread = JavaThread::current(); - oop vt = JNIHandles::resolve(vthread); - - thread->rebind_to_jvmti_thread_state_of(vt); - - assert(thread->is_in_VTMS_transition(), "sanity check"); - finish_VTMS_transition(vthread, /* is_mount */ true); -} - -void -JvmtiVTMSTransitionDisabler::VTMS_unmount_begin(jobject vthread, bool last_unmount) { - JavaThread* thread = JavaThread::current(); - - assert(!thread->is_in_VTMS_transition(), "sanity check"); - - start_VTMS_transition(vthread, /* is_mount */ false); - if (!last_unmount) { - thread->rebind_to_jvmti_thread_state_of(thread->threadObj()); - } -} - -void -JvmtiVTMSTransitionDisabler::VTMS_unmount_end(jobject vthread) { - JavaThread* thread = JavaThread::current(); - assert(thread->is_in_VTMS_transition(), "sanity check"); - finish_VTMS_transition(vthread, /* is_mount */ false); -} - - // // Virtual Threads Suspend/Resume management // diff --git a/src/hotspot/share/prims/jvmtiThreadState.hpp b/src/hotspot/share/prims/jvmtiThreadState.hpp index 17bdae4662e..43b568cf1fc 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.hpp @@ -72,67 +72,6 @@ class JvmtiEnvThreadStateIterator : public StackObj { JvmtiEnvThreadState* next(JvmtiEnvThreadState* ets); }; -/////////////////////////////////////////////////////////////// -// -// class JvmtiVTMSTransitionDisabler -// -// Virtual Thread Mount State Transition (VTMS transition) mechanism -// -class JvmtiVTMSTransitionDisabler : public AnyObj { - private: - static volatile int _VTMS_transition_disable_for_one_count; // transitions for one virtual thread are disabled while it is positive - static volatile int _VTMS_transition_disable_for_all_count; // transitions for all virtual threads are disabled while it is positive - static volatile bool _SR_mode; // there is an active suspender or resumer - static volatile int _sync_protocol_enabled_count; // current number of JvmtiVTMSTransitionDisablers enabled sync protocol - static volatile bool _sync_protocol_enabled_permanently; // seen a suspender: JvmtiVTMSTransitionDisabler protocol is enabled permanently - - bool _is_SR; // is suspender or resumer - bool _is_virtual; // target thread is virtual - bool _is_self; // JvmtiVTMSTransitionDisabler is a no-op for current platform, carrier or virtual thread - jthread _thread; // virtual thread to disable transitions for, no-op if it is a platform thread - - DEBUG_ONLY(static void print_info();) - void VTMS_transition_disable_for_one(); - void VTMS_transition_disable_for_all(); - void VTMS_transition_enable_for_one(); - void VTMS_transition_enable_for_all(); - - public: - static bool _VTMS_notify_jvmti_events; // enable notifications from VirtualThread about VTMS events - static bool VTMS_notify_jvmti_events() { return _VTMS_notify_jvmti_events; } - static void set_VTMS_notify_jvmti_events(bool val) { _VTMS_notify_jvmti_events = val; } - - static void inc_sync_protocol_enabled_count() { AtomicAccess::inc(&_sync_protocol_enabled_count); } - static void dec_sync_protocol_enabled_count() { AtomicAccess::dec(&_sync_protocol_enabled_count); } - static int sync_protocol_enabled_count() { return AtomicAccess::load(&_sync_protocol_enabled_count); } - static bool sync_protocol_enabled_permanently() { return AtomicAccess::load(&_sync_protocol_enabled_permanently); } - - static bool sync_protocol_enabled() { return sync_protocol_enabled_permanently() || sync_protocol_enabled_count() > 0; } - - // parameter is_SR: suspender or resumer - JvmtiVTMSTransitionDisabler(bool is_SR = false); - JvmtiVTMSTransitionDisabler(jthread thread); - ~JvmtiVTMSTransitionDisabler(); - - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - static void set_is_in_VTMS_transition(JavaThread* thread, jobject vthread, bool in_trans); - - static void start_VTMS_transition(jthread vthread, bool is_mount); - static void finish_VTMS_transition(jthread vthread, bool is_mount); - - static void VTMS_vthread_start(jobject vthread); - static void VTMS_vthread_end(jobject vthread); - - static void VTMS_vthread_mount(jobject vthread, bool hide); - static void VTMS_vthread_unmount(jobject vthread, bool hide); - - static void VTMS_mount_begin(jobject vthread); - static void VTMS_mount_end(jobject vthread); - - static void VTMS_unmount_begin(jobject vthread, bool last_unmount); - static void VTMS_unmount_end(jobject vthread); -}; - /////////////////////////////////////////////////////////////// // // class VirtualThreadList diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 5514f7d3260..a6ce092e40d 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -508,8 +508,16 @@ WB_ENTRY(jboolean, WB_ConcurrentGCRunTo(JNIEnv* env, jobject o, jobject at)) return ConcurrentGCBreakpoints::run_to(c_name); WB_END -WB_ENTRY(jboolean, WB_HasExternalSymbolsStripped(JNIEnv* env, jobject o)) -#if defined(HAS_STRIPPED_DEBUGINFO) +WB_ENTRY(jboolean, WB_ShipDebugInfoFull(JNIEnv* env, jobject o)) +#if defined(SHIP_DEBUGINFO_FULL) + return true; +#else + return false; +#endif +WB_END + +WB_ENTRY(jboolean, WB_ShipDebugInfoPublic(JNIEnv* env, jobject o)) +#if defined(SHIP_DEBUGINFO_PUBLIC) return true; #else return false; @@ -1678,7 +1686,7 @@ WB_ENTRY(void, WB_RelocateNMethodFromAddr(JNIEnv* env, jobject o, jlong addr, ji CodeBlob* blob = CodeCache::find_blob(address); if (blob != nullptr && blob->is_nmethod()) { nmethod* code = blob->as_nmethod(); - if (code->is_in_use()) { + if (code->is_in_use() && !code->is_unloading()) { CompiledICLocker ic_locker(code); code->relocate(static_cast(blob_type)); } @@ -2840,7 +2848,8 @@ static JNINativeMethod methods[] = { {CC"getVMLargePageSize", CC"()J", (void*)&WB_GetVMLargePageSize}, {CC"getHeapSpaceAlignment", CC"()J", (void*)&WB_GetHeapSpaceAlignment}, {CC"getHeapAlignment", CC"()J", (void*)&WB_GetHeapAlignment}, - {CC"hasExternalSymbolsStripped", CC"()Z", (void*)&WB_HasExternalSymbolsStripped}, + {CC"shipsFullDebugInfo", CC"()Z", (void*)&WB_ShipDebugInfoFull}, + {CC"shipsPublicDebugInfo", CC"()Z", (void*)&WB_ShipDebugInfoPublic}, {CC"countAliveClasses0", CC"(Ljava/lang/String;)I", (void*)&WB_CountAliveClasses }, {CC"getSymbolRefcount", CC"(Ljava/lang/String;)I", (void*)&WB_GetSymbolRefcount }, {CC"parseCommandLine0", diff --git a/src/hotspot/share/runtime/continuation.cpp b/src/hotspot/share/runtime/continuation.cpp index 8f1cbe39640..935f304a751 100644 --- a/src/hotspot/share/runtime/continuation.cpp +++ b/src/hotspot/share/runtime/continuation.cpp @@ -35,6 +35,7 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.inline.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/osThread.hpp" #include "runtime/vframe.inline.hpp" #include "runtime/vframe_hp.hpp" @@ -56,66 +57,50 @@ JVM_ENTRY(void, CONT_unpin(JNIEnv* env, jclass cls)) { } JVM_END -#if INCLUDE_JVMTI -class JvmtiUnmountBeginMark : public StackObj { +class UnmountBeginMark : public StackObj { Handle _vthread; JavaThread* _current; freeze_result _result; bool _failed; public: - JvmtiUnmountBeginMark(JavaThread* t) : + UnmountBeginMark(JavaThread* t) : _vthread(t, t->vthread()), _current(t), _result(freeze_pinned_native), _failed(false) { - assert(!_current->is_in_VTMS_transition(), "must be"); + assert(!_current->is_in_vthread_transition(), "must be"); - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount((jthread)_vthread.raw_value(), true); + MountUnmountDisabler::start_transition(_current, _vthread(), false /*is_mount*/, false /*is_thread_start*/); - // Don't preempt if there is a pending popframe or earlyret operation. This can - // be installed in start_VTMS_transition() so we need to check it here. - if (JvmtiExport::can_pop_frame() || JvmtiExport::can_force_early_return()) { - JvmtiThreadState* state = _current->jvmti_thread_state(); - if (_current->has_pending_popframe() || (state != nullptr && state->is_earlyret_pending())) { - _failed = true; - } - } - - // Don't preempt in case there is an async exception installed since - // we would incorrectly throw it during the unmount logic in the carrier. - if (_current->has_async_exception_condition()) { + // Don't preempt if there is a pending popframe or earlyret operation. This can + // be installed in in process_at_transition_start() so we need to check it here. + if (JvmtiExport::can_pop_frame() || JvmtiExport::can_force_early_return()) { + JvmtiThreadState* state = _current->jvmti_thread_state(); + if (_current->has_pending_popframe() || (state != nullptr && state->is_earlyret_pending())) { _failed = true; } - } else { - _current->set_is_in_VTMS_transition(true); - java_lang_Thread::set_is_in_VTMS_transition(_vthread(), true); + } + + // Don't preempt in case there is an async exception installed since + // we would incorrectly throw it during the unmount logic in the carrier. + if (_current->has_async_exception_condition()) { + _failed = true; } } - ~JvmtiUnmountBeginMark() { + ~UnmountBeginMark() { assert(!_current->is_suspended(), "must be"); - - assert(_current->is_in_VTMS_transition(), "must be"); - assert(java_lang_Thread::is_in_VTMS_transition(_vthread()), "must be"); - - // Read it again since for late binding agents the flag could have - // been set while blocked in the allocation path during freeze. - bool jvmti_present = JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events(); + assert(_current->is_in_vthread_transition(), "must be"); if (_result != freeze_ok) { // Undo transition - if (jvmti_present) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount((jthread)_vthread.raw_value(), false); - } else { - _current->set_is_in_VTMS_transition(false); - java_lang_Thread::set_is_in_VTMS_transition(_vthread(), false); - } + MountUnmountDisabler::end_transition(_current, _vthread(), true /*is_mount*/, false /*is_thread_start*/); } } void set_result(freeze_result res) { _result = res; } bool failed() { return _failed; } }; +#if INCLUDE_JVMTI static bool is_vthread_safe_to_preempt_for_jvmti(JavaThread* current) { - if (current->is_in_VTMS_transition()) { + if (current->is_in_vthread_transition()) { // We are at the end of a mount transition. return false; } @@ -150,11 +135,11 @@ freeze_result Continuation::try_preempt(JavaThread* current, oop continuation) { return freeze_pinned_native; } - JVMTI_ONLY(JvmtiUnmountBeginMark jubm(current);) - JVMTI_ONLY(if (jubm.failed()) return freeze_pinned_native;) + UnmountBeginMark ubm(current); + if (ubm.failed()) return freeze_pinned_native; freeze_result res = CAST_TO_FN_PTR(FreezeContFnT, freeze_preempt_entry())(current, current->last_Java_sp()); log_trace(continuations, preempt)("try_preempt: %d", res); - JVMTI_ONLY(jubm.set_result(res);) + ubm.set_result(res); if (current->has_pending_exception()) { assert(res == freeze_exception, "expecting an exception result from freeze"); diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 2a31e5fb5b2..ccbe78817d6 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -58,6 +58,7 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/keepStackGCProcessed.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/orderAccess.hpp" #include "runtime/prefetch.inline.hpp" @@ -1690,7 +1691,7 @@ static void jvmti_mount_end(JavaThread* current, ContinuationWrapper& cont, fram AnchorMark am(current, top); // Set anchor so that the stack is walkable. JRT_BLOCK - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount((jthread)vth.raw_value(), false); + MountUnmountDisabler::end_transition(current, vth(), true /*is_mount*/, false /*is_thread_start*/); if (current->pending_contended_entered_event()) { // No monitor JVMTI events for ObjectLocker case. @@ -2629,19 +2630,21 @@ intptr_t* ThawBase::handle_preempted_continuation(intptr_t* sp, Continuation::pr DEBUG_ONLY(verify_frame_kind(top, preempt_kind);) NOT_PRODUCT(int64_t tid = _thread->monitor_owner_id();) -#if INCLUDE_JVMTI // Finish the VTMS transition. - assert(_thread->is_in_VTMS_transition(), "must be"); + assert(_thread->is_in_vthread_transition(), "must be"); bool is_vthread = Continuation::continuation_scope(_cont.continuation()) == java_lang_VirtualThread::vthread_scope(); if (is_vthread) { - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { +#if INCLUDE_JVMTI + if (MountUnmountDisabler::notify_jvmti_events()) { jvmti_mount_end(_thread, _cont, top, preempt_kind); - } else { - _thread->set_is_in_VTMS_transition(false); - java_lang_Thread::set_is_in_VTMS_transition(_thread->vthread(), false); + } else +#endif + { // Faster version of MountUnmountDisabler::end_transition() to avoid + // unnecessary extra instructions from jvmti_mount_end(). + java_lang_Thread::set_is_in_vthread_transition(_thread->vthread(), false); + _thread->set_is_in_vthread_transition(false); } } -#endif if (fast_case) { // If we thawed in the slow path the runtime stub/native wrapper frame already diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 51517fa49db..405b47e1813 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -711,7 +711,7 @@ void JVMFlag::printFlags(outputStream* out, bool withComments, bool printRanges, for (size_t i = 0; i < length; i++) { const bool skip = (skipDefaults && flagTable[i].is_default()); const bool visited = iteratorMarkers.at(i); - if (!visited && flagTable[i].is_unlocked() && !skip) { + if (!visited && !skip) { if ((bestFlag == nullptr) || (strcmp(bestFlag->name(), flagTable[i].name()) > 0)) { bestFlag = &flagTable[i]; bestFlagIndex = i; diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index d002edd48cd..68b5d8254fd 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1671,8 +1671,9 @@ const int ObjectAlignmentInBytes = 8; "putback") \ \ /* new oopmap storage allocation */ \ - develop(intx, MinOopMapAllocation, 8, \ + develop(int, MinOopMapAllocation, 8, \ "Minimum number of OopMap entries in an OopMapSet") \ + range(0, max_jint) \ \ /* recompilation */ \ product_pd(intx, CompileThreshold, \ diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index f468f27e2c0..89b02717a7a 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -34,6 +34,7 @@ #include "runtime/handshake.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" #include "runtime/stackWatermarkSet.hpp" @@ -361,6 +362,27 @@ void Handshake::execute(HandshakeClosure* hs_cl) { VMThread::execute(&handshake); } +void Handshake::execute(HandshakeClosure* hs_cl, oop vthread) { + assert(java_lang_VirtualThread::is_instance(vthread), ""); + Handle vth(JavaThread::current(), vthread); + + MountUnmountDisabler md(vthread); + oop carrier_thread = java_lang_VirtualThread::carrier_thread(vth()); + if (carrier_thread != nullptr) { + JavaThread* target = java_lang_Thread::thread(carrier_thread); + assert(target != nullptr, ""); + // Technically there is no need for a ThreadsListHandle since the target + // will block if it tries to unmount the vthread, so it can never exit. + ThreadsListHandle tlh(JavaThread::current()); + assert(tlh.includes(target), ""); + execute(hs_cl, &tlh, target); + assert(target->threadObj() == java_lang_VirtualThread::carrier_thread(vth()), ""); + } else { + // unmounted vthread, execute closure with the current thread + hs_cl->do_thread(nullptr); + } +} + void Handshake::execute(HandshakeClosure* hs_cl, JavaThread* target) { // tlh == nullptr means we rely on a ThreadsListHandle somewhere // in the caller's context (and we sanity check for that). diff --git a/src/hotspot/share/runtime/handshake.hpp b/src/hotspot/share/runtime/handshake.hpp index 1304dca12b7..c764bbcfcd2 100644 --- a/src/hotspot/share/runtime/handshake.hpp +++ b/src/hotspot/share/runtime/handshake.hpp @@ -69,6 +69,7 @@ class Handshake : public AllStatic { // This version of execute() relies on a ThreadListHandle somewhere in // the caller's context to protect target (and we sanity check for that). static void execute(HandshakeClosure* hs_cl, JavaThread* target); + static void execute(HandshakeClosure* hs_cl, oop vthread); // This version of execute() is used when you have a ThreadListHandle in // hand and are using it to protect target. If tlh == nullptr, then we // sanity check for a ThreadListHandle somewhere in the caller's context diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 28bc47c4c74..1bf4841e193 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -448,15 +448,11 @@ JavaThread::JavaThread(MemTag mem_tag) : _do_not_unlock_if_synchronized(false), #if INCLUDE_JVMTI _carrier_thread_suspended(false), - _is_in_VTMS_transition(false), _is_disable_suspend(false), _is_in_java_upcall(false), - _VTMS_transition_mark(false), + _jvmti_events_disabled(0), _on_monitor_waited_event(false), _contended_entered_monitor(nullptr), -#ifdef ASSERT - _is_VTMS_transition_disabler(false), -#endif #endif _jni_attach_state(_not_attaching_via_jni), _is_in_internal_oome_mark(false), @@ -502,6 +498,10 @@ JavaThread::JavaThread(MemTag mem_tag) : _handshake(this), _suspend_resume_manager(this, &_handshake._lock), + _is_in_vthread_transition(false), + DEBUG_ONLY(_is_vthread_transition_disabler(false) COMMA) + DEBUG_ONLY(_is_disabler_at_start(false) COMMA) + _popframe_preserved_args(nullptr), _popframe_preserved_args_size(0), @@ -1149,17 +1149,26 @@ void JavaThread::send_async_exception(JavaThread* target, oop java_throwable) { Handshake::execute(&iaeh, target); } -#if INCLUDE_JVMTI -void JavaThread::set_is_in_VTMS_transition(bool val) { - assert(is_in_VTMS_transition() != val, "already %s transition", val ? "inside" : "outside"); - _is_in_VTMS_transition = val; +bool JavaThread::is_in_vthread_transition() const { + DEBUG_ONLY(Thread* current = Thread::current();) + assert(is_handshake_safe_for(current) || SafepointSynchronize::is_at_safepoint() + || JavaThread::cast(current)->is_disabler_at_start(), "not safe"); + return AtomicAccess::load(&_is_in_vthread_transition); +} + +void JavaThread::set_is_in_vthread_transition(bool val) { + assert(is_in_vthread_transition() != val, "already %s transition", val ? "inside" : "outside"); + AtomicAccess::store(&_is_in_vthread_transition, val); } #ifdef ASSERT -void JavaThread::set_is_VTMS_transition_disabler(bool val) { - _is_VTMS_transition_disabler = val; +void JavaThread::set_is_vthread_transition_disabler(bool val) { + _is_vthread_transition_disabler = val; +} + +void JavaThread::set_is_disabler_at_start(bool val) { + _is_disabler_at_start = val; } -#endif #endif // External suspension mechanism. @@ -1169,11 +1178,8 @@ void JavaThread::set_is_VTMS_transition_disabler(bool val) { // - Target thread will not enter any new monitors. // bool JavaThread::java_suspend(bool register_vthread_SR) { -#if INCLUDE_JVMTI - // Suspending a JavaThread in VTMS transition or disabling VTMS transitions can cause deadlocks. - assert(!is_in_VTMS_transition(), "no suspend allowed in VTMS transition"); - assert(!is_VTMS_transition_disabler(), "no suspend allowed for VTMS transition disablers"); -#endif + // Suspending a vthread transition disabler can cause deadlocks. + assert(!is_vthread_transition_disabler(), "no suspend allowed for vthread transition disablers"); guarantee(Thread::is_JavaThread_protected(/* target */ this), "target JavaThread is not protected in calling context."); diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index b0cd6fb3e4f..d4c12887e10 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -322,15 +322,11 @@ class JavaThread: public Thread { // never locked) when throwing an exception. Used by interpreter only. #if INCLUDE_JVMTI volatile bool _carrier_thread_suspended; // Carrier thread is externally suspended - bool _is_in_VTMS_transition; // thread is in virtual thread mount state transition bool _is_disable_suspend; // JVMTI suspend is temporarily disabled; used on current thread only bool _is_in_java_upcall; // JVMTI is doing a Java upcall, so JVMTI events must be hidden - bool _VTMS_transition_mark; // used for sync between VTMS transitions and disablers + int _jvmti_events_disabled; // JVMTI events disabled manually bool _on_monitor_waited_event; // Avoid callee arg processing for enterSpecial when posting waited event ObjectMonitor* _contended_entered_monitor; // Monitor for pending monitor_contended_entered callback -#ifdef ASSERT - bool _is_VTMS_transition_disabler; // thread currently disabled VTMS transitions -#endif #endif // JNI attach states: @@ -736,6 +732,20 @@ public: // current thread, i.e. reverts optimizations based on escape analysis. void wait_for_object_deoptimization(); +private: + bool _is_in_vthread_transition; // thread is in virtual thread mount state transition + DEBUG_ONLY(bool _is_vthread_transition_disabler;) // thread currently disabled vthread transitions + DEBUG_ONLY(bool _is_disabler_at_start;) // thread at process of disabling vthread transitions +public: + bool is_in_vthread_transition() const; + void set_is_in_vthread_transition(bool val); +#ifdef ASSERT + bool is_vthread_transition_disabler() const { return _is_vthread_transition_disabler; } + void set_is_vthread_transition_disabler(bool val); + bool is_disabler_at_start() const { return _is_disabler_at_start; } + void set_is_disabler_at_start(bool val); +#endif + #if INCLUDE_JVMTI inline bool set_carrier_thread_suspended(); inline bool clear_carrier_thread_suspended(); @@ -744,33 +754,28 @@ public: return AtomicAccess::load(&_carrier_thread_suspended); } - bool is_in_VTMS_transition() const { return _is_in_VTMS_transition; } - void set_is_in_VTMS_transition(bool val); - bool is_disable_suspend() const { return _is_disable_suspend; } - void toggle_is_disable_suspend() { _is_disable_suspend = !_is_disable_suspend; }; + void toggle_is_disable_suspend() { _is_disable_suspend = !_is_disable_suspend; } bool is_in_java_upcall() const { return _is_in_java_upcall; } - void toggle_is_in_java_upcall() { _is_in_java_upcall = !_is_in_java_upcall; }; + void toggle_is_in_java_upcall() { _is_in_java_upcall = !_is_in_java_upcall; } - bool VTMS_transition_mark() const { return AtomicAccess::load(&_VTMS_transition_mark); } - void set_VTMS_transition_mark(bool val) { AtomicAccess::store(&_VTMS_transition_mark, val); } + void disable_jvmti_events() { _jvmti_events_disabled++; } + void enable_jvmti_events() { _jvmti_events_disabled--; } // Temporarily skip posting JVMTI events for safety reasons when executions is in a critical section: - // - is in a VTMS transition (_is_in_VTMS_transition) + // - is in a vthread transition (_is_in_vthread_transition) // - is in an interruptLock or similar critical section (_is_disable_suspend) // - JVMTI is making a Java upcall (_is_in_java_upcall) - bool should_hide_jvmti_events() const { return _is_in_VTMS_transition || _is_disable_suspend || _is_in_java_upcall; } + bool should_hide_jvmti_events() const { + return _is_in_vthread_transition || _is_disable_suspend || _is_in_java_upcall || _jvmti_events_disabled != 0; + } bool on_monitor_waited_event() { return _on_monitor_waited_event; } void set_on_monitor_waited_event(bool val) { _on_monitor_waited_event = val; } bool pending_contended_entered_event() { return _contended_entered_monitor != nullptr; } ObjectMonitor* contended_entered_monitor() { return _contended_entered_monitor; } -#ifdef ASSERT - bool is_VTMS_transition_disabler() const { return _is_VTMS_transition_disabler; } - void set_is_VTMS_transition_disabler(bool val); -#endif #endif void set_contended_entered_monitor(ObjectMonitor* val) NOT_JVMTI_RETURN JVMTI_ONLY({ _contended_entered_monitor = val; }) @@ -925,9 +930,9 @@ public: static ByteSize preempt_alternate_return_offset() { return byte_offset_of(JavaThread, _preempt_alternate_return); } DEBUG_ONLY(static ByteSize interp_at_preemptable_vmcall_cnt_offset() { return byte_offset_of(JavaThread, _interp_at_preemptable_vmcall_cnt); }) static ByteSize unlocked_inflated_monitor_offset() { return byte_offset_of(JavaThread, _unlocked_inflated_monitor); } + static ByteSize is_in_vthread_transition_offset() { return byte_offset_of(JavaThread, _is_in_vthread_transition); } #if INCLUDE_JVMTI - static ByteSize is_in_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_VTMS_transition); } static ByteSize is_disable_suspend_offset() { return byte_offset_of(JavaThread, _is_disable_suspend); } #endif diff --git a/src/hotspot/share/runtime/mountUnmountDisabler.cpp b/src/hotspot/share/runtime/mountUnmountDisabler.cpp new file mode 100644 index 00000000000..5bf00323f10 --- /dev/null +++ b/src/hotspot/share/runtime/mountUnmountDisabler.cpp @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "classfile/javaClasses.inline.hpp" +#include "prims/jvmtiEventController.hpp" +#include "prims/jvmtiExport.hpp" +#include "prims/jvmtiThreadState.inline.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/javaThread.hpp" +#include "runtime/mountUnmountDisabler.hpp" +#include "runtime/threadSMR.hpp" + +volatile int MountUnmountDisabler::_global_vthread_transition_disable_count = 0; +volatile int MountUnmountDisabler::_active_disablers = 0; +bool MountUnmountDisabler::_exclusive_operation_ongoing = false; +bool MountUnmountDisabler::_notify_jvmti_events = false; + +#if INCLUDE_JVMTI +class JVMTIStartTransition : public StackObj { + JavaThread* _current; + Handle _vthread; + bool _is_mount; + bool _is_thread_end; + public: + JVMTIStartTransition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_end) : + _current(current), _vthread(current, vthread), _is_mount(is_mount), _is_thread_end(is_thread_end) { + assert(DoJVMTIVirtualThreadTransitions || !JvmtiExport::can_support_virtual_threads(), "sanity check"); + if (DoJVMTIVirtualThreadTransitions && MountUnmountDisabler::notify_jvmti_events()) { + // post VirtualThreadUnmount event before VirtualThreadEnd + if (!_is_mount && JvmtiExport::should_post_vthread_unmount()) { + JvmtiExport::post_vthread_unmount((jthread)_vthread.raw_value()); + } + if (_is_thread_end && JvmtiExport::should_post_vthread_end()) { + JvmtiExport::post_vthread_end((jthread)_vthread.raw_value()); + } + } + } + ~JVMTIStartTransition() { + if (DoJVMTIVirtualThreadTransitions && MountUnmountDisabler::notify_jvmti_events()) { + if (_is_thread_end && _current->jvmti_thread_state() != nullptr) { + JvmtiExport::cleanup_thread(_current); + assert(_current->jvmti_thread_state() == nullptr, "should be null"); + assert(java_lang_Thread::jvmti_thread_state(_vthread()) == nullptr, "should be null"); + } + if (!_is_mount) { + _current->rebind_to_jvmti_thread_state_of(_current->threadObj()); + } + } + } +}; + +class JVMTIEndTransition : public StackObj { + JavaThread* _current; + Handle _vthread; + bool _is_mount; + bool _is_thread_start; + public: + JVMTIEndTransition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_start) : + _current(current), _vthread(current, vthread), _is_mount(is_mount), _is_thread_start(is_thread_start) { + assert(DoJVMTIVirtualThreadTransitions || !JvmtiExport::can_support_virtual_threads(), "sanity check"); + if (DoJVMTIVirtualThreadTransitions && MountUnmountDisabler::notify_jvmti_events()) { + if (_is_mount) { + _current->rebind_to_jvmti_thread_state_of(_vthread()); + } + DEBUG_ONLY(bool is_virtual = java_lang_VirtualThread::is_instance(_current->jvmti_vthread())); + assert(_is_mount == is_virtual, "wrong identity"); + } + } + ~JVMTIEndTransition() { + if (DoJVMTIVirtualThreadTransitions && MountUnmountDisabler::notify_jvmti_events()) { + if (!_is_mount && _current->is_carrier_thread_suspended()) { + MonitorLocker ml(VThreadTransition_lock); + while (_current->is_carrier_thread_suspended()) { + ml.wait(200); + } + } + + if (_is_thread_start) { + // If interp_only_mode has been enabled then we must eagerly create JvmtiThreadState + // objects for globally enabled virtual thread filtered events. Otherwise, + // it is an important optimization to create JvmtiThreadState objects lazily. + // This optimization is disabled when watchpoint capabilities are present. It is to + // work around a bug with virtual thread frames which can be not deoptimized in time. + if (JvmtiThreadState::seen_interp_only_mode() || + JvmtiExport::should_post_field_access() || + JvmtiExport::should_post_field_modification()){ + JvmtiEventController::thread_started(_current); + } + if (JvmtiExport::should_post_vthread_start()) { + JvmtiExport::post_vthread_start((jthread)_vthread.raw_value()); + } + } + if (_is_mount && JvmtiExport::should_post_vthread_mount()) { + JvmtiExport::post_vthread_mount((jthread)_vthread.raw_value()); + } + } + } +}; +#endif // INCLUDE_JVMTI + +bool MountUnmountDisabler::is_start_transition_disabled(JavaThread* thread, oop vthread) { + // We need to read the per-vthread and global counters to check if transitions are disabled. + // In case of JVMTI present, the global counter will always be at least 1. This is to force + // the slow path and check for possible event posting. Here we need to check if transitions + // are actually disabled, so we compare the global counter against 1 or 0 accordingly. + // In case of JVMTI we also need to check for suspension. + int base_disable_count = notify_jvmti_events() ? 1 : 0; + return java_lang_Thread::vthread_transition_disable_count(vthread) > 0 + || global_vthread_transition_disable_count() > base_disable_count + JVMTI_ONLY(|| (JvmtiVTSuspender::is_vthread_suspended(java_lang_Thread::thread_id(vthread)) || thread->is_suspended())); +} + +void MountUnmountDisabler::start_transition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_end) { + assert(!java_lang_Thread::is_in_vthread_transition(vthread), ""); + assert(!current->is_in_vthread_transition(), ""); + Handle vth = Handle(current, vthread); + JVMTI_ONLY(JVMTIStartTransition jst(current, vthread, is_mount, is_thread_end);) + + java_lang_Thread::set_is_in_vthread_transition(vth(), true); + current->set_is_in_vthread_transition(true); + + // Prevent loads of disable conditions from floating up. + OrderAccess::storeload(); + + while (is_start_transition_disabled(current, vth())) { + java_lang_Thread::set_is_in_vthread_transition(vth(), false); + current->set_is_in_vthread_transition(false); + { + // Block while transitions are disabled + MonitorLocker ml(VThreadTransition_lock); + while (is_start_transition_disabled(current, vth())) { + ml.wait(200); + } + } + + // Try to start transition again... + java_lang_Thread::set_is_in_vthread_transition(vth(), true); + current->set_is_in_vthread_transition(true); + OrderAccess::storeload(); + } + + // Start of the critical section. If this is a mount, we need an acquire barrier to + // synchronize with a possible disabler that executed an operation while this thread + // was unmounted. We make VirtualThread.mount guarantee such ordering and avoid barriers + // here. If this is an unmount, the handshake that the disabler executed against this + // thread already provided the needed synchronization. + // This pairs with the release barrier in xx_enable_for_one()/xx_enable_for_all(). +} + +void MountUnmountDisabler::end_transition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_start) { + assert(java_lang_Thread::is_in_vthread_transition(vthread), ""); + assert(current->is_in_vthread_transition(), ""); + Handle vth = Handle(current, vthread); + JVMTI_ONLY(JVMTIEndTransition jst(current, vthread, is_mount, is_thread_start);) + + // End of the critical section. If this is an unmount, we need a release barrier before + // clearing the in_transition flags to make sure any memory operations executed in the + // transition are visible to a possible disabler that executes while this thread is unmounted. + // We make VirtualThread.unmount guarantee such ordering and avoid barriers here. If this is + // a mount, the only thing that needs to be published is the setting of carrierThread, since + // the handshake that the disabler will execute against it already provides the needed + // synchronization. This order is already guaranteed by the barriers in VirtualThread.mount. + // This pairs with the acquire barrier in xx_disable_for_one()/xx_disable_for_all(). + + java_lang_Thread::set_is_in_vthread_transition(vth(), false); + current->set_is_in_vthread_transition(false); + + // Unblock waiting transition disablers. + if (active_disablers() > 0) { + MonitorLocker ml(VThreadTransition_lock); + ml.notify_all(); + } +} + +// disable transitions for one virtual thread +// disable transitions for all threads if thread is nullptr or a platform thread +MountUnmountDisabler::MountUnmountDisabler(oop thread_oop) + : _is_exclusive(false), + _is_self(false) +{ + if (!Continuations::enabled()) { + return; // MountUnmountDisabler is no-op without virtual threads + } + if (Thread::current_or_null() == nullptr) { + return; // Detached thread, can be a call from Agent_OnLoad. + } + JavaThread* current = JavaThread::current(); + assert(!current->is_in_vthread_transition(), ""); + + bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop); + if (thread_oop == nullptr || + (!is_virtual && thread_oop == current->threadObj()) || + (is_virtual && thread_oop == current->vthread())) { + _is_self = true; + return; // no need for current thread to disable and enable transitions for itself + } + + // Target can be virtual or platform thread. + // If target is a platform thread then we have to disable transitions for all threads. + // It is by several reasons: + // - carrier threads can mount virtual threads which may cause incorrect behavior + // - there is no mechanism to disable transitions for a specific carrier thread yet + if (is_virtual) { + _vthread = Handle(current, thread_oop); + disable_transition_for_one(); // disable transitions for one virtual thread + } else { + disable_transition_for_all(); // disable transitions for all virtual threads + } +} + +// disable transitions for all virtual threads +MountUnmountDisabler::MountUnmountDisabler(bool exclusive) + : _is_exclusive(exclusive), + _is_self(false) +{ + if (!Continuations::enabled()) { + return; // MountUnmountDisabler is no-op without virtual threads + } + if (Thread::current_or_null() == nullptr) { + return; // Detached thread, can be a call from Agent_OnLoad. + } + assert(!JavaThread::current()->is_in_vthread_transition(), ""); + disable_transition_for_all(); +} + +MountUnmountDisabler::~MountUnmountDisabler() { + if (!Continuations::enabled()) { + return; // MountUnmountDisabler is a no-op without virtual threads + } + if (Thread::current_or_null() == nullptr) { + return; // Detached thread, can be a call from Agent_OnLoad. + } + if (_is_self) { + return; // no need for current thread to disable and enable transitions for itself + } + if (_vthread() != nullptr) { + enable_transition_for_one(); // enable transitions for one virtual thread + } else { + enable_transition_for_all(); // enable transitions for all virtual threads + } +} + +// disable transitions for one virtual thread +void +MountUnmountDisabler::disable_transition_for_one() { + MonitorLocker ml(VThreadTransition_lock); + while (exclusive_operation_ongoing()) { + ml.wait(10); + } + + inc_active_disablers(); + java_lang_Thread::inc_vthread_transition_disable_count(_vthread()); + + // Prevent load of transition flag from floating up. + OrderAccess::storeload(); + + while (java_lang_Thread::is_in_vthread_transition(_vthread())) { + ml.wait(10); // wait while the virtual thread is in transition + } + + // Start of the critical section. If the target is unmounted, we need an acquire + // barrier to make sure memory operations executed in the last transition are visible. + // If the target is mounted, although the handshake that will be executed against it + // already provides the needed synchronization, we still need to prevent the load of + // carrierThread to float up. + // This pairs with the release barrier in end_transition(). + OrderAccess::acquire(); + DEBUG_ONLY(JavaThread::current()->set_is_vthread_transition_disabler(true);) +} + +// disable transitions for all virtual threads +void +MountUnmountDisabler::disable_transition_for_all() { + DEBUG_ONLY(JavaThread* thread = JavaThread::current();) + DEBUG_ONLY(thread->set_is_disabler_at_start(true);) + + MonitorLocker ml(VThreadTransition_lock); + while (exclusive_operation_ongoing()) { + ml.wait(10); + } + if (_is_exclusive) { + set_exclusive_operation_ongoing(true); + while (active_disablers() > 0) { + ml.wait(10); + } + } + inc_active_disablers(); + inc_global_vthread_transition_disable_count(); + + // Prevent loads of transition flag from floating up. Technically not + // required since JavaThreadIteratorWithHandle includes full fence. + OrderAccess::storeload(); + + // Block while some mount/unmount transitions are in progress. + // Debug version fails and prints diagnostic information. + for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { + while (jt->is_in_vthread_transition()) { + ml.wait(10); + } + } + + // Start of the critical section. If some target is unmounted, we need an acquire + // barrier to make sure memory operations executed in the last transition are visible. + // If a target is mounted, although the handshake that will be executed against it + // already provides the needed synchronization, we still need to prevent the load of + // carrierThread to float up. + // This pairs with the release barrier in end_transition(). + OrderAccess::acquire(); + DEBUG_ONLY(thread->set_is_vthread_transition_disabler(true);) + DEBUG_ONLY(thread->set_is_disabler_at_start(false);) +} + +// enable transitions for one virtual thread +void +MountUnmountDisabler::enable_transition_for_one() { + assert(java_lang_VirtualThread::is_instance(_vthread()), ""); + + // End of the critical section. If the target was unmounted, we need a + // release barrier before decrementing _vthread_transition_disable_count to + // make sure any memory operations executed by the disabler are visible to + // the target once it mounts again. If the target was mounted, the handshake + // executed against it already provided the needed synchronization. + // This pairs with the equivalent acquire barrier in start_transition(). + OrderAccess::release(); + + MonitorLocker ml(VThreadTransition_lock); + dec_active_disablers(); + java_lang_Thread::dec_vthread_transition_disable_count(_vthread()); + if (java_lang_Thread::vthread_transition_disable_count(_vthread()) == 0) { + ml.notify_all(); + } + DEBUG_ONLY(JavaThread::current()->set_is_vthread_transition_disabler(false);) +} + +// enable transitions for all virtual threads +void +MountUnmountDisabler::enable_transition_for_all() { + JavaThread* thread = JavaThread::current(); + + // End of the critical section. If some target was unmounted, we need a + // release barrier before decrementing _global_vthread_transition_disable_count + // to make sure any memory operations executed by the disabler are visible to + // the target once it mounts again. If a target was mounted, the handshake + // executed against it already provided the needed synchronization. + // This pairs with the equivalent acquire barrier in start_transition(). + OrderAccess::release(); + + MonitorLocker ml(VThreadTransition_lock); + if (exclusive_operation_ongoing()) { + set_exclusive_operation_ongoing(false); + } + dec_active_disablers(); + dec_global_vthread_transition_disable_count(); + int base_disable_count = notify_jvmti_events() ? 1 : 0; + if (global_vthread_transition_disable_count() == base_disable_count || _is_exclusive) { + ml.notify_all(); + } + DEBUG_ONLY(thread->set_is_vthread_transition_disabler(false);) +} + +int MountUnmountDisabler::global_vthread_transition_disable_count() { + assert(_global_vthread_transition_disable_count >= 0, ""); + return AtomicAccess::load(&_global_vthread_transition_disable_count); +} + +void MountUnmountDisabler::inc_global_vthread_transition_disable_count() { + assert(VThreadTransition_lock->owned_by_self() || SafepointSynchronize::is_at_safepoint(), "Must be locked"); + assert(_global_vthread_transition_disable_count >= 0, ""); + AtomicAccess::store(&_global_vthread_transition_disable_count, _global_vthread_transition_disable_count + 1); +} + +void MountUnmountDisabler::dec_global_vthread_transition_disable_count() { + assert(VThreadTransition_lock->owned_by_self() || SafepointSynchronize::is_at_safepoint(), "Must be locked"); + assert(_global_vthread_transition_disable_count > 0, ""); + AtomicAccess::store(&_global_vthread_transition_disable_count, _global_vthread_transition_disable_count - 1); +} + +bool MountUnmountDisabler::exclusive_operation_ongoing() { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + return _exclusive_operation_ongoing; +} + +void MountUnmountDisabler::set_exclusive_operation_ongoing(bool val) { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + assert(_exclusive_operation_ongoing != val, ""); + _exclusive_operation_ongoing = val; +} + +int MountUnmountDisabler::active_disablers() { + assert(_active_disablers >= 0, ""); + return AtomicAccess::load(&_active_disablers); +} + +void MountUnmountDisabler::inc_active_disablers() { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + assert(_active_disablers >= 0, ""); + _active_disablers++; +} + +void MountUnmountDisabler::dec_active_disablers() { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + assert(_active_disablers > 0, ""); + _active_disablers--; +} + +bool MountUnmountDisabler::notify_jvmti_events() { + return _notify_jvmti_events; +} + +void MountUnmountDisabler::set_notify_jvmti_events(bool val, bool is_onload) { + if (val == _notify_jvmti_events || !DoJVMTIVirtualThreadTransitions) return; + + // Force slow path on start/end vthread transitions for JVMTI bookkeeping. + // 'val' is always true except with WhiteBox methods for testing purposes. + if (is_onload) { + // Skip existing increment methods since asserts will fail. + assert(val && _global_vthread_transition_disable_count == 0, ""); + AtomicAccess::inc(&_global_vthread_transition_disable_count); + } else { + assert(SafepointSynchronize::is_at_safepoint(), ""); + if (val) { + inc_global_vthread_transition_disable_count(); + } else { + dec_global_vthread_transition_disable_count(); + } + } + log_trace(continuations,tracking)("%s _notify_jvmti_events, _global_vthread_transition_disable_count=%d", val ? "enabling" : "disabling", _global_vthread_transition_disable_count); + _notify_jvmti_events = val; +} diff --git a/src/hotspot/share/runtime/mountUnmountDisabler.hpp b/src/hotspot/share/runtime/mountUnmountDisabler.hpp new file mode 100644 index 00000000000..2ebb09734a6 --- /dev/null +++ b/src/hotspot/share/runtime/mountUnmountDisabler.hpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_MOUNTUNMOUNTDISABLER_HPP +#define SHARE_RUNTIME_MOUNTUNMOUNTDISABLER_HPP + +#include "memory/allocation.hpp" +#include "runtime/handles.hpp" + +class JavaThread; + +// This class adds support to disable virtual thread transitions (mount/unmount). +// This is needed to safely execute operations that access virtual thread state. +// Users should use the Handshake class when possible instead of using this directly. +class MountUnmountDisabler : public AnyObj { + // The global counter is used for operations that require disabling + // transitions for all virtual threads. Currently this is only used + // by some JVMTI operations. We also increment this counter when the + // first JVMTI agent attaches to always force the slowpath when starting + // a transition. This is needed because if JVMTI is present we need to + // check for possible event posting. + static volatile int _global_vthread_transition_disable_count; + static volatile int _active_disablers; + static bool _exclusive_operation_ongoing; + + bool _is_exclusive; // currently only for suspender or resumer + bool _is_virtual; // target thread is virtual + bool _is_self; // MountUnmountDisabler is a no-op for current platform, carrier or virtual thread + Handle _vthread; // virtual thread to disable transitions for, no-op if it is a platform thread + + //DEBUG_ONLY(static void print_info();) + void disable_transition_for_one(); + void disable_transition_for_all(); + void enable_transition_for_one(); + void enable_transition_for_all(); + + public: + MountUnmountDisabler(bool exlusive = false); + MountUnmountDisabler(oop thread_oop); + ~MountUnmountDisabler(); + + static int global_vthread_transition_disable_count(); + static void inc_global_vthread_transition_disable_count(); + static void dec_global_vthread_transition_disable_count(); + + static volatile int* global_vthread_transition_disable_count_address() { + return &_global_vthread_transition_disable_count; + } + + static bool exclusive_operation_ongoing(); + static void set_exclusive_operation_ongoing(bool val); + + static int active_disablers(); + static void inc_active_disablers(); + static void dec_active_disablers(); + + static void start_transition(JavaThread* thread, oop vthread, bool is_mount, bool is_thread_end); + static void end_transition(JavaThread* thread, oop vthread, bool is_mount, bool is_thread_start); + + static bool is_start_transition_disabled(JavaThread* thread, oop vthread); + + // enable notifications from VirtualThread about Mount/Unmount events + static bool _notify_jvmti_events; + static bool notify_jvmti_events(); + static void set_notify_jvmti_events(bool val, bool is_onload = false); + static bool* notify_jvmti_events_address() { + return &_notify_jvmti_events; + } +}; + +#endif // SHARE_RUNTIME_MOUNTUNMOUNTDISABLER_HPP diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index e4707a342a7..b102e6424f1 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -49,7 +49,7 @@ Mutex* JfieldIdCreation_lock = nullptr; Monitor* JNICritical_lock = nullptr; Mutex* JvmtiThreadState_lock = nullptr; Monitor* EscapeBarrier_lock = nullptr; -Monitor* JvmtiVTMSTransition_lock = nullptr; +Monitor* VThreadTransition_lock = nullptr; Mutex* JvmtiVThreadSuspend_lock = nullptr; Monitor* Heap_lock = nullptr; #if INCLUDE_PARALLELGC @@ -244,7 +244,7 @@ void mutex_init() { MUTEX_DEFN(SymbolArena_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(ExceptionCache_lock , PaddedMutex , safepoint); #ifndef PRODUCT - MUTEX_DEFN(FullGCALot_lock , PaddedMutex , safepoint); // a lock to make FullGCALot MT safe + MUTEX_DEFN(FullGCALot_lock , PaddedMutex , nosafepoint); // a lock to make FullGCALot MT safe #endif MUTEX_DEFN(BeforeExit_lock , PaddedMonitor, safepoint); @@ -265,7 +265,7 @@ void mutex_init() { MUTEX_DEFN(CompileStatistics_lock , PaddedMutex , safepoint); MUTEX_DEFN(DirectivesStack_lock , PaddedMutex , nosafepoint); - MUTEX_DEFN(JvmtiVTMSTransition_lock , PaddedMonitor, safepoint); // used for Virtual Thread Mount State transition management + MUTEX_DEFN(VThreadTransition_lock , PaddedMonitor, safepoint); MUTEX_DEFN(JvmtiVThreadSuspend_lock , PaddedMutex, nosafepoint-1); MUTEX_DEFN(EscapeBarrier_lock , PaddedMonitor, nosafepoint); // Used to synchronize object reallocation/relocking triggered by JVMTI MUTEX_DEFN(Management_lock , PaddedMutex , safepoint); // used for JVM management @@ -361,8 +361,8 @@ void mutex_init() { // JVMCIRuntime_lock must be acquired before JVMCI_lock to avoid deadlock MUTEX_DEFL(JVMCI_lock , PaddedMonitor, JVMCIRuntime_lock); #endif - MUTEX_DEFL(JvmtiThreadState_lock , PaddedMutex , JvmtiVTMSTransition_lock); // Used by JvmtiThreadState/JvmtiEventController - MUTEX_DEFL(SharedDecoder_lock , PaddedMutex , NmtVirtualMemory_lock); // Must be lower than NmtVirtualMemory_lock due to MemTracker::print_containing_region + MUTEX_DEFL(JvmtiThreadState_lock , PaddedMutex , VThreadTransition_lock); // Used by JvmtiThreadState/JvmtiEventController + MUTEX_DEFL(SharedDecoder_lock , PaddedMutex , NmtVirtualMemory_lock); // Must be lower than NmtVirtualMemory_lock due to MemTracker::print_containing_region // Allocate RecursiveMutex MultiArray_lock = new RecursiveMutex(); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 74fe4650b7c..f6c0a967718 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -47,7 +47,7 @@ extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI stati extern Monitor* JNICritical_lock; // a lock used while synchronizing with threads entering/leaving JNI critical regions extern Mutex* JvmtiThreadState_lock; // a lock on modification of JVMTI thread data extern Monitor* EscapeBarrier_lock; // a lock to sync reallocating and relocking objects because of JVMTI access -extern Monitor* JvmtiVTMSTransition_lock; // a lock for Virtual Thread Mount State transition (VTMS transition) management +extern Monitor* VThreadTransition_lock; // a lock used when disabling virtual thread transitions extern Mutex* JvmtiVThreadSuspend_lock; // a lock for virtual threads suspension extern Monitor* Heap_lock; // a lock on the heap #if INCLUDE_PARALLELGC diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index e277e1fb569..7e3bf763d08 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -737,34 +737,6 @@ void SharedRuntime::throw_and_post_jvmti_exception(JavaThread* current, Symbol* throw_and_post_jvmti_exception(current, h_exception); } -#if INCLUDE_JVMTI -JRT_ENTRY(void, SharedRuntime::notify_jvmti_vthread_start(oopDesc* vt, jboolean hide, JavaThread* current)) - assert(hide == JNI_FALSE, "must be VTMS transition finish"); - jobject vthread = JNIHandles::make_local(const_cast(vt)); - JvmtiVTMSTransitionDisabler::VTMS_vthread_start(vthread); - JNIHandles::destroy_local(vthread); -JRT_END - -JRT_ENTRY(void, SharedRuntime::notify_jvmti_vthread_end(oopDesc* vt, jboolean hide, JavaThread* current)) - assert(hide == JNI_TRUE, "must be VTMS transition start"); - jobject vthread = JNIHandles::make_local(const_cast(vt)); - JvmtiVTMSTransitionDisabler::VTMS_vthread_end(vthread); - JNIHandles::destroy_local(vthread); -JRT_END - -JRT_ENTRY(void, SharedRuntime::notify_jvmti_vthread_mount(oopDesc* vt, jboolean hide, JavaThread* current)) - jobject vthread = JNIHandles::make_local(const_cast(vt)); - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount(vthread, hide); - JNIHandles::destroy_local(vthread); -JRT_END - -JRT_ENTRY(void, SharedRuntime::notify_jvmti_vthread_unmount(oopDesc* vt, jboolean hide, JavaThread* current)) - jobject vthread = JNIHandles::make_local(const_cast(vt)); - JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount(vthread, hide); - JNIHandles::destroy_local(vthread); -JRT_END -#endif // INCLUDE_JVMTI - // The interpreter code to call this tracing function is only // called/generated when UL is on for redefine, class and has the right level // and tags. Since obsolete methods are never compiled, we don't have @@ -809,6 +781,8 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, // determine handler bci, if any EXCEPTION_MARK; + Handle orig_exception(THREAD, exception()); + int handler_bci = -1; int scope_depth = 0; if (!force_unwind) { @@ -830,7 +804,7 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, // thrown (bugs 4307310 and 4546590). Set "exception" reference // argument to ensure that the correct exception is thrown (4870175). recursive_exception_occurred = true; - exception = Handle(THREAD, PENDING_EXCEPTION); + exception.replace(PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; if (handler_bci >= 0) { bci = handler_bci; @@ -859,8 +833,10 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, // If the compiler did not anticipate a recursive exception, resulting in an exception // thrown from the catch bci, then the compiled exception handler might be missing. - // This is rare. Just deoptimize and let the interpreter handle it. + // This is rare. Just deoptimize and let the interpreter rethrow the original + // exception at the original bci. if (t == nullptr && recursive_exception_occurred) { + exception.replace(orig_exception()); // restore original exception bool make_not_entrant = false; return Deoptimization::deoptimize_for_missing_exception_handler(nm, make_not_entrant); } diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index a696ce5a71b..140207e5d63 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -317,14 +317,6 @@ class SharedRuntime: AllStatic { static void throw_and_post_jvmti_exception(JavaThread* current, Handle h_exception); static void throw_and_post_jvmti_exception(JavaThread* current, Symbol* name, const char *message = nullptr); -#if INCLUDE_JVMTI - // Functions for JVMTI notifications - static void notify_jvmti_vthread_start(oopDesc* vt, jboolean hide, JavaThread* current); - static void notify_jvmti_vthread_end(oopDesc* vt, jboolean hide, JavaThread* current); - static void notify_jvmti_vthread_mount(oopDesc* vt, jboolean hide, JavaThread* current); - static void notify_jvmti_vthread_unmount(oopDesc* vt, jboolean hide, JavaThread* current); -#endif - // RedefineClasses() tracing support for obsolete method entry static int rc_trace_method_entry(JavaThread* thread, Method* m); diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index b051c6d0e18..f9080364dc4 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -199,23 +199,10 @@ // declaration order. #ifdef COMPILER2 -// do_jvmti_stub(name) -#if INCLUDE_JVMTI -#define C2_JVMTI_STUBS_DO(do_jvmti_stub) \ - do_jvmti_stub(notify_jvmti_vthread_start) \ - do_jvmti_stub(notify_jvmti_vthread_end) \ - do_jvmti_stub(notify_jvmti_vthread_mount) \ - do_jvmti_stub(notify_jvmti_vthread_unmount) \ - -#else -#define C2_JVMTI_STUBS_DO(do_jvmti_stub) -#endif // INCLUDE_JVMTI - // client macro to operate on c2 stubs // // do_blob(name, type) // do_stub(name, fancy_jump, pass_tls, return_pc) -// do_jvmti_stub(name) // // do_blob is used for stubs that are generated via direct invocation // of the assembler to write into a blob of the appropriate type @@ -225,10 +212,8 @@ // in the IR graph employ a special type of jump (0, 1 or 2) or // provide access to TLS and the return pc. // -// do_jvmti_stub generates a JVMTI stub as an IR intrinsic which -// employs jump 0, and requires no special access -#define C2_STUBS_DO(do_blob, do_stub, do_jvmti_stub) \ +#define C2_STUBS_DO(do_blob, do_stub) \ do_blob(uncommon_trap, UncommonTrapBlob) \ do_blob(exception, ExceptionBlob) \ do_stub(new_instance, 0, true, false) \ @@ -239,16 +224,19 @@ do_stub(multianewarray4, 0, true, false) \ do_stub(multianewarray5, 0, true, false) \ do_stub(multianewarrayN, 0, true, false) \ - C2_JVMTI_STUBS_DO(do_jvmti_stub) \ do_stub(complete_monitor_locking, 0, false, false) \ do_stub(monitor_notify, 0, false, false) \ do_stub(monitor_notifyAll, 0, false, false) \ do_stub(rethrow, 2, true, true) \ do_stub(slow_arraycopy, 0, false, false) \ do_stub(register_finalizer, 0, false, false) \ + do_stub(vthread_end_first_transition, 0, false, false) \ + do_stub(vthread_start_final_transition, 0, false, false) \ + do_stub(vthread_start_transition, 0, false, false) \ + do_stub(vthread_end_transition, 0, false, false) \ #else -#define C2_STUBS_DO(do_blob, do_stub, do_jvmti_stub) +#define C2_STUBS_DO(do_blob, do_stub) #endif // Stubgen stub declarations @@ -1190,9 +1178,6 @@ // ignore do_stub(name, fancy_jump, pass_tls, return_pc) declarations #define DO_STUB_EMPTY4(name, fancy_jump, pass_tls, return_pc) -// ignore do_jvmti_stub(name) declarations -#define DO_JVMTI_STUB_EMPTY1(stub_name) - // ignore do_stub(blob_name, stub_name) declarations #define DO_STUB_EMPTY2(blob_name, stub_name) diff --git a/src/hotspot/share/runtime/stubInfo.cpp b/src/hotspot/share/runtime/stubInfo.cpp index bca6ff344ea..47a31fe7967 100644 --- a/src/hotspot/share/runtime/stubInfo.cpp +++ b/src/hotspot/share/runtime/stubInfo.cpp @@ -509,14 +509,6 @@ void StubInfo::process_stubgen_entry(StubGroup& group_cursor, StubId:: JOIN3(c2, name, id), \ EntryId:: JOIN3(c2, name, id)); \ -#define PROCESS_C2_JVMTI_STUB(name) \ - process_c2_blob(_group_cursor, _blob_cursor, \ - _stub_cursor, _entry_cursor, \ - "C2 Runtime " # name "_blob", \ - BlobId:: JOIN3(c2, name, id), \ - StubId:: JOIN3(c2, name, id), \ - EntryId:: JOIN3(c2, name, id)); \ - #define PROCESS_STUBGEN_BLOB(blob) \ process_stubgen_blob(_group_cursor, _blob_cursor, \ _stub_cursor, _entry_cursor, \ @@ -610,7 +602,7 @@ void StubInfo::populate_stub_tables() { group_details(_group_cursor)._max = BlobId::NO_BLOBID; group_details(_group_cursor)._entry_base = EntryId::NO_ENTRYID; group_details(_group_cursor)._entry_max = EntryId::NO_ENTRYID; - C2_STUBS_DO(PROCESS_C2_BLOB, PROCESS_C2_STUB, PROCESS_C2_JVMTI_STUB); + C2_STUBS_DO(PROCESS_C2_BLOB, PROCESS_C2_STUB); _group_cursor = StubGroup::STUBGEN; group_details(_group_cursor)._name = "StubGen Stubs"; @@ -637,7 +629,6 @@ void StubInfo::populate_stub_tables() { #undef PROCESS_C1_BLOB #undef PROCESS_C2_BLOB #undef PROCESS_C2_STUB -#undef PROCESS_C2_JVMTI_STUB #undef PROCESS_STUBGEN_BLOB #undef PROCESS_STUBGEN_STUB #undef PROCESS_STUBGEN_ENTRY diff --git a/src/hotspot/share/runtime/stubInfo.hpp b/src/hotspot/share/runtime/stubInfo.hpp index eaea07f7e6c..9ed6e0cb9f9 100644 --- a/src/hotspot/share/runtime/stubInfo.hpp +++ b/src/hotspot/share/runtime/stubInfo.hpp @@ -164,7 +164,6 @@ enum class StubGroup : int { #define SHARED_DECLARE_TAG(name, type) JOIN3(shared, name, id) , #define C1_DECLARE_TAG(name) JOIN3(c1, name, id) , -#define C2_DECLARE_TAG1(name) JOIN3(c2, name, id) , #define C2_DECLARE_TAG2(name, _1) JOIN3(c2, name, id) , #define C2_DECLARE_TAG4(name, _1, _2, _3) JOIN3(c2, name, id) , #define STUBGEN_DECLARE_TAG(name) JOIN3(stubgen, name, id) , @@ -177,8 +176,7 @@ enum class BlobId : int { C1_STUBS_DO(C1_DECLARE_TAG) // declare an enum tag for each opto runtime blob or stub C2_STUBS_DO(C2_DECLARE_TAG2, - C2_DECLARE_TAG4, - C2_DECLARE_TAG1) + C2_DECLARE_TAG4) // declare an enum tag for each stubgen blob STUBGEN_BLOBS_DO(STUBGEN_DECLARE_TAG) NUM_BLOBIDS @@ -214,7 +212,6 @@ enum class BlobId : int { #define SHARED_DECLARE_TAG(name, type) JOIN3(shared, name, id) , #define C1_DECLARE_TAG(name) JOIN3(c1, name, id) , -#define C2_DECLARE_TAG1(name) JOIN3(c2, name, id) , #define C2_DECLARE_TAG2(name, _1) JOIN3(c2, name, id) , #define C2_DECLARE_TAG4(name, _1, _2, _3) JOIN3(c2, name, id) , #define STUBGEN_DECLARE_TAG(blob, name) JOIN3(stubgen, name, id) , @@ -227,8 +224,7 @@ enum class StubId : int { C1_STUBS_DO(C1_DECLARE_TAG) // declare an enum tag for each opto runtime blob or stub C2_STUBS_DO(C2_DECLARE_TAG2, - C2_DECLARE_TAG4, - C2_DECLARE_TAG1) + C2_DECLARE_TAG4) // declare an enum tag for each stubgen runtime stub STUBGEN_STUBS_DO(STUBGEN_DECLARE_TAG) NUM_STUBIDS @@ -307,7 +303,7 @@ enum class StubId : int { type ::ENTRY_COUNT - 1, \ // macros to declare a tag for a C1 generated blob or a C2 generated -// blob, stub or JVMTI stub all of which have a single unique entry +// blob, stub all of which have a single unique entry #define C1_DECLARE_TAG(name) \ JOIN3(c1, name, id), \ @@ -318,9 +314,6 @@ enum class StubId : int { #define C2_DECLARE_STUB_TAG(name, fancy_jump, pass_tls, return_pc) \ JOIN3(c2, name, id), \ -#define C2_DECLARE_JVMTI_STUB_TAG(name) \ - JOIN3(c2, name, id), \ - // macros to declare a tag for a StubGen normal entry or initialized // entry @@ -366,8 +359,7 @@ enum class EntryId : int { C1_STUBS_DO(C1_DECLARE_TAG) // declare an enum tag for each opto runtime blob or stub C2_STUBS_DO(C2_DECLARE_BLOB_TAG, - C2_DECLARE_STUB_TAG, - C2_DECLARE_JVMTI_STUB_TAG) + C2_DECLARE_STUB_TAG) // declare an enum tag for each stubgen entry or, in the case of an // array of entries for the first and last entries. STUBGEN_ALL_ENTRIES_DO(STUBGEN_DECLARE_TAG, @@ -382,7 +374,6 @@ enum class EntryId : int { #undef C1_DECLARE_TAG #undef C2_DECLARE_BLOB_TAG #undef C2_DECLARE_STUB_TAG -#undef C2_DECLARE_JVMTI_STUB_TAG #undef STUBGEN_DECLARE_TAG #undef STUBGEN_DECLARE_INIT_TAG #undef STUBGEN_DECLARE_ARRAY_TAG @@ -402,7 +393,7 @@ enum class EntryId : int { 0 C1_STUBS_DO(COUNT1) #define C2_STUB_COUNT_INITIALIZER \ - 0 C2_STUBS_DO(COUNT2, COUNT4, COUNT1) + 0 C2_STUBS_DO(COUNT2, COUNT4) #define STUBGEN_BLOB_COUNT_INITIALIZER \ 0 STUBGEN_BLOBS_DO(COUNT1) diff --git a/src/hotspot/share/runtime/suspendResumeManager.cpp b/src/hotspot/share/runtime/suspendResumeManager.cpp index 1b9606cf633..067579b6386 100644 --- a/src/hotspot/share/runtime/suspendResumeManager.cpp +++ b/src/hotspot/share/runtime/suspendResumeManager.cpp @@ -93,11 +93,12 @@ void SuspendResumeManager::set_suspended_current_thread(int64_t vthread_id, bool } bool SuspendResumeManager::suspend(bool register_vthread_SR) { - JVMTI_ONLY(assert(!_target->is_in_VTMS_transition(), "no suspend allowed in VTMS transition");) JavaThread* self = JavaThread::current(); if (_target == self) { // If target is the current thread we can bypass the handshake machinery // and just suspend directly. + // Self-suspending while in transition can cause deadlocks. + assert(!self->is_in_vthread_transition(), "no self-suspend allowed in transition"); // The vthread() oop must only be accessed before state is set to _thread_blocked. int64_t id = java_lang_Thread::thread_id(_target->vthread()); ThreadBlockInVM tbivm(self); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 25a99c2d758..4ecc8f9ca01 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -216,6 +216,7 @@ nonstatic_field(InstanceKlass, _annotations, Annotations*) \ nonstatic_field(InstanceKlass, _method_ordering, Array*) \ nonstatic_field(InstanceKlass, _default_vtable_indices, Array*) \ + nonstatic_field(InstanceKlass, _access_flags, AccessFlags) \ nonstatic_field(Klass, _super_check_offset, juint) \ nonstatic_field(Klass, _secondary_super_cache, Klass*) \ nonstatic_field(Klass, _secondary_supers, Array*) \ @@ -225,7 +226,6 @@ volatile_nonstatic_field(Klass, _subklass, Klass*) \ nonstatic_field(Klass, _layout_helper, jint) \ nonstatic_field(Klass, _name, Symbol*) \ - nonstatic_field(Klass, _access_flags, AccessFlags) \ volatile_nonstatic_field(Klass, _next_sibling, Klass*) \ nonstatic_field(Klass, _next_link, Klass*) \ nonstatic_field(Klass, _vtable_len, int) \ @@ -353,6 +353,7 @@ nonstatic_field(ThreadLocalAllocBuffer, _pf_top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _desired_size, size_t) \ nonstatic_field(ThreadLocalAllocBuffer, _refill_waste_limit, size_t) \ + static_field(ThreadLocalAllocBuffer, _reserve_for_allocation_prefetch, int) \ static_field(ThreadLocalAllocBuffer, _target_refills, unsigned) \ nonstatic_field(ThreadLocalAllocBuffer, _number_of_refills, unsigned) \ nonstatic_field(ThreadLocalAllocBuffer, _refill_waste, unsigned) \ diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp index 48f4eb16cf1..8772195df0b 100644 --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -1179,12 +1179,13 @@ public: GrowableArray* _bcis; JavaThreadStatus _thread_status; OopHandle _thread_name; + OopHandle _carrier_thread; GrowableArray* _locks; Blocker _blocker; - GetThreadSnapshotHandshakeClosure(Handle thread_h, JavaThread* java_thread): + GetThreadSnapshotHandshakeClosure(Handle thread_h): HandshakeClosure("GetThreadSnapshotHandshakeClosure"), - _thread_h(thread_h), _java_thread(java_thread), + _thread_h(thread_h), _java_thread(nullptr), _frame_count(0), _methods(nullptr), _bcis(nullptr), _thread_status(), _thread_name(nullptr), _locks(nullptr), _blocker() { @@ -1275,14 +1276,15 @@ private: public: void do_thread(Thread* th) override { Thread* current = Thread::current(); + _java_thread = th != nullptr ? JavaThread::cast(th) : nullptr; bool is_virtual = java_lang_VirtualThread::is_instance(_thread_h()); if (_java_thread != nullptr) { if (is_virtual) { // mounted vthread, use carrier thread state - oop carrier_thread = java_lang_VirtualThread::carrier_thread(_thread_h()); - assert(carrier_thread != nullptr, "should only get here for a mounted vthread"); - _thread_status = java_lang_Thread::get_thread_status(carrier_thread); + _carrier_thread = OopHandle(oop_storage(), java_lang_VirtualThread::carrier_thread(_thread_h())); + assert(_carrier_thread.resolve() == _java_thread->threadObj(), ""); + _thread_status = java_lang_Thread::get_thread_status(_carrier_thread.resolve()); } else { _thread_status = java_lang_Thread::get_thread_status(_thread_h()); } @@ -1459,67 +1461,21 @@ oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) { oop thread_oop; bool has_javathread = tlh.cv_internal_thread_to_JavaThread(jthread, &java_thread, &thread_oop); assert((has_javathread && thread_oop != nullptr) || !has_javathread, "Missing Thread oop"); - Handle thread_h(THREAD, thread_oop); - bool is_virtual = java_lang_VirtualThread::is_instance(thread_h()); // Deals with null + bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop); // Deals with null if (!has_javathread && !is_virtual) { return nullptr; // thread terminated so not of interest } - // wrapper to auto delete JvmtiVTMSTransitionDisabler - class TransitionDisabler { - JvmtiVTMSTransitionDisabler* _transition_disabler; - public: - TransitionDisabler(): _transition_disabler(nullptr) {} - ~TransitionDisabler() { - reset(); - } - void init(jobject jthread) { - _transition_disabler = new (mtInternal) JvmtiVTMSTransitionDisabler(jthread); - } - void reset() { - if (_transition_disabler != nullptr) { - delete _transition_disabler; - _transition_disabler = nullptr; - } - } - } transition_disabler; - - Handle carrier_thread; - if (is_virtual) { - // 1st need to disable mount/unmount transitions - transition_disabler.init(jthread); - - carrier_thread = Handle(THREAD, java_lang_VirtualThread::carrier_thread(thread_h())); - if (carrier_thread != nullptr) { - // Note: The java_thread associated with this carrier_thread may not be - // protected by the ThreadsListHandle above. There could have been an - // unmount and remount after the ThreadsListHandle above was created - // and before the JvmtiVTMSTransitionDisabler was created. However, as - // we have disabled transitions, if we are mounted on it, then it cannot - // terminate and so is safe to handshake with. - java_thread = java_lang_Thread::thread(carrier_thread()); - } else { - // We may have previously found a carrier but the virtual thread has unmounted - // after that, so clear that previous reference. - java_thread = nullptr; - } - } else { - java_thread = java_lang_Thread::thread(thread_h()); - } - // Handshake with target - GetThreadSnapshotHandshakeClosure cl(thread_h, java_thread); - if (java_thread == nullptr) { - // unmounted vthread, execute on the current thread - cl.do_thread(nullptr); + Handle thread_h(THREAD, thread_oop); + GetThreadSnapshotHandshakeClosure cl(thread_h); + if (java_lang_VirtualThread::is_instance(thread_oop)) { + Handshake::execute(&cl, thread_oop); } else { Handshake::execute(&cl, &tlh, java_thread); } - // all info is collected, can enable transitions. - transition_disabler.reset(); - // StackTrace InstanceKlass* ste_klass = vmClasses::StackTraceElement_klass(); assert(ste_klass != nullptr, "must be loaded"); @@ -1569,7 +1525,7 @@ oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) { Handle snapshot = jdk_internal_vm_ThreadSnapshot::allocate(InstanceKlass::cast(snapshot_klass), CHECK_NULL); jdk_internal_vm_ThreadSnapshot::set_name(snapshot(), cl._thread_name.resolve()); jdk_internal_vm_ThreadSnapshot::set_thread_status(snapshot(), (int)cl._thread_status); - jdk_internal_vm_ThreadSnapshot::set_carrier_thread(snapshot(), carrier_thread()); + jdk_internal_vm_ThreadSnapshot::set_carrier_thread(snapshot(), cl._carrier_thread.resolve()); jdk_internal_vm_ThreadSnapshot::set_stack_trace(snapshot(), trace()); jdk_internal_vm_ThreadSnapshot::set_locks(snapshot(), locks()); if (!cl._blocker.is_empty()) { diff --git a/src/hotspot/share/utilities/accessFlags.hpp b/src/hotspot/share/utilities/accessFlags.hpp index a752c09cb42..54bbaeb2c13 100644 --- a/src/hotspot/share/utilities/accessFlags.hpp +++ b/src/hotspot/share/utilities/accessFlags.hpp @@ -67,7 +67,7 @@ class AccessFlags { void set_flags(u2 flags) { _flags = flags; } private: - friend class Klass; + friend class InstanceKlass; friend class ClassFileParser; // the functions below should only be called on the _access_flags inst var directly, // otherwise they are just changing a copy of the flags diff --git a/src/hotspot/share/utilities/concurrentHashTable.hpp b/src/hotspot/share/utilities/concurrentHashTable.hpp index 48166b22126..a837a56a19a 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.hpp @@ -451,8 +451,7 @@ class ConcurrentHashTable : public CHeapObj { // All callbacks for get are under critical sections. Other callbacks may be // under critical section or may have locked parts of table. Calling any - // methods on the table during a callback is not supported.Only MultiGetHandle - // supports multiple gets. + // methods on the table during a callback is not supported. // Get methods return true on found item with LOOKUP_FUNC and FOUND_FUNC is // called. @@ -538,18 +537,6 @@ class ConcurrentHashTable : public CHeapObj { // Must be done at a safepoint. void rehash_nodes_to(Thread* thread, ConcurrentHashTable* to_cht); - // Scoped multi getter. - class MultiGetHandle : private ScopedCS { - public: - MultiGetHandle(Thread* thread, ConcurrentHashTable* cht) - : ScopedCS(thread, cht) {} - // In the MultiGetHandle scope you can lookup items matching LOOKUP_FUNC. - // The VALUEs are safe as long as you never save the VALUEs outside the - // scope, e.g. after ~MultiGetHandle(). - template - VALUE* get(LOOKUP_FUNC& lookup_f, bool* grow_hint = nullptr); - }; - private: class BucketsOperation; diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index 908405d3617..eeaff0167b2 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -233,14 +233,6 @@ inline ConcurrentHashTable:: GlobalCounter::critical_section_end(_thread, _cs_context); } -template -template -inline typename CONFIG::Value* ConcurrentHashTable:: - MultiGetHandle::get(LOOKUP_FUNC& lookup_f, bool* grow_hint) -{ - return ScopedCS::_cht->internal_get(ScopedCS::_thread, lookup_f, grow_hint); -} - // HaveDeletables template template diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AES_Crypt.java b/src/java.base/share/classes/com/sun/crypto/provider/AES_Crypt.java index 19dceae01af..27429f6a2fd 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AES_Crypt.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AES_Crypt.java @@ -54,11 +54,11 @@ final class AES_Crypt extends SymmetricCipher { private int rounds; private byte[] prevKey = null; - // Following two attributes are specific to Intrinsics where sessionK is - // used for PPC64, S390, and RISCV64 architectures, whereas K is used for - // everything else. - private int[][] sessionK = null; - private int[] K = null; + // Following attributes are specific to Intrinsics, where sessionKe is the + // unprocessed key that is also used for decryption on PPC64, S390 and + // RISCV64 architectures. Other ones use sessionKd for decryption. + private int[] sessionKe = null; // key for encryption + private int[] sessionKd = null; // preprocessed key for decryption // Round constant private static final int[] RCON = { @@ -904,7 +904,6 @@ final class AES_Crypt extends SymmetricCipher { */ void init(boolean decrypting, String algorithm, byte[] key) throws InvalidKeyException { - int decrypt = decrypting ? 1 : 0; if (!algorithm.equalsIgnoreCase("AES") && !algorithm.equalsIgnoreCase("Rijndael")) { @@ -920,21 +919,25 @@ final class AES_Crypt extends SymmetricCipher { throw new InvalidKeyException("Invalid key length (" + key.length + ")."); } + if (!MessageDigest.isEqual(prevKey, key)) { - if (sessionK == null) { - sessionK = new int[2][]; - } else { - Arrays.fill(sessionK[0], 0); - Arrays.fill(sessionK[1], 0); + if (sessionKe != null) { + Arrays.fill(sessionKe, 0); + } + sessionKe = genRoundKeys(key, rounds); + if (sessionKd != null) { + Arrays.fill(sessionKd, 0); + sessionKd = null; } - sessionK[0] = genRoundKeys(key, rounds); - sessionK[1] = genInvRoundKeys(sessionK[0], rounds); if (prevKey != null) { Arrays.fill(prevKey, (byte) 0); } prevKey = key.clone(); } - K = sessionK[decrypt]; + + if (decrypting && (sessionKd == null)) { + sessionKd = genInvRoundKeys(sessionKe, rounds); + } } /** @@ -1035,6 +1038,7 @@ final class AES_Crypt extends SymmetricCipher { */ @IntrinsicCandidate private void implEncryptBlock(byte[] p, int po, byte[] c, int co) { + int[] K = sessionKe; int ti0, ti1, ti2, ti3; int a0, a1, a2, a3; int w = K.length - WB; @@ -1213,6 +1217,7 @@ final class AES_Crypt extends SymmetricCipher { */ @IntrinsicCandidate private void implDecryptBlock(byte[] c, int co, byte[] p, int po) { + int[] K = sessionKd; int ti0, ti1, ti2, ti3; int a0, a1, a2, a3; diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 52f908c9e98..d7aef113e15 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -117,9 +117,38 @@ import sun.nio.cs.UTF_8; * Unicode code points (i.e., characters), in addition to those for * dealing with Unicode code units (i.e., {@code char} values). * - *

Unless otherwise noted, methods for comparing Strings do not take locale - * into account. The {@link java.text.Collator} class provides methods for - * finer-grain, locale-sensitive String comparison. + *

String comparison and case-insensitive matching + * + *

There are several related ways to compare {@code String} values; choose + * the one whose semantics fit your purpose: + * + *

    + *
  • Exact content equality — {@link #equals(Object)} checks that two + * strings contain the identical char sequence of UTF-16 code units. This is + * a strict, case-sensitive comparison suitable for exact matching, hashing + * and any situation that requires bit-for-bit stability.
  • + * + *
  • Simple case-insensitive equality — {@link #equalsIgnoreCase(String)} + * (and the corresponding {@link #compareToIgnoreCase(String)} and {@link #CASE_INSENSITIVE_ORDER}) + * performs a per-code-point, locale-independent comparison using + * {@link Character#toUpperCase(int)} and {@link Character#toLowerCase(int)}. + * It is convenient for many common case-insensitive checks.
  • + * + *
  • Unicode case-folded equivalence — {@link #equalsFoldCase(String)} + * (and the corresponding {@link #compareToFoldCase(String)} and {@link #UNICODE_CASEFOLD_ORDER}) + * implement the Unicode {@index "full case folding"} rules defined in + * Unicode CaseFolding.txt. + * Case folding is locale-independent and language-neutral and may map a single code + * point to multiple code points (1:M mappings). For example, the German sharp + * s ({@code U+00DF}) is folded to the sequence {@code "ss"}. + * Use these methods when you need Unicode-compliant + * + * caseless matching, searching, or ordering.
  • + *
+ * + *

Unless otherwise noted, methods for comparing Strings do not take locale into + * account. The {@link java.text.Collator} class provides methods for finer-grain, + * locale-sensitive String comparison. * * @implNote The implementation of the string concatenation operator is left to * the discretion of a Java compiler, as long as the compiler ultimately conforms @@ -2179,6 +2208,7 @@ public final class String * false} otherwise * * @see #equals(Object) + * @see #equalsFoldCase(String) * @see #codePoints() */ public boolean equalsIgnoreCase(String anotherString) { @@ -2188,6 +2218,57 @@ public final class String && regionMatches(true, 0, anotherString, 0, length()); } + /** + * Compares this {@code String} to another {@code String} for equality, + * using {@index "Unicode case folding"}. Two strings are considered equal + * by this method if their case-folded forms are identical. + *

+ * Case folding is defined by the Unicode Standard in + * CaseFolding.txt, + * including 1:M mappings. For example, {@code "Fuß".equalsFoldCase("FUSS")} + * returns {@code true}, since the character {@code U+00DF} (sharp s) folds + * to {@code "ss"}. + *

+ * Case folding is locale-independent and language-neutral, unlike + * locale-sensitive transformations such as {@link #toLowerCase()} or + * {@link #toUpperCase()}. It is intended for caseless matching, + * searching, and indexing. + * + * @apiNote + * This method is the Unicode-compliant alternative to + * {@link #equalsIgnoreCase(String)}. It implements full case folding as + * defined by the Unicode Standard, which may differ from the simpler + * per-character mapping performed by {@code equalsIgnoreCase}. + * For example: + * {@snippet lang=java : + * String a = "Fuß"; + * String b = "FUSS"; + * boolean equalsFoldCase = a.equalsFoldCase(b); // returns true + * boolean equalsIgnoreCase = a.equalsIgnoreCase(b); // returns false + * } + * + * @param anotherString + * The {@code String} to compare this {@code String} against + * + * @return {@code true} if the given object is not {@code null} and represents + * the same sequence of characters as this string under Unicode case + * folding; {@code false} otherwise. + * + * @spec https://www.unicode.org/versions/latest/core-spec/chapter-5/#G21790 Unicode Caseless Matching + * @see #compareToFoldCase(String) + * @see #equalsIgnoreCase(String) + * @since 26 + */ + public boolean equalsFoldCase(String anotherString) { + if (this == anotherString) { + return true; + } + if (anotherString == null) { + return false; + } + return UNICODE_CASEFOLD_ORDER.compare(this, anotherString) == 0; + } + /** * Compares two strings lexicographically. * The comparison is based on the Unicode value of each character in @@ -2303,12 +2384,86 @@ public final class String * than this String, ignoring case considerations. * @see java.text.Collator * @see #codePoints() + * @see #compareToFoldCase(String) * @since 1.2 */ public int compareToIgnoreCase(String str) { return CASE_INSENSITIVE_ORDER.compare(this, str); } + /** + * A Comparator that orders {@code String} objects as by + * {@link #compareToFoldCase(String) compareToFoldCase()}. + * + * @see #compareToFoldCase(String) + * @since 26 + */ + public static final Comparator UNICODE_CASEFOLD_ORDER + = new FoldCaseComparator(); + + private static class FoldCaseComparator implements Comparator { + + @Override + public int compare(String s1, String s2) { + byte[] v1 = s1.value; + byte[] v2 = s2.value; + if (s1.coder == s2.coder()) { + return s1.coder == LATIN1 ? StringLatin1.compareToFC(v1, v2) + : StringUTF16.compareToFC(v1, v2); + } + return s1.coder == LATIN1 ? StringLatin1.compareToFC_UTF16(v1, v2) + : StringUTF16.compareToFC_Latin1(v1, v2); + } + } + + /** + * Compares two strings lexicographically using {@index "Unicode case folding"}. + * This method returns an integer whose sign is that of calling {@code compareTo} + * on the Unicode case folded version of the strings. Unicode Case folding + * eliminates differences in case according to the Unicode Standard, using the + * mappings defined in + * CaseFolding.txt, + * including 1:M mappings, such as {@code"ß"} → {@code }"ss"}. + *

+ * Case folding is a locale-independent, language-neutral form of case mapping, + * primarily intended for caseless matching. Unlike {@link #compareToIgnoreCase(String)}, + * which applies a simpler locale-insensitive uppercase mapping. This method + * follows the Unicode {@index "full"} case folding, providing stable and + * consistent results across all environments. + *

+ * Note that this method does not take locale into account, and may + * produce results that differ from locale-sensitive ordering. Use + * {@link java.text.Collator} for locale-sensitive comparison. + * + * @apiNote + * This method is the Unicode-compliant alternative to + * {@link #compareToIgnoreCase(String)}. It implements the + * {@index "full case folding"} as defined by the Unicode Standard, which + * may differ from the simpler per-character mapping performed by + * {@code compareToIgnoreCase}. + * For example: + * {@snippet lang=java : + * String a = "Fuß"; + * String b = "FUSS"; + * int cmpFoldCase = a.compareToFoldCase(b); // returns 0 + * int cmpIgnoreCase = a.compareToIgnoreCase(b); // returns > 0 + * } + * + * @param str the {@code String} to be compared. + * @return a negative integer, zero, or a positive integer as the specified + * String is greater than, equal to, or less than this String, + * ignoring case considerations by case folding. + * + * @spec https://www.unicode.org/versions/latest/core-spec/chapter-5/#G21790 Unicode Caseless Matching + * @see java.text.Collator + * @see #compareToIgnoreCase(String) + * @see #equalsFoldCase(String) + * @since 26 + */ + public int compareToFoldCase(String str) { + return UNICODE_CASEFOLD_ORDER.compare(this, str); + } + /** * Tests if two string regions are equal. *

diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index 61c62d049bc..21a8b2dd61a 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -32,6 +32,8 @@ import java.util.function.Consumer; import java.util.function.IntConsumer; import java.util.stream.Stream; import java.util.stream.StreamSupport; + +import jdk.internal.lang.CaseFolding; import jdk.internal.util.ArraysSupport; import jdk.internal.vm.annotation.IntrinsicCandidate; @@ -179,6 +181,128 @@ final class StringLatin1 { return len1 - len2; } + private static int compareToFC0(byte[] value, int off, int last, byte[] other, int ooff, int olast) { + int k1 = off, k2 = ooff; + boolean lo1 = false, lo2 = false; // true if we have a leftover 's' from u+00df -> ss + while ((k1 < last || lo1) && (k2 < olast || lo2)) { + int c1, c2; + if (lo1) { + c1 = 0x73; // leftover 's' + lo1 = false; + } else { + c1 = getChar(value, k1++); + if (c1 == 0xdf) { + c1 = 0x73; + lo1 = true; + } + } + if (lo2) { + c2 = 0x73; // 's' + lo2 = false; + } else { + c2 = getChar(other, k2++); + if (c2 == 0xdf) { + c2 = 0x73; + lo2 = true; + } + } + if (!CharacterDataLatin1.equalsIgnoreCase((byte)c1, (byte)c2)) { + return Character.toLowerCase(c1) - Character.toLowerCase(c2); + } + } + if (k1 < last || lo1) { + return 1; + } + if (k2 < olast || lo2) { + return -1; + } + return 0; + } + + static int compareToFC(byte[] value, byte[] other) { + int len = value.length; + int olen = other.length; + int lim = Math.min(len, olen); + for (int k = 0; k < lim; k++) { + byte b1 = value[k]; + byte b2 = other[k]; + if (!CharacterDataLatin1.equalsIgnoreCase(b1, b2)) { + int c1 = b1 & 0xff; + int c2 = b2 & 0xff; + if (c1 == 0xdf || c2 == 0xdf) { // 0xdf is the only 1:M in latin1 range + return compareToFC0(value, k, len, other, k, olen); + } + return Character.toLowerCase(c1) - Character.toLowerCase(c2); + } + } + return len - olen; + } + + private static int compareToFC0_UTF16(byte[] value, int off, int last, byte[] other, int ooff, int olast) { + int f1 = 0, f2 = 0; + int k1 = off, k2 = ooff; + while ((k1 < last || f1 != 0) && (k2 < olast || f2 != 0)) { + int c1, c2; + if (f1 != 0) { + c1 = (f1 & 0xffff); f1 >>>= 16; + } else { + c1 = getChar(value, k1++); + var f = CaseFolding.fold(c1); + if (CaseFolding.isSingleCodePoint(f)) { + c1 = (int)(f & 0xfffff); + } else { + c1 = (int)f & 0xffff; + f1 = (int)(f >>> 16); + } + } + if (f2 != 0) { + c2 = f2 & 0xffff; f2 >>>= 16; + } else { + c2 = StringUTF16.codePointAt(other, k2, olast, true); + k2 += Character.charCount(c2); + var f = CaseFolding.fold(c2); + if (CaseFolding.isSingleCodePoint(f)) { + c2 = (int)(f & 0xfffff); + } else { + c2 = (int)(f & 0xffff); + f2 = (int)(f >>> 16); + } + } + if (c1 != c2) { + return c1 - c2; + } + } + if (k1 < last || f1 != 0) { + return 1; + } + if (k2 < olast || f2 != 0) { + return -1; + } + return 0; + } + + // latin1 vs utf16 + static int compareToFC_UTF16(byte[] value, byte[] other) { + int last = length(value); + int olast = StringUTF16.length(other); + int lim = Math.min(last, olast); + for (int k = 0; k < lim; k++) { + int cp1 = getChar(value, k); + int cp2 = StringUTF16.codePointAt(other, k, olast, true); + if (cp1 != cp2) { + long cf1 = CaseFolding.fold(cp1); + long cf2 = CaseFolding.fold(cp2); + if (cf1 != cf2) { + if (!CaseFolding.isSingleCodePoint(cf1) || !CaseFolding.isSingleCodePoint(cf2)) { + return compareToFC0_UTF16(value, k, last, other, k, olast); + } + return (int)(cf1 - cf2); + } + } + } + return last - olast; + } + static int hashCode(byte[] value) { return ArraysSupport.hashCodeOfUnsigned(value, 0, value.length, 0); } diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 4e31c9728e9..75c9e8239ba 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -34,6 +34,7 @@ import java.util.function.IntConsumer; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jdk.internal.lang.CaseFolding; import jdk.internal.misc.Unsafe; import jdk.internal.util.ArraysSupport; import jdk.internal.vm.annotation.ForceInline; @@ -93,7 +94,7 @@ final class StringUTF16 { return value.length >> 1; } - private static int codePointAt(byte[] value, int index, int end, boolean checked) { + static int codePointAt(byte[] value, int index, int end, boolean checked) { assert index < end; if (checked) { checkIndex(index, value); @@ -592,6 +593,77 @@ final class StringUTF16 { return -StringLatin1.compareToCI_UTF16(other, value); } + public static int compareToFC_Latin1(byte[] value, byte[] other) { + return -StringLatin1.compareToFC_UTF16(other, value); + } + + private static int compareToFC0(byte[] value, int off, int last, byte[] other, int ooff, int olast) { + int f1 = 0, f2 = 0; + int k1 = off, k2 = ooff; + while ((k1 < last || f1 != 0) && (k2 < olast || f2 != 0)) { + int c1, c2; + if (f1 != 0) { + c1 = f1 & 0xffff; f1 >>>= 16; + } else { + c1 = StringUTF16.codePointAt(value, k1, last, true); + k1 += Character.charCount(c1); + var f = CaseFolding.fold(c1); + if (CaseFolding.isSingleCodePoint(f)) { + c1 = (int)(f & 0xfffff); + } else { + c1 = (int)(f & 0xffff); + f1 = (int)(f >> 16); + } + } + if (f2 != 0) { + c2 = f2 & 0xffff; f2 >>>= 16; + } else { + c2 = StringUTF16.codePointAt(other, k2, olast, true); + k2 += Character.charCount(c2); + var f = CaseFolding.fold(c2); + if (CaseFolding.isSingleCodePoint(f)) { + c2 = (int)(f & 0xfffff); + } else { + c2 = (int)(f & 0xffff); + f2 = (int)(f >>> 16); + } + } + if (c1 != c2) { + return c1 - c2; + } + } + if (k1 < last || f1 != 0) { + return 1; + } + if (k2 < olast || f2 != 0) { + return -1; + } + return 0; + } + + public static int compareToFC(byte[] value, byte[] other) { + int tlast = length(value); + int olast = length(other); + int lim = Math.min(tlast, olast); + int k = 0; + while (k < lim) { + int cp1 = codePointAt(value, k, tlast, true); + int cp2 = codePointAt(other, k, olast, true); + if (cp1 != cp2) { + long cf1 = CaseFolding.fold(cp1); + long cf2 = CaseFolding.fold(cp2); + if (cf1 != cf2) { + if (!CaseFolding.isSingleCodePoint(cf1) || !CaseFolding.isSingleCodePoint(cf2)) { + return compareToFC0(value, k, tlast, other, k, olast); + } + return (int) cf1 - (int) cf2; + } + } + k += Character.charCount(cp1); + } + return tlast - olast; + } + static int hashCode(byte[] value) { return ArraysSupport.hashCodeOfUTF16(value, 0, value.length >> 1, 0); } diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 51543f835c1..514bf07e665 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -246,11 +246,11 @@ final class VirtualThread extends BaseVirtualThread { @Hidden @JvmtiHideEvents public void run() { - vthread.notifyJvmtiStart(); // notify JVMTI + vthread.endFirstTransition(); try { vthread.run(task); } finally { - vthread.notifyJvmtiEnd(); // notify JVMTI + vthread.startFinalTransition(); } } }; @@ -491,8 +491,9 @@ final class VirtualThread extends BaseVirtualThread { @ChangesCurrentThread @ReservedStackAccess private void mount() { - // notify JVMTI before mount - notifyJvmtiMount(/*hide*/true); + startTransition(/*is_mount*/true); + // We assume following volatile accesses provide equivalent + // of acquire ordering, otherwise we need U.loadFence() here. // sets the carrier thread Thread carrier = Thread.currentCarrierThread(); @@ -533,8 +534,9 @@ final class VirtualThread extends BaseVirtualThread { } carrier.clearInterrupt(); - // notify JVMTI after unmount - notifyJvmtiUnmount(/*hide*/false); + // We assume previous volatile accesses provide equivalent + // of release ordering, otherwise we need U.storeFence() here. + endTransition(/*is_mount*/false); } /** @@ -543,11 +545,11 @@ final class VirtualThread extends BaseVirtualThread { */ @Hidden private boolean yieldContinuation() { - notifyJvmtiUnmount(/*hide*/true); + startTransition(/*is_mount*/false); try { return Continuation.yield(VTHREAD_SCOPE); } finally { - notifyJvmtiMount(/*hide*/false); + endTransition(/*is_mount*/true); } } @@ -1401,23 +1403,34 @@ final class VirtualThread extends BaseVirtualThread { this.carrierThread = carrier; } - // -- JVM TI support -- + // The following four methods notify the VM when a "transition" starts and ends. + // A "mount transition" embodies the steps to transfer control from a platform + // thread to a virtual thread, changing the thread identity, and starting or + // resuming the virtual thread's continuation on the carrier. + // An "unmount transition" embodies the steps to transfer control from a virtual + // thread to its carrier, suspending the virtual thread's continuation, and + // restoring the thread identity to the platform thread. + // The notifications to the VM are necessary in order to coordinate with functions + // (JVMTI mostly) that disable transitions for one or all virtual threads. Starting + // a transition may block if transitions are disabled. Ending a transition may + // notify a thread that is waiting to disable transitions. The notifications are + // also used to post JVMTI events for virtual thread start and end. @IntrinsicCandidate @JvmtiMountTransition - private native void notifyJvmtiStart(); + private native void endFirstTransition(); @IntrinsicCandidate @JvmtiMountTransition - private native void notifyJvmtiEnd(); + private native void startFinalTransition(); @IntrinsicCandidate @JvmtiMountTransition - private native void notifyJvmtiMount(boolean hide); + private native void startTransition(boolean is_mount); @IntrinsicCandidate @JvmtiMountTransition - private native void notifyJvmtiUnmount(boolean hide); + private native void endTransition(boolean is_mount); @IntrinsicCandidate private static native void notifyJvmtiDisableSuspend(boolean enter); diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFile.java b/src/java.base/share/classes/java/lang/classfile/ClassFile.java index 216facbdddf..5a2b7e6297e 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFile.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFile.java @@ -1038,6 +1038,14 @@ public sealed interface ClassFile */ int JAVA_26_VERSION = 70; + /** + * The class major version introduced by Java SE 27, {@value}. + * + * @see ClassFileFormatVersion#RELEASE_27 + * @since 27 + */ + int JAVA_27_VERSION = 71; + /** * A minor version number {@value} indicating a class uses preview features * of a Java SE release since 12, for major versions {@value @@ -1049,7 +1057,7 @@ public sealed interface ClassFile * {@return the latest class major version supported by the current runtime} */ static int latestMajorVersion() { - return JAVA_26_VERSION; + return JAVA_27_VERSION; } /** diff --git a/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java b/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java index 16fe000091c..1990a467b60 100644 --- a/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java +++ b/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java @@ -379,10 +379,22 @@ public enum ClassFileFormatVersion { * @since 26 * * @see + * href="https://docs.oracle.com/en/java/javase/26/docs/specs/jvms/index.html"> * The Java Virtual Machine Specification, Java SE 26 Edition */ RELEASE_26(70), + + /** + * The version introduced by the Java Platform, Standard Edition + * 27. + * + * @since 27 + * + * @see + * The Java Virtual Machine Specification, Java SE 27 Edition + */ + RELEASE_27(71), ; // Reduce code churn when appending new constants // Note to maintainers: when adding constants for newer releases, @@ -398,7 +410,7 @@ public enum ClassFileFormatVersion { * {@return the latest class file format version} */ public static ClassFileFormatVersion latest() { - return RELEASE_26; + return RELEASE_27; } /** diff --git a/src/java.base/share/classes/java/lang/reflect/Field.java b/src/java.base/share/classes/java/lang/reflect/Field.java index 663e3453343..a4f0afa0199 100644 --- a/src/java.base/share/classes/java/lang/reflect/Field.java +++ b/src/java.base/share/classes/java/lang/reflect/Field.java @@ -367,7 +367,7 @@ class Field extends AccessibleObject implements Member { * @jls 8.3.1 Field Modifiers */ public String toString() { - int mod = getModifiers(); + int mod = getModifiers() & Modifier.fieldModifiers(); return (((mod == 0) ? "" : (Modifier.toString(mod) + " ")) + getType().getTypeName() + " " + getDeclaringClass().getTypeName() + "." @@ -400,7 +400,7 @@ class Field extends AccessibleObject implements Member { * @jls 8.3.1 Field Modifiers */ public String toGenericString() { - int mod = getModifiers(); + int mod = getModifiers() & Modifier.fieldModifiers(); Type fieldType = getGenericType(); return (((mod == 0) ? "" : (Modifier.toString(mod) + " ")) + fieldType.getTypeName() + " " diff --git a/src/java.base/share/classes/java/lang/reflect/Parameter.java b/src/java.base/share/classes/java/lang/reflect/Parameter.java index d4a53e193a9..8ecf8060615 100644 --- a/src/java.base/share/classes/java/lang/reflect/Parameter.java +++ b/src/java.base/share/classes/java/lang/reflect/Parameter.java @@ -126,7 +126,7 @@ public final class Parameter implements AnnotatedElement { final Type type = getParameterizedType(); final String typename = type.getTypeName(); - sb.append(Modifier.toString(getModifiers())); + sb.append(Modifier.toString(getModifiers() & Modifier.parameterModifiers() )); if(0 != modifiers) sb.append(' '); diff --git a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java index 029e31ef9f6..b45b6eac83e 100644 --- a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java +++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java @@ -1426,23 +1426,6 @@ public class ThreadPoolExecutor extends AbstractExecutorService { } } - // Override without "throws Throwable" for compatibility with subclasses - // whose finalize method invokes super.finalize() (as is recommended). - // Before JDK 11, finalize() had a non-empty method body. - - /** - * @implNote Previous versions of this class had a finalize method - * that shut down this executor, but in this version, finalize - * does nothing. - * - * @deprecated Finalization has been deprecated for removal. See - * {@link java.lang.Object#finalize} for background information and details - * about migration options. - */ - @Deprecated(since="9", forRemoval=true) - @SuppressWarnings("removal") - protected void finalize() {} - /** * Sets the thread factory used to create new threads. * diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index dc2d65bcc99..d1a8f1310a9 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -27,7 +27,6 @@ package java.util.jar; import jdk.internal.access.SharedSecrets; import jdk.internal.access.JavaUtilZipFileAccess; -import jdk.internal.misc.ThreadTracker; import sun.security.util.ManifestEntryVerifier; import sun.security.util.SignatureFileVerifier; @@ -213,6 +212,9 @@ public class JarFile extends ZipFile { */ static final String INDEX_NAME = "META-INF/INDEX.LIST"; + // this will be set when the thread is initializing a JAR verifier + private static final ScopedValue IN_VERIFIER_INIT = ScopedValue.newInstance(); + /** * Returns the version that represents the unversioned configuration of a * multi-release jar file. @@ -1025,36 +1027,30 @@ public class JarFile extends ZipFile { } } - private static class ThreadTrackHolder { - static final ThreadTracker TRACKER = new ThreadTracker(); - } - - private static Object beginInit() { - return ThreadTrackHolder.TRACKER.begin(); - } - - private static void endInit(Object key) { - ThreadTrackHolder.TRACKER.end(key); - } - synchronized void ensureInitialization() { try { maybeInstantiateVerifier(); } catch (IOException e) { throw new RuntimeException(e); } - if (jv != null && !jvInitialized) { - Object key = beginInit(); - try { + if (jv == null || jvInitialized) { + return; + } + // mark the current thread as initializing + // the JAR verifier + ScopedValue.where(IN_VERIFIER_INIT, true).run(new Runnable() { + @Override + public void run() { initializeVerifier(); jvInitialized = true; - } finally { - endInit(key); } - } + }); } + /** + * {@return true if the current thread is initializing a JAR verifier, false otherwise} + */ static boolean isInitializing() { - return ThreadTrackHolder.TRACKER.contains(Thread.currentThread()); + return IN_VERIFIER_INIT.isBound(); } } diff --git a/src/java.base/share/classes/java/util/regex/Pattern.java b/src/java.base/share/classes/java/util/regex/Pattern.java index 2908370acd5..58c9186924b 100644 --- a/src/java.base/share/classes/java/util/regex/Pattern.java +++ b/src/java.base/share/classes/java/util/regex/Pattern.java @@ -43,8 +43,8 @@ import java.util.function.Predicate; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jdk.internal.lang.CaseFolding; import jdk.internal.util.ArraysSupport; -import jdk.internal.util.regex.CaseFolding; import jdk.internal.util.regex.Grapheme; /** diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index d7636032c28..a0c8a0a5a4f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -33,6 +33,7 @@ import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import jdk.internal.util.ArraysSupport; import jdk.internal.util.Preconditions; +import jdk.internal.vm.annotation.DontInline; import jdk.internal.vm.annotation.ForceInline; import sun.nio.ch.DirectBuffer; @@ -68,7 +69,7 @@ import java.util.stream.StreamSupport; * {@link MappedMemorySegmentImpl}. */ public abstract sealed class AbstractMemorySegmentImpl - implements MemorySegment, SegmentAllocator, BiFunction, RuntimeException> + implements MemorySegment, SegmentAllocator permits HeapMemorySegmentImpl, NativeMemorySegmentImpl { static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess(); @@ -100,19 +101,19 @@ public abstract sealed class AbstractMemorySegmentImpl @Override public AbstractMemorySegmentImpl asSlice(long offset, long newSize) { - checkBounds(offset, newSize); + checkSliceBounds(offset, newSize); return asSliceNoCheck(offset, newSize); } @Override public AbstractMemorySegmentImpl asSlice(long offset) { - checkBounds(offset, 0); + checkSliceBounds(offset, 0); return asSliceNoCheck(offset, length - offset); } @Override public MemorySegment asSlice(long offset, long newSize, long byteAlignment) { - checkBounds(offset, newSize); + checkSliceBounds(offset, newSize); Utils.checkAlign(byteAlignment); if (!isAlignedForElement(offset, byteAlignment)) { @@ -354,7 +355,7 @@ public abstract sealed class AbstractMemorySegmentImpl @ForceInline public void checkAccess(long offset, long length, boolean readOnly) { checkReadOnly(readOnly); - checkBounds(offset, length); + checkAccessBounds(offset, length); } @ForceInline @@ -398,20 +399,40 @@ public abstract sealed class AbstractMemorySegmentImpl } @ForceInline - void checkBounds(long offset, long length) { - if (length > 0) { - Preconditions.checkIndex(offset, this.length - length + 1, this); - } else if (length < 0 || offset < 0 || - offset > this.length - length) { - throw outOfBoundException(offset, length); + void checkSliceBounds(long offset, long length) { + try { + checkBounds(offset, length); + } catch (IndexOutOfBoundsException e) { + throwOutOfBounds(offset, length, /* isSlice = */ true); } } - @Override - public RuntimeException apply(String s, List numbers) { - long offset = numbers.get(0).longValue(); - long length = byteSize() - numbers.get(1).longValue() + 1; - return outOfBoundException(offset, length); + @ForceInline + void checkAccessBounds(long offset, long length) { + try { + checkBounds(offset, length); + } catch (IndexOutOfBoundsException e) { + throwOutOfBounds(offset, length, /* isSlice = */ false); + } + } + + @ForceInline + private void checkBounds(long offset, long length) { + if (length > 0) { + Preconditions.checkIndex(offset, this.length - length + 1, null); + } else if (length < 0 || offset < 0 || + offset > this.length - length) { + throw new IndexOutOfBoundsException(); + } + } + + @DontInline + private void throwOutOfBounds(long offset, long length, boolean isSlice) { + String action = isSlice ? "get slice" : "access an element"; + String msg = String.format("Out of bound access on segment %s; attempting to %s of length %d at offset %d " + + "which is outside the valid range 0 <= offset+length < byteSize (=%d)", + this, action, length, offset, this.length); + throw new IndexOutOfBoundsException(msg); } @Override @@ -429,11 +450,6 @@ public abstract sealed class AbstractMemorySegmentImpl return scope; } - private IndexOutOfBoundsException outOfBoundException(long offset, long length) { - return new IndexOutOfBoundsException(String.format("Out of bound access on segment %s; new offset = %d; new length = %d", - this, offset, length)); - } - static class SegmentSplitter implements Spliterator { AbstractMemorySegmentImpl segment; long elemCount; diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java index 5af4bc37692..ab6b78b73ee 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java @@ -194,7 +194,7 @@ public final class SegmentBulkOperations { @ForceInline public static int contentHash(AbstractMemorySegmentImpl segment, long fromOffset, long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length == 0) { // The state has to be checked explicitly for zero-length segments segment.scope.checkValidState(); diff --git a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java index bb6cb2d3915..208c6d54aab 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java +++ b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java @@ -145,7 +145,7 @@ public final class StringSupport { final long fromOffset, final long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length < Byte.BYTES) { // There can be no null terminator present segment.scope.checkValidState(); @@ -179,7 +179,7 @@ public final class StringSupport { final long fromOffset, final long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length < Short.BYTES) { // There can be no null terminator present segment.scope.checkValidState(); @@ -215,7 +215,7 @@ public final class StringSupport { final long fromOffset, final long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length < Integer.BYTES) { // There can be no null terminator present segment.scope.checkValidState(); diff --git a/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template b/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template new file mode 100644 index 00000000000..24a183c8da0 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/lang/CaseFolding.java.template @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.lang; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static java.util.Map.entry; + +/** + * Utility class that handles Unicode case folding properties defined in + * CasingFolding.txt, including 1:M full case folding. + */ +public final class CaseFolding { + + private CaseFolding() {} + + /** + * Tests whether the specified code point has a folding mapping entry defined. + * + * @param cp + * the Unicode code point to test + * @return {@code true} if the given code point has a case folding mapping entry + * defined in (@code caseFoldingMap}, {@code false} otherwise + */ + public static boolean isDefined(int cp) { + return getDefined(cp) != -1; + } + + /** + * Returns the case-folded form of the specified code point according + * to the Unicode case folding mappings. + *

+ * If the code point has no case folding mapping defined, this method returns + * the original code point. + * + * Possible combinations of the returning case-folding form as a long value + * + * +---+---------+--------+---------+--------+--------+ + * | 1:1 mapping | 0000 | 0000 | 000x | xxxx | 0041 => 0061 or 1E921 => 1E943 + * +---+---------+--------+---------+--------+--------+ + * | 1:2 mapping | 0002 | 0000 | xxxx | xxxx | FB02 => 0066 006C + * +---+---------+--------+---------+--------+--------+ + * | 1:3 mapping | 0003 | xxxx | xxxx | xxxx | FB03 => 0066 0066 0069 + * +---+---------+--------+---------+--------+--------+ + * + * @param cp + * the Unicode code point to fold + * @return a long value representing the case-folded form of the input + * code point, encoded as TBD + */ + public static long fold(int cp) { + var fold = getDefined(cp); + return fold == -1 ? cp : fold; + } + + public static boolean isSingleCodePoint(long fold) { + return (fold >> 48) == 0; + } + + /** + * Returns an expansion set to "close" a given regex Unicode character class range for case-sensitive + * matching, according to the + * Simple Loose Matches + * rule defined in Unicode Technical Standard #18: Unicode Regular Expressions. + *

+ * To conform with Level 1 of UTS #18, specifically RL1.5: Simple Loose Matches, simple case folding must + * be applied to literals and (optionally) to character classes. When applied to character classes, each + * character class is expected to be closed under simple case folding. See the standard for the + * detailed explanation and example of "closed". + *

+ * RL1.5 states: To meet this requirement, an implementation that supports case-sensitive matching should + *

    + *
  1. Provide at least the simple, default Unicode case-insensitive matching, and
  2. + *
  3. Specify which character properties or constructs are closed under the matching.
  4. + *
+ *

+ * In the {@code Pattern} implementation, 5 types of constructs maybe case-sensitive when matching: + * back-refs, string slice (sequences), single, family(char-property) and class range. Single and + * family may appears independently or within a class. + *

+ * For loose/case-insensitive matching, the back-refs, slices and singles apply {@code toUpperCase} and + * {@code toLowerCase} to both the pattern and the input string. This effectively 'close' the class for + * matching. + *

+ * The family/char-properties are not "closed" and should remain unchanged. This is acceptable per RL1.5, + * if their behavior is clearly specified. + *

+ * This method addresses that requirement for the "range" construct within in character class by computing + * the additional characters that should be included to close the range under simple case folding: + *

+ * For each character in the input range {@code [start, end]} (inclusive), if the character has a simple + * case folding mapping in Unicode's CaseFolding.txt, the mapping is not a round-trip map, and the mapped + * character is not already in the range, then that mapped character (typically lowercase) is added to + * the expansion set. + *

+ * This allows regex character class "range" implementation to use the returned expansion set to support + * additional case-insensitive matching, without duplicating characters already covered by the existing + * regex range implementation. The expectation is the matching is done using both the uppercase and + * lowercase forms of the input character, for example + * + *

{@code
+    *
+    *     ch -> inRange(lower, Character.toUpperCase(ch), upper) ||
+    *           inRange(lower, Character.toLower(ch), upper) ||
+    *           additionalClosingCharacters.contains(Character.toUpperCase(ch)) ||
+    *           additionalClosingCharacters.contains(Character.toUpperCase(ch))
+    * }
+ * + * @param start the starting code point of the character range + * @param end the ending code point of the character range + * @return a {@code int[]} containing the all simple case equivalents of characters in the range, excluding + * those already in the range + * @spec https://www.unicode.org/reports/tr18/#Simple_Loose_Matches + */ + public static int[] getClassRangeClosingCharacters(int start, int end) { + int[] expanded = new int[expanded_case_cps.length]; + int off = 0; + for (int cp : expanded_case_cps) { + if (cp >= start && cp <= end) { + int folding = expanded_case_map.get(cp); + if (folding < start || folding > end) { + expanded[off++] = folding; + } + } + } + return Arrays.copyOf(expanded, off); + } + + private static final Map expanded_case_map = Map.ofEntries( +%%%Expanded_Case_Map_Entries + ); + + private static final int[] expanded_case_cps = expanded_case_map.keySet() + .stream() + .mapToInt(Integer::intValue) + .toArray(); + + private static final int HASH_CP = 0; + private static final int HASH_INDEX = 1; + private static final int HASH_NEXT = 2; + + private static int[][] hashKeys(int[] keys) { + var hashes = new int[keys.length << 1][3]; // cp + hash + next + var off = keys.length; + for (int i = 0; i < keys.length; i++) { + var cp = keys[i]; + var hash = cp % keys.length; + while (hashes[hash][HASH_CP] != 0) { + var next = hashes[hash][HASH_NEXT]; + if (next == 0) { + hashes[hash][HASH_NEXT] = off; + hash = off++; + break; + } else { + hash = next; + } + } + hashes[hash][HASH_CP] = cp; + hashes[hash][HASH_INDEX] = i; + } + return Arrays.copyOf(hashes, off); + } + + private static long getDefined(int cp) { + var hashes = CASE_FOLDING_HASHES; + var length = CASE_FOLDING_CPS.length; // hashed based on total defined. + var hash = cp % length; + while (hashes[hash][HASH_CP] != cp) { + var next = hashes[hash][HASH_NEXT]; + if (next == 0) { + return -1; // hash miss + } + hash = next; + } + var index = hashes[hash][HASH_INDEX]; + return CASE_FOLDING_VALUES[index]; + } + +%%%Entries + + private static final int[][] CASE_FOLDING_HASHES = hashKeys(CASE_FOLDING_CPS); +} diff --git a/src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template b/src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template new file mode 100644 index 00000000000..2d46f8f0e60 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/misc/resources/release.txt.template @@ -0,0 +1 @@ +@@COMPANY_NAME@@-@@VERSION_STRING@@-@@VERSION_DATE@@ diff --git a/src/java.base/share/classes/jdk/internal/util/regex/CaseFolding.java.template b/src/java.base/share/classes/jdk/internal/util/regex/CaseFolding.java.template deleted file mode 100644 index 8ffbde6c535..00000000000 --- a/src/java.base/share/classes/jdk/internal/util/regex/CaseFolding.java.template +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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.util.regex; - -import java.util.Arrays; -import java.util.Map; -import java.util.Objects; - -import static java.util.Map.entry; - -public final class CaseFolding { - - private static final Map expanded_case_map = Map.ofEntries( -%%%Entries - ); - - private static final int[] expanded_case_cps = expanded_case_map.keySet() - .stream() - .mapToInt(Integer::intValue) - .toArray(); - - private CaseFolding() {} - - /** - * Returns an expansion set to "close" a given regex Unicode character class range for case-sensitive - * matching, according to the - * Simple Loose Matches - * rule defined in Unicode Technical Standard #18: Unicode Regular Expressions. - *

- * To conform with Level 1 of UTS #18, specifically RL1.5: Simple Loose Matches, simple case folding must - * be applied to literals and (optionally) to character classes. When applied to character classes, each - * character class is expected to be closed under simple case folding. See the standard for the - * detailed explanation and example of "closed". - *

- * RL1.5 states: To meet this requirement, an implementation that supports case-sensitive matching should - *

    - *
  1. Provide at least the simple, default Unicode case-insensitive matching, and
  2. - *
  3. Specify which character properties or constructs are closed under the matching.
  4. - *
- *

- * In the {@code Pattern} implementation, 5 types of constructs maybe case-sensitive when matching: - * back-refs, string slice (sequences), single, family(char-property) and class range. Single and - * family may appears independently or within a class. - *

- * For loose/case-insensitive matching, the back-refs, slices and singles apply {code toUpperCase} and - * {@code toLowerCase} to both the pattern and the input string. This effectively 'close' the class for - * matching. - *

- * The family/char-properties are not "closed" and should remain unchanged. This is acceptable per RL1.5, - * if their behavior is clearly specified. - *

- * This method addresses that requirement for the "range" construct within in character class by computing - * the additional characters that should be included to close the range under simple case folding: - *

- * For each character in the input range {@code [start, end]} (inclusive), if the character has a simple - * case folding mapping in Unicode's CaseFolding.txt, the mapping is not a round-trip map, and the mapped - * character is not already in the range, then that mapped character (typically lowercase) is added to - * the expansion set. - *

- * This allows regex character class "range" implementation to use the returned expansion set to support - * additional case-insensitive matching, without duplicating characters already covered by the existing - * regex range implementation. The expectation is the matching is done using both the uppercase and - * lowercase forms of the input character, for example - * - *

{@code
-     *
-     *     ch -> inRange(lower, Character.toUpperCase(ch), upper) ||
-     *           inRange(lower, Character.toLower(ch), upper) ||
-     *           additionalClosingCharacters.contains(Character.toUpperCase(ch)) ||
-     *           additionalClosingCharacters.contains(Character.toUpperCase(ch))
-     * }
- * - *

- * @spec https://www.unicode.org/reports/tr18/#Simple_Loose_Matches - * @param start the starting code point of the character range - * @param end the ending code point of the character range - * @return a {@code int[]} containing the all simple case equivalents of characters in the range, excluding - * those already in the range - */ - public static int[] getClassRangeClosingCharacters(int start, int end) { - int[] expanded = new int[expanded_case_cps.length]; - int off = 0; - for (int cp : expanded_case_cps) { - if (cp >= start && cp <= end) { - int folding = expanded_case_map.get(cp); - if (folding < start || folding > end) { - expanded[off++] = folding; - } - } - } - return Arrays.copyOf(expanded, off); - } -} diff --git a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java index 5832e7f529a..57935ff5b00 100644 --- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java @@ -289,6 +289,7 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp */ private int implRead(byte[] b, int off, int len, long remainingNanos) throws IOException { int n = 0; + SocketException ex = null; FileDescriptor fd = beginRead(); try { if (connectionReset) @@ -307,18 +308,24 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp n = tryRead(fd, b, off, len); } } - return n; } catch (InterruptedIOException e) { throw e; } catch (ConnectionResetException e) { connectionReset = true; throw new SocketException("Connection reset"); } catch (IOException ioe) { - // throw SocketException to maintain compatibility - throw asSocketException(ioe); + // translate to SocketException to maintain compatibility + ex = asSocketException(ioe); } finally { endRead(n > 0); } + if (n <= 0 && isInputClosed) { + return -1; + } + if (ex != null) { + throw ex; + } + return n; } /** @@ -411,6 +418,7 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp */ private int implWrite(byte[] b, int off, int len) throws IOException { int n = 0; + SocketException ex = null; FileDescriptor fd = beginWrite(); try { configureNonBlockingIfNeeded(fd, false); @@ -419,15 +427,18 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp park(fd, Net.POLLOUT); n = tryWrite(fd, b, off, len); } - return n; } catch (InterruptedIOException e) { throw e; } catch (IOException ioe) { - // throw SocketException to maintain compatibility - throw asSocketException(ioe); + // translate to SocketException to maintain compatibility + ex = asSocketException(ioe); } finally { endWrite(n > 0); } + if (ex != null) { + throw ex; + } + return n; } /** 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 64c40f28162..82618f9b40e 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: 2025-05-15 +File-Date: 2025-08-25 %% Type: language Subtag: aa @@ -3102,6 +3102,7 @@ Added: 2009-07-29 Type: language Subtag: asb Description: Assiniboine +Description: Nakoda Assiniboine Added: 2009-07-29 %% Type: language @@ -3269,6 +3270,7 @@ Added: 2009-07-29 Type: language Subtag: atj Description: Atikamekw +Description: Nehirowimowin Added: 2009-07-29 %% Type: language @@ -7981,6 +7983,7 @@ Added: 2009-07-29 Type: language Subtag: clc Description: Chilcotin +Description: Tsilhqot’in Added: 2009-07-29 %% Type: language @@ -8021,6 +8024,7 @@ Added: 2009-07-29 %% Type: language Subtag: clm +Description: Klallam Description: Clallam Added: 2009-07-29 %% @@ -13509,7 +13513,7 @@ Added: 2009-07-29 %% Type: language Subtag: haa -Description: Han +Description: Hän Added: 2009-07-29 %% Type: language @@ -19022,6 +19026,7 @@ Added: 2009-07-29 %% Type: language Subtag: kwk +Description: Kwak'wala Description: Kwakiutl Added: 2009-07-29 %% @@ -22262,7 +22267,7 @@ Added: 2009-07-29 %% Type: language Subtag: mhn -Description: Mócheno +Description: Mòcheno Added: 2009-07-29 %% Type: language @@ -31655,6 +31660,7 @@ Added: 2009-07-29 Type: language Subtag: sec Description: Sechelt +Description: She shashishalhem Added: 2009-07-29 %% Type: language @@ -32003,6 +32009,7 @@ Added: 2009-07-29 Type: language Subtag: shs Description: Shuswap +Description: Secwepemctsín Added: 2009-07-29 %% Type: language @@ -33014,6 +33021,7 @@ Added: 2009-07-29 Type: language Subtag: squ Description: Squamish +Description: Sḵwx̱wú7mesh sníchim Added: 2009-07-29 %% Type: language @@ -34664,6 +34672,8 @@ Added: 2009-07-29 Type: language Subtag: thp Description: Thompson +Description: Nłeʔkepmxcín +Description: Thompson River Salish Added: 2009-07-29 %% Type: language @@ -34684,6 +34694,7 @@ Added: 2009-07-29 Type: language Subtag: tht Description: Tahltan +Description: Tāłtān Added: 2009-07-29 %% Type: language @@ -42419,7 +42430,7 @@ Added: 2009-07-29 %% Type: language Subtag: zmp -Description: Mpuono +Description: Mbuun Added: 2009-07-29 %% Type: language @@ -47639,6 +47650,12 @@ Comments: Denotes conventions established by the Academia Brasileira de Letras in 1943 and generally used in Brazil until 2009 %% Type: variant +Subtag: akhmimic +Description: Akhmimic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: akuapem Description: Akuapem Twi Added: 2017-06-05 @@ -47814,6 +47831,12 @@ Comments: Black American Sign Language (BASL) or Black Sign Variation (BSV) is a dialect of American Sign Language (ASL) %% Type: variant +Subtag: bohairic +Description: Bohairic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: bohoric Description: Slovene in Bohorič alphabet Added: 2012-06-27 @@ -47898,6 +47921,12 @@ Comments: Represents the standard written form of Ladin in Fascia which unified the three subvarieties Cazet, Brach and Moenat %% Type: variant +Subtag: fayyumic +Description: Fayyumic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: fodom Description: Fodom standard of Ladin Added: 2024-03-04 @@ -48167,6 +48196,12 @@ Comments: Russian orthography as established by the 1917/1918 orthographic reforms %% Type: variant +Subtag: lycopol +Description: Lycopolitan alias Subakhmimic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: mdcegyp Description: Ancient Egyptian hieroglyphs encoded in Manuel de Codage Added: 2025-02-06 @@ -48180,6 +48215,12 @@ Added: 2025-02-06 Prefix: egy %% Type: variant +Subtag: mesokem +Description: Mesokemic alias Oxyrhynchite dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: metelko Description: Slovene in Metelko alphabet Added: 2012-06-27 @@ -48367,6 +48408,12 @@ Prefix: rm Comments: Supraregional Romansh written standard %% Type: variant +Subtag: sahidic +Description: Sahidic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: saigon Description: The Sài Gòn variant of Vietnamese Added: 2025-03-10 @@ -48555,6 +48602,12 @@ Comments: The subtag represents the old orthography of the Latvian language used during c. 1600s–1920s. %% Type: variant +Subtag: viennese +Description: The Viennese dialect of German +Added: 2025-06-22 +Prefix: de +%% +Type: variant Subtag: vivaraup Description: Vivaro-Alpine Added: 2018-04-22 diff --git a/src/java.base/share/native/libjava/VirtualThread.c b/src/java.base/share/native/libjava/VirtualThread.c index 3cacf89e752..5936031f926 100644 --- a/src/java.base/share/native/libjava/VirtualThread.c +++ b/src/java.base/share/native/libjava/VirtualThread.c @@ -32,10 +32,10 @@ #define VIRTUAL_THREAD "Ljava/lang/VirtualThread;" static JNINativeMethod methods[] = { - { "notifyJvmtiStart", "()V", (void *)&JVM_VirtualThreadStart }, - { "notifyJvmtiEnd", "()V", (void *)&JVM_VirtualThreadEnd }, - { "notifyJvmtiMount", "(Z)V", (void *)&JVM_VirtualThreadMount }, - { "notifyJvmtiUnmount", "(Z)V", (void *)&JVM_VirtualThreadUnmount }, + { "endFirstTransition", "()V", (void *)&JVM_VirtualThreadEndFirstTransition }, + { "startFinalTransition", "()V", (void *)&JVM_VirtualThreadStartFinalTransition }, + { "startTransition", "(Z)V", (void *)&JVM_VirtualThreadStartTransition }, + { "endTransition", "(Z)V", (void *)&JVM_VirtualThreadEndTransition }, { "notifyJvmtiDisableSuspend", "(Z)V", (void *)&JVM_VirtualThreadDisableSuspend }, { "postPinnedEvent", "(" STR ")V", (void *)&JVM_VirtualThreadPinnedEvent }, { "takeVirtualThreadListToUnblock", "()" VIRTUAL_THREAD, (void *)&JVM_TakeVirtualThreadListToUnblock}, diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java b/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java index d051c833ee7..cd7cc38550c 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -610,23 +610,24 @@ class WindowsWatchService boolean criticalError = false; int errorCode = info.error(); int messageSize = info.bytesTransferred(); - if (errorCode == ERROR_NOTIFY_ENUM_DIR) { - // buffer overflow - key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); - } else if (errorCode != 0 && errorCode != ERROR_MORE_DATA) { + if (errorCode != 0 && + errorCode != ERROR_MORE_DATA && + errorCode != ERROR_NOTIFY_ENUM_DIR) { // ReadDirectoryChangesW failed criticalError = true; } else { // ERROR_MORE_DATA is a warning about incomplete // data transfer over TCP/UDP stack. For the case - // [messageSize] is zero in the most of cases. + // [messageSize] is zero in most cases. if (messageSize > 0) { // process non-empty events. processEvents(key, messageSize); - } else if (errorCode == 0) { - // insufficient buffer size - // not described, but can happen. + } else if (errorCode == 0 || + errorCode == ERROR_NOTIFY_ENUM_DIR) { + // errorCode == 0: insufficient buffer size; + // not described, but can happen. + // errorCode == ERROR_NOTIFY_ENUM_DIR: buffer overflow key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); } diff --git a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java index 6b4ae119504..2835143dc4e 100644 --- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -83,6 +83,11 @@ public enum SourceVersion { * preview, flexible constructor bodies in third preview) * 25: module import declarations, compact source files and * instance main methods, and flexible constructor bodies + * (primitive Types in Patterns, instanceof, and switch in + * third preview) + * 26: no changes (primitive Types in Patterns, instanceof, and + * switch in fourth preview) + * 27: tbd */ /** @@ -476,10 +481,22 @@ public enum SourceVersion { * @since 26 * * @see + * href="https://docs.oracle.com/en/java/javase/26/docs/specs/jls/index.html"> * The Java Language Specification, Java SE 26 Edition */ RELEASE_26, + + /** + * The version introduced by the Java Platform, Standard Edition + * 27. + * + * @since 27 + * + * @see + * The Java Language Specification, Java SE 27 Edition + */ + RELEASE_27, ; // Reduce code churn when appending new constants // Note that when adding constants for newer releases, the @@ -489,7 +506,7 @@ public enum SourceVersion { * {@return the latest source version that can be modeled} */ public static SourceVersion latest() { - return RELEASE_26; + return RELEASE_27; } private static final SourceVersion latestSupported = getLatestSupported(); @@ -504,7 +521,7 @@ public enum SourceVersion { private static SourceVersion getLatestSupported() { int intVersion = Runtime.version().feature(); return (intVersion >= 11) ? - valueOf("RELEASE_" + Math.min(26, intVersion)): + valueOf("RELEASE_" + Math.min(27, intVersion)): RELEASE_10; } diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java index 2b2f80358b0..bfd3b64a757 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java @@ -44,7 +44,7 @@ import javax.annotation.processing.SupportedSourceVersion; * @see AbstractAnnotationValueVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public abstract class AbstractAnnotationValueVisitor14 extends AbstractAnnotationValueVisitor9 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java index 59d1eb28282..31d0545744a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java @@ -50,7 +50,7 @@ import javax.annotation.processing.ProcessingEnvironment; * @see AbstractAnnotationValueVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractAnnotationValueVisitorPreview extends AbstractAnnotationValueVisitor14 { diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java index b624bb9f999..72b796a2cb7 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java @@ -50,7 +50,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractElementVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public abstract class AbstractElementVisitor14 extends AbstractElementVisitor9 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java index 761916a1434..009cf06a8ce 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java @@ -53,7 +53,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractElementVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractElementVisitorPreview extends AbstractElementVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java index 1860cd09ac5..95dfc473da1 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java @@ -47,7 +47,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractTypeVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public abstract class AbstractTypeVisitor14 extends AbstractTypeVisitor9 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java index 6b701262a4f..257d7f5aa17 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java @@ -53,7 +53,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractTypeVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractTypeVisitorPreview extends AbstractTypeVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java index cb0e1cfbc9f..58b1d81bcf9 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java @@ -61,7 +61,7 @@ import javax.lang.model.SourceVersion; * @see ElementKindVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class ElementKindVisitor14 extends ElementKindVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java index 0f436e6d1e5..e2183185b80 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java @@ -67,7 +67,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementKindVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class ElementKindVisitorPreview extends ElementKindVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java index 946cf97b092..6f7d8bc5fed 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java @@ -77,7 +77,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementScanner9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class ElementScanner14 extends ElementScanner9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java index a9d8e7c1f3f..27080c7abc5 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java @@ -81,7 +81,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementScanner14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class ElementScannerPreview extends ElementScanner14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java index 9320e18d5dd..a5e32c936e4 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java @@ -52,7 +52,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleAnnotationValueVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class SimpleAnnotationValueVisitor14 extends SimpleAnnotationValueVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java index 01509c0c4a5..a98161812fe 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java @@ -58,7 +58,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleAnnotationValueVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleAnnotationValueVisitorPreview extends SimpleAnnotationValueVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java index dff1731d3c9..da9797b2750 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java @@ -58,7 +58,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleElementVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class SimpleElementVisitor14 extends SimpleElementVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java index c3896a794c0..158dd24450f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java @@ -61,7 +61,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleElementVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleElementVisitorPreview extends SimpleElementVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java index d06f5d673d3..07b6b2bedbe 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java @@ -56,7 +56,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleTypeVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class SimpleTypeVisitor14 extends SimpleTypeVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java index 11e2e8a50d5..ff9a3050e12 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java @@ -62,7 +62,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleTypeVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleTypeVisitorPreview extends SimpleTypeVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java index 295ceb200b8..8c80f4ad79a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java @@ -61,7 +61,7 @@ import static javax.lang.model.SourceVersion.*; * @see TypeKindVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class TypeKindVisitor14 extends TypeKindVisitor9 { /** * Constructor for concrete subclasses to call; uses {@code null} diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java index c0ca3a0450a..62c059c605f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java @@ -66,7 +66,7 @@ import static javax.lang.model.SourceVersion.*; * @see TypeKindVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class TypeKindVisitorPreview extends TypeKindVisitor14 { /** diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m index 90a147aa5a2..14b7ee8c6b5 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m @@ -68,6 +68,11 @@ static jclass sjc_CAccessibility = NULL; sjm_getCurrentAccessiblePopupMenu, fAccessible, fComponent); + CHECK_EXCEPTION(); + if (axComponent == nil) { + return nil; + } + CommonComponentAccessibility *currentElement = [CommonComponentAccessibility createWithAccessible:axComponent withEnv:env withView:self->fView isCurrent:YES]; diff --git a/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java b/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java index 4c4179699f0..7a3ee8646a7 100644 --- a/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java +++ b/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -186,7 +186,13 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { * {@code getBounds2D(BufferedImage)} * are not necessarily the same as the coordinates of the * {@code BufferedImage} returned by this method. If the - * upper-left corner coordinates of the rectangle are + * application provides a {@code dst} that is always returned. + * If {@code dst} is {@code null} and a destination {code BufferedImage} + * with the transformed dimensions cannot be created, the {@code src} + * dimensions will be substituted. + * + *

+ * If the upper-left corner coordinates of the rectangle are * negative then this part of the rectangle is not drawn. If the * upper-left corner coordinates of the rectangle are positive * then the filtered image is drawn at that position in the @@ -224,7 +230,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { BufferedImage origDst = dst; if (dst == null) { - dst = createCompatibleDestImage(src, null); + dst = createCompatibleDestImageInt(src, null); dstCM = srcCM; origDst = dst; } @@ -272,7 +278,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { } else { needToConvert = true; - dst = createCompatibleDestImage(src, null); + dst = createCompatibleDestImageInt(src, null); } } @@ -320,7 +326,12 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { * {@code getBounds2D(Raster)} * are not necessarily the same as the coordinates of the * {@code WritableRaster} returned by this method. If the - * upper-left corner coordinates of rectangle are negative then + * application provides a {@code dst} that is always returned. + * If {@code dst} is {@code null} and a destination {code Raster} + * with the transformed dimensions cannot be created, the {@code src} + * dimensions will be substituted. + *

+ * If the upper-left corner coordinates of rectangle are negative then * this part of the rectangle is not drawn. If the coordinates * of the rectangle are positive then the filtered image is drawn at * that position in the destination {@code Raster}. @@ -342,7 +353,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { throw new NullPointerException("src image is null"); } if (dst == null) { - dst = createCompatibleDestRaster(src); + dst = createCompatibleDestRasterInt(src); } if (src == dst) { throw new IllegalArgumentException("src image cannot be the "+ @@ -422,7 +433,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { /** * Creates a zeroed destination image with the correct size and number of * bands. A {@code RasterFormatException} may be thrown if the - * transformed width or height is equal to 0. + * transformed width or height is less than or equal to 0, or too large. *

* If {@code destCM} is null, * an appropriate {@code ColorModel} is used; this @@ -437,9 +448,36 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { */ public BufferedImage createCompatibleDestImage (BufferedImage src, ColorModel destCM) { - BufferedImage image; Rectangle r = getBounds2D(src).getBounds(); + try { + return createCompatibleDestImage(src, destCM, r); + } catch (Exception e) { + if (e instanceof RasterFormatException) { + throw e; + } else { + RasterFormatException re = + new RasterFormatException("Could not create transformed image of size " + r); + re.initCause(e); + throw re; + } + } + } + private BufferedImage createCompatibleDestImageInt(BufferedImage src, + ColorModel destCM) { + + try { + return createCompatibleDestImage(src, destCM); + } catch (Exception e) { + return createCompatibleDestImage(src, destCM, src.getRaster().getBounds()); + } + } + + private BufferedImage createCompatibleDestImage(BufferedImage src, + ColorModel destCM, + Rectangle r) { + + BufferedImage image; // If r.x (or r.y) is < 0, then we want to only create an image // that is in the positive range. // If r.x (or r.y) is > 0, then we need to create an image that @@ -482,14 +520,38 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { /** * Creates a zeroed destination {@code Raster} with the correct size * and number of bands. A {@code RasterFormatException} may be thrown - * if the transformed width or height is equal to 0. + * if the transformed width or height is less than or equal to 0, or too large. * * @param src The {@code Raster} to be transformed. * * @return The zeroed destination {@code Raster}. */ public WritableRaster createCompatibleDestRaster (Raster src) { - Rectangle2D r = getBounds2D(src); + Rectangle r = getBounds2D(src).getBounds(); + try { + return createCompatibleDestRaster(src, r); + } catch (Exception e) { + if (e instanceof RasterFormatException) { + throw e; + } else { + RasterFormatException re = + new RasterFormatException("Could not create transformed raster of size " + r); + re.initCause(e); + throw re; + } + } + } + + private WritableRaster createCompatibleDestRasterInt(Raster src) { + try { + return createCompatibleDestRaster(src); + } catch (Exception e) { + Rectangle r = src.getBounds(); + return createCompatibleDestRaster(src, r); + } + } + + private WritableRaster createCompatibleDestRaster (Raster src, Rectangle r) { return src.createCompatibleWritableRaster((int)r.getX(), (int)r.getY(), diff --git a/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java index bad9abc6130..229c8a20d35 100644 --- a/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/BandedSampleModel.java @@ -293,6 +293,9 @@ public final class BandedSampleModel extends ComponentSampleModel * @param data The DataBuffer containing the image data. * @return the data for the specified pixel. * @see #setDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code obj} is too small to hold the output. */ public Object getDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -401,15 +404,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns all samples for the specified pixel in an int array. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples for the specified pixel. - * @see #setPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -434,26 +432,19 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns all samples for the specified rectangle of pixels in - * an int array, one sample per data array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples for the pixels within the specified region. - * @see #setPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative. + * or if {@code iArray} is too small to hold the output. */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -484,16 +475,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns as int the sample in a specified band for the pixel - * located at (x,y). - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return the sample in the specified band for the specified pixel. - * @see #setSample(int, int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public int getSample(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -508,16 +493,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns the sample in a specified band - * for the pixel located at (x,y) as a float. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return a float value that represents the sample in the specified - * band for the specified pixel. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public float getSampleFloat(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -532,16 +511,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns the sample in a specified band - * for a pixel located at (x,y) as a double. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return a double value that represents the sample in the specified - * band for the specified pixel. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public double getSampleDouble(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -556,25 +529,16 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Returns the samples in a specified band for the specified rectangle - * of pixels in an int array, one sample per data array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param b The band to return - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples in the specified band for the pixels within - * the specified region. - * @see #setSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } @@ -633,6 +597,9 @@ public final class BandedSampleModel extends ComponentSampleModel * object * @param data The DataBuffer containing the image data * @see #getDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code obj} is too small to hold the input. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -700,14 +667,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets a pixel in the DataBuffer using an int array of samples for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -722,25 +685,19 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets all samples for a rectangle of pixels from an int array containing - * one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative. + * or if {@code iArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -763,16 +720,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the DataBuffer using an int for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as an int - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, int s, DataBuffer data) { @@ -786,16 +737,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the DataBuffer using a float for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as a float - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, float s , @@ -810,16 +755,10 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the DataBuffer using a double for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as a double - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, double s, @@ -834,23 +773,16 @@ public final class BandedSampleModel extends ComponentSampleModel } /** - * Sets the samples in the specified band for the specified rectangle - * of pixels from an int array containing one sample per data array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param b The band to set - * @param iArray The input sample array - * @param data The DataBuffer containing the image data - * @see #getSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } diff --git a/src/java.desktop/share/classes/java/awt/image/BufferedImage.java b/src/java.desktop/share/classes/java/awt/image/BufferedImage.java index 09c96a6560f..52bf8a8c4bf 100644 --- a/src/java.desktop/share/classes/java/awt/image/BufferedImage.java +++ b/src/java.desktop/share/classes/java/awt/image/BufferedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,10 +100,7 @@ public class BufferedImage extends java.awt.Image * Represents an image with 8-bit RGBA color components packed into * integer pixels. The image has a {@code DirectColorModel} * with alpha. The color data in this image is considered not to be - * premultiplied with alpha. When this type is used as the - * {@code imageType} argument to a {@code BufferedImage} - * constructor, the created image is consistent with images - * created in the JDK1.1 and earlier releases. + * premultiplied with alpha. */ public static final int TYPE_INT_ARGB = 2; diff --git a/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java b/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java index 7a3d67c7e6e..89a72b18dea 100644 --- a/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java @@ -600,7 +600,7 @@ public class ComponentSampleModel extends SampleModel * @return the data of the specified pixel * @see #setDataElements(int, int, Object, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are * not in bounds, or if obj is too small to hold the output. */ @@ -707,20 +707,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns all samples for the specified pixel in an int array, - * one sample per array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x the X coordinate of the pixel location - * @param y the Y coordinate of the pixel location - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples of the specified pixel. - * @see #setPixel(int, int, int[], DataBuffer) - * - * @throws NullPointerException if data is null. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the output. + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -742,26 +732,19 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns all samples for the specified rectangle of pixels in - * an int array, one sample per array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data - * @return the samples of the pixels within the specified region. - * @see #setPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the output. */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || y > height || y1 < 0 || y1 > height) + if (x < 0 || (w < 0) || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || (h < 0) || y >= height || y > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -790,16 +773,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns as int the sample in a specified band for the pixel - * located at (x,y). - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x the X coordinate of the pixel location - * @param y the Y coordinate of the pixel location - * @param b the band to return - * @param data the {@code DataBuffer} containing the image data - * @return the sample in a specified band for the specified pixel - * @see #setSample(int, int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public int getSample(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -814,16 +791,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns the sample in a specified band - * for the pixel located at (x,y) as a float. - * An {@code ArrayIndexOutOfBoundsException} might be - * thrown if the coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return a float value representing the sample in the specified - * band for the specified pixel. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public float getSampleFloat(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -837,18 +808,11 @@ public class ComponentSampleModel extends SampleModel bandOffsets[b]); return sample; } - /** - * Returns the sample in a specified band - * for a pixel located at (x,y) as a double. - * An {@code ArrayIndexOutOfBoundsException} might be - * thrown if the coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to return - * @param data The DataBuffer containing the image data - * @return a double value representing the sample in the specified - * band for the specified pixel. + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public double getSampleDouble(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -864,25 +828,16 @@ public class ComponentSampleModel extends SampleModel } /** - * Returns the samples in a specified band for the specified rectangle - * of pixels in an int array, one sample per data array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w the width of the pixel rectangle - * @param h the height of the pixel rectangle - * @param b the band to return - * @param iArray if non-{@code null}, returns the samples - * in this array - * @param data the {@code DataBuffer} containing the image data - * @return the samples in the specified band of the specified pixel - * @see #setSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || ( h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } @@ -943,6 +898,9 @@ public class ComponentSampleModel extends SampleModel * @param obj a primitive array containing pixel data * @param data the DataBuffer containing the image data * @see #getDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the input. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -1011,15 +969,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets a pixel in the {@code DataBuffer} using an int array of - * samples for input. An {@code ArrayIndexOutOfBoundsException} - * might be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -1034,25 +987,19 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets all samples for a rectangle of pixels from an int array containing - * one sample per array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if the - * coordinates are not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -1075,16 +1022,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the {@code DataBuffer} using an int for input. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if the - * coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b the band to set - * @param s the input sample as an int - * @param data the DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, int s, DataBuffer data) { @@ -1098,16 +1039,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the {@code DataBuffer} using a float for input. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as a float - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, float s , @@ -1123,16 +1058,10 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the {@code DataBuffer} using a double for input. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if - * the coordinates are not in bounds. - * @param x The X coordinate of the pixel location - * @param y The Y coordinate of the pixel location - * @param b The band to set - * @param s The input sample as a double - * @param data The DataBuffer containing the image data - * @see #getSample(int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, double s, @@ -1148,23 +1077,16 @@ public class ComponentSampleModel extends SampleModel } /** - * Sets the samples in the specified band for the specified rectangle - * of pixels from an int array containing one sample per data array element. - * An {@code ArrayIndexOutOfBoundsException} might be thrown if the - * coordinates are not in bounds. - * @param x The X coordinate of the upper left pixel location - * @param y The Y coordinate of the upper left pixel location - * @param w The width of the pixel rectangle - * @param h The height of the pixel rectangle - * @param b The band to set - * @param iArray The input samples in an int array - * @param data The DataBuffer containing the image data - * @see #getSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } diff --git a/src/java.desktop/share/classes/java/awt/image/Kernel.java b/src/java.desktop/share/classes/java/awt/image/Kernel.java index d2b9760aba5..67f62e79b9e 100644 --- a/src/java.desktop/share/classes/java/awt/image/Kernel.java +++ b/src/java.desktop/share/classes/java/awt/image/Kernel.java @@ -25,6 +25,7 @@ package java.awt.image; +import java.util.Objects; /** * The {@code Kernel} class defines a matrix that describes how a @@ -59,7 +60,7 @@ public class Kernel implements Cloneable { * @param width width of the kernel * @param height height of the kernel * @param data kernel data in row major order - * @throws IllegalArgumentException if {@code data} is null + * @throws NullPointerException if {@code data} is null * @throws IllegalArgumentException if {@code width} or {@code height} * is not positive * @throws IllegalArgumentException if product of {@code width} and @@ -69,9 +70,7 @@ public class Kernel implements Cloneable { * {@code height} */ public Kernel(int width, int height, float[] data) { - if (data == null) { - throw new IllegalArgumentException("Data must not be null"); - } + Objects.requireNonNull(data, "Data must not be null"); if ((width <= 0) || (height <= 0)) { throw new IllegalArgumentException("Invalid width or height"); } diff --git a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java index 9254d9fa717..e40da604887 100644 --- a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java @@ -343,7 +343,7 @@ public class MultiPixelPackedSampleModel extends SampleModel * coordinates are not in bounds. * @param x the X coordinate of the specified pixel * @param y the Y coordinate of the specified pixel - * @param b the band to return, which is assumed to be 0 + * @param b the band to return, which must be 0 * @param data the {@code DataBuffer} containing the image * data * @return the specified band containing the sample of the specified @@ -374,7 +374,7 @@ public class MultiPixelPackedSampleModel extends SampleModel * coordinates are not in bounds. * @param x the X coordinate of the specified pixel * @param y the Y coordinate of the specified pixel - * @param b the band to return, which is assumed to be 0 + * @param b the band to set, which must be 0 * @param s the input sample as an {@code int} * @param data the {@code DataBuffer} where image data is stored * @throws ArrayIndexOutOfBoundsException if the coordinates are @@ -448,6 +448,9 @@ public class MultiPixelPackedSampleModel extends SampleModel * not in bounds, or if {@code obj} is not {@code null} or * not large enough to hold the pixel data * @see #setDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {code obj} is too small to hold the output. */ public Object getDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -527,8 +530,11 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param data the {@code DataBuffer} where image data is stored * @return an array containing the specified pixel. * @throws ArrayIndexOutOfBoundsException if the coordinates - * are not in bounds + * are not in bounds, or if {@code iArray} is too small to hold the output. * @see #setPixel(int, int, int[], DataBuffer) + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -588,6 +594,9 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param obj a primitive array containing pixel data * @param data the {@code DataBuffer} containing the image data * @see #getDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code obj} is too small to hold the input. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -638,6 +647,9 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param iArray the input pixel in an {@code int} array * @param data the {@code DataBuffer} containing the image data * @see #getPixel(int, int, int[], DataBuffer) + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { diff --git a/src/java.desktop/share/classes/java/awt/image/SampleModel.java b/src/java.desktop/share/classes/java/awt/image/SampleModel.java index 678925ffd20..0ecd4162c60 100644 --- a/src/java.desktop/share/classes/java/awt/image/SampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/SampleModel.java @@ -231,9 +231,9 @@ public abstract class SampleModel * @return the samples for the specified pixel. * @see #setPixel(int, int, int[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the output. + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { @@ -293,9 +293,9 @@ public abstract class SampleModel * @see java.awt.image.DataBuffer * @see #setDataElements(int, int, Object, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if obj is too small to hold the output. + * not in bounds, or if {@code obj} is too small to hold the output. */ public abstract Object getDataElements(int x, int y, Object obj, DataBuffer data); @@ -347,9 +347,10 @@ public abstract class SampleModel * @see #setDataElements(int, int, int, int, Object, DataBuffer) * @see java.awt.image.DataBuffer * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if obj is too small to hold the output. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code obj} is too small to hold the output. */ public Object getDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) { @@ -362,8 +363,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -528,7 +529,7 @@ public abstract class SampleModel * @see #getDataElements(int, int, Object, DataBuffer) * @see java.awt.image.DataBuffer * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are * not in bounds, or if obj is too small to hold the input. */ @@ -577,7 +578,7 @@ public abstract class SampleModel * @see #getDataElements(int, int, int, int, Object, DataBuffer) * @see java.awt.image.DataBuffer * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are * not in bounds, or if obj is too small to hold the input. */ @@ -592,8 +593,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -695,9 +696,9 @@ public abstract class SampleModel * @return the samples for the specified pixel. * @see #setPixel(int, int, float[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the output. + * not in bounds, or if {@code fArray} is too small to hold the output. */ public float[] getPixel(int x, int y, float[] fArray, DataBuffer data) { @@ -726,9 +727,9 @@ public abstract class SampleModel * @return the samples for the specified pixel. * @see #setPixel(int, int, double[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if dArray is too small to hold the output. + * not in bounds, or if {@code dArray} is too small to hold the output. */ public double[] getPixel(int x, int y, double[] dArray, DataBuffer data) { @@ -760,9 +761,10 @@ public abstract class SampleModel * @return the samples for the specified region of pixels. * @see #setPixels(int, int, int, int, int[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the output. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the output. */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { @@ -772,8 +774,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -808,9 +810,10 @@ public abstract class SampleModel * @return the samples for the specified region of pixels. * @see #setPixels(int, int, int, int, float[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the output. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code fArray} is too small to hold the output. */ public float[] getPixels(int x, int y, int w, int h, float[] fArray, DataBuffer data) { @@ -820,8 +823,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -856,9 +859,10 @@ public abstract class SampleModel * @return the samples for the specified region of pixels. * @see #setPixels(int, int, int, int, double[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if dArray is too small to hold the output. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code dArray} is too small to hold the output. */ public double[] getPixels(int x, int y, int w, int h, double[] dArray, DataBuffer data) { @@ -867,8 +871,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -903,7 +907,7 @@ public abstract class SampleModel * @return the sample in a specified band for the specified pixel. * @see #setSample(int, int, int, int, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -921,7 +925,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @return the sample in a specified band for the specified pixel. * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -943,7 +947,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @return the sample in a specified band for the specified pixel. * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -971,10 +975,10 @@ public abstract class SampleModel * of pixels. * @see #setSamples(int, int, int, int, int, int[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if iArray is too small to - * hold the output. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { @@ -983,8 +987,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x1 < x || x1 > width || - y < 0 || y1 < y || y1 > height) + if (x < 0 || w < 0 || x1 < x || x1 > width || + y < 0 || h < 0 || y1 < y || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1019,10 +1023,10 @@ public abstract class SampleModel * of pixels. * @see #setSamples(int, int, int, int, int, float[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if fArray is too small to - * hold the output. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public float[] getSamples(int x, int y, int w, int h, int b, float[] fArray, @@ -1032,8 +1036,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x1 < x || x1 > width || - y < 0 || y1 < y || y1 > height) + if (x < 0 || w < 0 || x1 < x || x1 > width || + y < 0 || h < 0 || y1 < y || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates"); } @@ -1068,10 +1072,10 @@ public abstract class SampleModel * of pixels. * @see #setSamples(int, int, int, int, int, double[], DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if dArray is too small to - * hold the output. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code dArray} is too small to hold the output. */ public double[] getSamples(int x, int y, int w, int h, int b, double[] dArray, @@ -1081,8 +1085,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x1 < x || x1 > width || - y < 0 || y1 < y || y1 > height) + if (x < 0 || w < 0 || x1 < x || x1 > width || + y < 0 || h < 0 || y1 < y || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates"); } @@ -1111,9 +1115,9 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixel(int, int, int[], DataBuffer) * - * @throws NullPointerException if iArray or data is null. + * @throws NullPointerException if {@code iArray} or {code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the input. + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { @@ -1131,9 +1135,9 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixel(int, int, float[], DataBuffer) * - * @throws NullPointerException if fArray or data is null. + * @throws NullPointerException if {@code fArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the input. + * not in bounds, or if {@code fArray} is too small to hold the input. */ public void setPixel(int x, int y, float[] fArray, DataBuffer data) { @@ -1150,9 +1154,9 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixel(int, int, double[], DataBuffer) * - * @throws NullPointerException if dArray or data is null. + * @throws NullPointerException if {@code dArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the input. + * not in bounds, or if {@code dArray} is too small to hold the input. */ public void setPixel(int x, int y, double[] dArray, DataBuffer data) { @@ -1173,9 +1177,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixels(int, int, int, int, int[], DataBuffer) * - * @throws NullPointerException if iArray or data is null. + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if iArray is too small to hold the input. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { @@ -1183,8 +1188,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1211,9 +1216,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixels(int, int, int, int, float[], DataBuffer) * - * @throws NullPointerException if fArray or data is null. + * @throws NullPointerException if {@code fArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if fArray is too small to hold the input. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code fArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, float[] fArray, DataBuffer data) { @@ -1221,8 +1227,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width|| - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1249,9 +1255,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getPixels(int, int, int, int, double[], DataBuffer) * - * @throws NullPointerException if dArray or data is null. + * @throws NullPointerException if {@code dArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates are - * not in bounds, or if dArray is too small to hold the input. + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code dArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, double[] dArray, DataBuffer data) { @@ -1259,8 +1266,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1286,7 +1293,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSample(int, int, int, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -1310,7 +1317,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSample(int, int, int, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -1338,7 +1345,7 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSample(int, int, int, DataBuffer) * - * @throws NullPointerException if data is null. + * @throws NullPointerException if {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or * the band index are not in bounds. */ @@ -1364,10 +1371,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSamples(int, int, int, int, int, int[], DataBuffer) * - * @throws NullPointerException if iArray or data is null. + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if iArray is too small to - * hold the input. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { @@ -1375,8 +1382,8 @@ public abstract class SampleModel int Offset=0; int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1402,10 +1409,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSamples(int, int, int, int, int, float[], DataBuffer) * - * @throws NullPointerException if fArray or data is null. + * @throws NullPointerException if {@code fArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if fArray is too small to - * hold the input. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code fArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, float[] fArray, DataBuffer data) { @@ -1413,8 +1420,8 @@ public abstract class SampleModel int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } @@ -1440,10 +1447,10 @@ public abstract class SampleModel * @param data The DataBuffer containing the image data. * @see #getSamples(int, int, int, int, int, double[], DataBuffer) * - * @throws NullPointerException if dArray or data is null. + * @throws NullPointerException if {@code dArray} or {@code data} is {@code null}. * @throws ArrayIndexOutOfBoundsException if the coordinates or - * the band index are not in bounds, or if dArray is too small to - * hold the input. + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code dArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, double[] dArray, DataBuffer data) { @@ -1452,8 +1459,8 @@ public abstract class SampleModel int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException("Invalid coordinates."); } diff --git a/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java index abb669e02c6..a75b5197c44 100644 --- a/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java @@ -357,6 +357,9 @@ public class SinglePixelPackedSampleModel extends SampleModel * @param data The DataBuffer containing the image data. * @return the data for the specified pixel. * @see #setDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the output. */ public Object getDataElements(int x, int y, Object obj, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -416,15 +419,10 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Returns all samples in for the specified pixel in an int array. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location. - * @param y The Y coordinate of the pixel location. - * @param iArray If non-null, returns the samples in this array - * @param data The DataBuffer containing the image data. - * @return all samples for the specified pixel. - * @see #setPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the output. */ public int [] getPixel(int x, int y, int[] iArray, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -446,26 +444,20 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Returns all samples for the specified rectangle of pixels in - * an int array, one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location. - * @param y The Y coordinate of the upper left pixel location. - * @param w The width of the pixel rectangle. - * @param h The height of the pixel rectangle. - * @param iArray If non-null, returns the samples in this array. - * @param data The DataBuffer containing the image data. - * @return all samples for the specified region of pixels. - * @see #setPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the output. */ + @Override public int[] getPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -493,17 +485,10 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Returns as int the sample in a specified band for the pixel - * located at (x,y). - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location. - * @param y The Y coordinate of the pixel location. - * @param b The band to return. - * @param data The DataBuffer containing the image data. - * @return the sample in a specified band for the specified - * pixel. - * @see #setSample(int, int, int, int, DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public int getSample(int x, int y, int b, DataBuffer data) { // Bounds check for 'b' will be performed automatically @@ -516,25 +501,16 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Returns the samples for a specified band for the specified rectangle - * of pixels in an int array, one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location. - * @param y The Y coordinate of the upper left pixel location. - * @param w The width of the pixel rectangle. - * @param h The height of the pixel rectangle. - * @param b The band to return. - * @param iArray If non-null, returns the samples in this array. - * @param data The DataBuffer containing the image data. - * @return the samples for the specified band for the specified - * region of pixels. - * @see #setSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the output. */ public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } @@ -592,6 +568,9 @@ public class SinglePixelPackedSampleModel extends SampleModel * @param obj A primitive array containing pixel data. * @param data The DataBuffer containing the image data. * @see #getDataElements(int, int, Object, DataBuffer) + * @throws NullPointerException if {@code obj} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the input. */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { @@ -624,14 +603,10 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Sets a pixel in the DataBuffer using an int array of samples for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location. - * @param y The Y coordinate of the pixel location. - * @param iArray The input samples in an int array. - * @param data The DataBuffer containing the image data. - * @see #getPixel(int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if {@code iArray} is too small to hold the input. */ public void setPixel(int x, int y, int[] iArray, @@ -650,25 +625,19 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Sets all samples for a rectangle of pixels from an int array containing - * one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location. - * @param y The Y coordinate of the upper left pixel location. - * @param w The width of the pixel rectangle. - * @param h The height of the pixel rectangle. - * @param iArray The input samples in an int array. - * @param data The DataBuffer containing the image data. - * @see #getPixels(int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or {@code w} or {@code h} is negative + * or if {@code iArray} is too small to hold the input. */ public void setPixels(int x, int y, int w, int h, int[] iArray, DataBuffer data) { int x1 = x + w; int y1 = y + h; - if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || - y < 0 || y >= height || h > height || y1 < 0 || y1 > height) + if (x < 0 || w < 0 || x >= width || w > width || x1 < 0 || x1 > width || + y < 0 || h < 0 || y >= height || h > height || y1 < 0 || y1 > height) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); @@ -692,17 +661,11 @@ public class SinglePixelPackedSampleModel extends SampleModel } } - /** - * Sets a sample in the specified band for the pixel located at (x,y) - * in the DataBuffer using an int for input. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the pixel location. - * @param y The Y coordinate of the pixel location. - * @param b The band to set. - * @param s The input sample as an int. - * @param data The DataBuffer containing the image data. - * @see #getSample(int, int, int, DataBuffer) + /* + * {inheritDoc} + * @throws NullPointerException if {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. */ public void setSample(int x, int y, int b, int s, DataBuffer data) { @@ -718,23 +681,16 @@ public class SinglePixelPackedSampleModel extends SampleModel } /** - * Sets the samples in the specified band for the specified rectangle - * of pixels from an int array containing one sample per array element. - * ArrayIndexOutOfBoundsException may be thrown if the coordinates are - * not in bounds. - * @param x The X coordinate of the upper left pixel location. - * @param y The Y coordinate of the upper left pixel location. - * @param w The width of the pixel rectangle. - * @param h The height of the pixel rectangle. - * @param b The band to set. - * @param iArray The input samples in an int array. - * @param data The DataBuffer containing the image data. - * @see #getSamples(int, int, int, int, int, int[], DataBuffer) + * {@inheritDoc} + * @throws NullPointerException if {@code iArray} or {@code data} is {@code null}. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * band index are not in bounds, or {@code w} or {@code h} is negative, + * or if {@code iArray} is too small to hold the input. */ public void setSamples(int x, int y, int w, int h, int b, int[] iArray, DataBuffer data) { // Bounds check for 'b' will be performed automatically - if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + if ((x < 0) || (y < 0) || (w < 0) || (h < 0) || (x + w > width) || (y + h > height)) { throw new ArrayIndexOutOfBoundsException ("Coordinate out of bounds!"); } diff --git a/src/java.desktop/share/classes/javax/swing/JList.java b/src/java.desktop/share/classes/javax/swing/JList.java index 301813533d7..8d4497d6f9a 100644 --- a/src/java.desktop/share/classes/javax/swing/JList.java +++ b/src/java.desktop/share/classes/javax/swing/JList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2497,6 +2497,9 @@ public class JList extends JComponent implements Scrollable, Accessible /** * Returns the distance to scroll to expose the next or previous * row (for vertical scrolling) or column (for horizontal scrolling). + * The scrolling distance returned will be positive, + * unless scrolling for the specified parameters is already + * at its furthest extent, in which case it will return zero. *

* For horizontal scrolling, if the layout orientation is {@code VERTICAL}, * then the list's font size is returned (or {@code 1} if the font is @@ -2507,8 +2510,9 @@ public class JList extends JComponent implements Scrollable, Accessible * {@code SwingConstants.VERTICAL} * @param direction less or equal to zero to scroll up/back, * greater than zero for down/forward - * @return the "unit" increment for scrolling in the specified direction; - * always positive + * @return the non-negative "unit" increment + * for scrolling in the specified direction + * * @see #getScrollableBlockIncrement * @see Scrollable#getScrollableUnitIncrement * @throws IllegalArgumentException if {@code visibleRect} is {@code null}, or @@ -2529,7 +2533,8 @@ public class JList extends JComponent implements Scrollable, Accessible /* Scroll Down */ if (direction > 0) { Rectangle r = getCellBounds(row, row); - return (r == null) ? 0 : r.height - (visibleRect.y - r.y); + return (r == null) ? 0 : + ((r.height - (visibleRect.y - r.y)) < 0) ? 0 : r.height - (visibleRect.y - r.y); } /* Scroll Up */ else { diff --git a/src/java.desktop/share/classes/javax/swing/JTree.java b/src/java.desktop/share/classes/javax/swing/JTree.java index c081b3cfff8..622c55e2ede 100644 --- a/src/java.desktop/share/classes/javax/swing/JTree.java +++ b/src/java.desktop/share/classes/javax/swing/JTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -777,10 +777,10 @@ public class JTree extends JComponent implements Scrollable, Accessible updateInProgress = true; try { - setUI((TreeUI)UIManager.getUI(this)); - SwingUtilities.updateRendererOrEditorUI(getCellRenderer()); SwingUtilities.updateRendererOrEditorUI(getCellEditor()); + + setUI((TreeUI)UIManager.getUI(this)); } finally { updateInProgress = false; } diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index eab0817af23..78cd4a7e57d 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -138,8 +138,6 @@ import sun.awt.X11GraphicsDevice; import sun.awt.X11GraphicsEnvironment; import sun.awt.XSettings; import sun.awt.datatransfer.DataTransferer; -import sun.awt.screencast.ScreencastHelper; -import sun.awt.screencast.XdgDesktopPortal; import sun.awt.util.PerformanceLogger; import sun.awt.util.ThreadGroupUtils; import sun.font.FontConfigManager; @@ -1523,21 +1521,16 @@ public final class XToolkit extends UNIXToolkit implements Runnable { awtLock(); try { if (numberOfButtons == 0) { - if (XdgDesktopPortal.isRemoteDesktop() - && ScreencastHelper.isAvailable()) { + numberOfButtons = getNumberOfButtonsImpl(); + numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons; + //4th and 5th buttons are for wheel and shouldn't be reported as buttons. + //If we have more than 3 physical buttons and a wheel, we report N-2 buttons. + //If we have 3 physical buttons and a wheel, we report 3 buttons. + //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively. + if (numberOfButtons >= 5) { + numberOfButtons -= 2; + } else if (numberOfButtons == 4 || numberOfButtons == 5) { numberOfButtons = 3; - } else { - numberOfButtons = getNumberOfButtonsImpl(); - numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons; - //4th and 5th buttons are for wheel and shouldn't be reported as buttons. - //If we have more than 3 physical buttons and a wheel, we report N-2 buttons. - //If we have 3 physical buttons and a wheel, we report 3 buttons. - //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively. - if (numberOfButtons >= 5) { - numberOfButtons -= 2; - } else if (numberOfButtons == 4 || numberOfButtons == 5) { - numberOfButtons = 3; - } } } //Assume don't have to re-query the number again and again. diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c index e5b2dfa6db9..03dba969e8d 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c @@ -42,7 +42,6 @@ #include "debug_assert.h" static void *gtk3_libhandle = NULL; -static void *gthread_libhandle = NULL; static void transform_detail_string (const gchar *detail, GtkStyleContext *context); @@ -79,15 +78,6 @@ static void* dl_symbol(const char* name) return result; } -static void* dl_symbol_gthread(const char* name) -{ - void* result = dlsym(gthread_libhandle, name); - if (!result) - longjmp(j, NO_SYMBOL_EXCEPTION); - - return result; -} - gboolean gtk3_check(const char* lib_name, gboolean load) { if (gtk3_libhandle != NULL) { @@ -264,13 +254,6 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name) return FALSE; } - gthread_libhandle = dlopen(GTHREAD_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL); - if (gthread_libhandle == NULL) { - gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL); - if (gthread_libhandle == NULL) - return FALSE; - } - if (setjmp(j) == 0) { fp_gtk_check_version = dl_symbol("gtk_check_version"); @@ -634,9 +617,6 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name) dlclose(gtk3_libhandle); gtk3_libhandle = NULL; - dlclose(gthread_libhandle); - gthread_libhandle = NULL; - return NULL; } @@ -735,7 +715,6 @@ static int gtk3_unload() dlerror(); dlclose(gtk3_libhandle); - dlclose(gthread_libhandle); if ((gtk3_error = dlerror()) != NULL) { return FALSE; diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h b/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h index 11ec245ce8b..39be6a735d7 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h @@ -38,9 +38,6 @@ #define TRUE (!FALSE) #endif -#define GTHREAD_LIB_VERSIONED VERSIONED_JNI_LIB_NAME("gthread-2.0", "0") -#define GTHREAD_LIB JNI_LIB_NAME("gthread-2.0") - #define _G_TYPE_CIC(ip, gt, ct) ((ct*) ip) #define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) \ (_G_TYPE_CIC ((instance), (g_type), c_type)) @@ -850,9 +847,6 @@ typedef struct GtkApi { gboolean gtk_load(JNIEnv *env, GtkVersion version, gboolean verbose); gboolean gtk_check_version(GtkVersion version); -typedef struct _GThreadFunctions GThreadFunctions; -static gboolean (*fp_g_thread_get_initialized)(void); -static void (*fp_g_thread_init)(GThreadFunctions *vtable); static void (*fp_gdk_threads_init)(void); static void (*fp_gdk_threads_enter)(void); static void (*fp_gdk_threads_leave)(void); diff --git a/src/java.net.http/share/classes/java/net/http/HttpClient.java b/src/java.net.http/share/classes/java/net/http/HttpClient.java index a7a2171857d..9ecb048342b 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpClient.java +++ b/src/java.net.http/share/classes/java/net/http/HttpClient.java @@ -312,10 +312,22 @@ public abstract class HttpClient implements AutoCloseable { * need to be established, for example if a connection can be reused * from a previous request, then this timeout duration has no effect. * + * @implSpec + * A connection timeout applies to the entire connection phase, from the + * moment a connection is requested until it is established. + * Implementations are recommended to ensure that the connection timeout + * covers any SSL/TLS handshakes. + * + * @implNote + * The built-in JDK implementation of the connection timeout covers any + * SSL/TLS handshakes. + * * @param duration the duration to allow the underlying connection to be * established * @return this builder * @throws IllegalArgumentException if the duration is non-positive + * @see HttpRequest.Builder#timeout(Duration) Configuring timeout for + * request execution */ public Builder connectTimeout(Duration duration); diff --git a/src/java.net.http/share/classes/java/net/http/HttpRequest.java b/src/java.net.http/share/classes/java/net/http/HttpRequest.java index c56328ba4b4..741573e06b3 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpRequest.java +++ b/src/java.net.http/share/classes/java/net/http/HttpRequest.java @@ -258,12 +258,28 @@ public abstract class HttpRequest { * {@link HttpClient#sendAsync(java.net.http.HttpRequest, * java.net.http.HttpResponse.BodyHandler) HttpClient::sendAsync} * completes exceptionally with an {@code HttpTimeoutException}. The effect - * of not setting a timeout is the same as setting an infinite Duration, - * i.e. block forever. + * of not setting a timeout is the same as setting an infinite + * {@code Duration}, i.e., block forever. + * + * @implSpec + * A timeout applies to the duration measured from the instant the + * request execution starts to, at least, the instant an + * {@link HttpResponse} is constructed. The elapsed time includes + * obtaining a connection for transport and retrieving the response + * headers. + * + * @implNote + * The JDK built-in implementation applies timeout over the duration + * measured from the instant the request execution starts to the + * instant the response body is consumed, if present. This is + * implemented by stopping the timer after the response body subscriber + * completion. * * @param duration the timeout duration * @return this builder * @throws IllegalArgumentException if the duration is non-positive + * @see HttpClient.Builder#connectTimeout(Duration) Configuring + * timeout for connection establishment */ public abstract Builder timeout(Duration duration); diff --git a/src/java.net.http/share/classes/java/net/http/WebSocket.java b/src/java.net.http/share/classes/java/net/http/WebSocket.java index 313847cf449..84fc8472eef 100644 --- a/src/java.net.http/share/classes/java/net/http/WebSocket.java +++ b/src/java.net.http/share/classes/java/net/http/WebSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -144,6 +144,16 @@ public interface WebSocket { * {@link HttpTimeoutException}. If this method is not invoked then the * infinite timeout is assumed. * + * @implSpec + * A connection timeout applies to the entire connection phase, from the + * moment a connection is requested until it is established. + * Implementations are recommended to ensure that the connection timeout + * covers any WebSocket and SSL/TLS handshakes. + * + * @implNote + * The built-in JDK implementation of the connection timeout covers any + * WebSocket and SSL/TLS handshakes. + * * @param timeout * the timeout, non-{@linkplain Duration#isNegative() negative}, * non-{@linkplain Duration#ZERO ZERO} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java index 74600e78557..c1ed01ff07a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java @@ -581,6 +581,18 @@ abstract class ExchangeImpl { // Needed for HTTP/2 to subscribe a dummy subscriber and close the stream } + /** + * {@return {@code true}, if it is allowed to cancel the request timer on + * response body subscriber termination; {@code false}, otherwise} + * + * @param webSocket indicates if the associated request is a WebSocket handshake + * @param statusCode the status code of the associated response + */ + static boolean cancelTimerOnResponseBodySubscriberTermination( + boolean webSocket, int statusCode) { + return webSocket || statusCode < 100 || statusCode >= 200; + } + /* The following methods have separate HTTP/1.1 and HTTP/2 implementations */ abstract CompletableFuture> sendHeadersAsync(); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java index 02ce63b6314..72a47eca42c 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java @@ -206,8 +206,15 @@ class Http1Exchange extends ExchangeImpl { */ static final class Http1ResponseBodySubscriber extends HttpBodySubscriberWrapper { final Http1Exchange exchange; - Http1ResponseBodySubscriber(BodySubscriber userSubscriber, Http1Exchange exchange) { + + private final boolean cancelTimerOnTermination; + + Http1ResponseBodySubscriber( + BodySubscriber userSubscriber, + boolean cancelTimerOnTermination, + Http1Exchange exchange) { super(userSubscriber); + this.cancelTimerOnTermination = cancelTimerOnTermination; this.exchange = exchange; } @@ -220,6 +227,14 @@ class Http1Exchange extends ExchangeImpl { protected void unregister() { exchange.unregisterResponseSubscriber(this); } + + @Override + protected void onTermination() { + if (cancelTimerOnTermination) { + exchange.exchange.multi.cancelTimer(); + } + } + } @Override @@ -459,9 +474,10 @@ class Http1Exchange extends ExchangeImpl { @Override Http1ResponseBodySubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { BodySubscriber subscriber = handler.apply(response); - Http1ResponseBodySubscriber bs = - new Http1ResponseBodySubscriber(subscriber, this); - return bs; + var cancelTimerOnTermination = + cancelTimerOnResponseBodySubscriberTermination( + exchange.request().isWebSocket(), response.statusCode()); + return new Http1ResponseBodySubscriber<>(subscriber, cancelTimerOnTermination, this); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java index 41a4a84958a..81475a47c4a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java @@ -554,8 +554,12 @@ final class Http3ExchangeImpl extends Http3Stream { } final class Http3StreamResponseSubscriber extends HttpBodySubscriberWrapper { - Http3StreamResponseSubscriber(BodySubscriber subscriber) { + + private final boolean cancelTimerOnTermination; + + Http3StreamResponseSubscriber(BodySubscriber subscriber, boolean cancelTimerOnTermination) { super(subscriber); + this.cancelTimerOnTermination = cancelTimerOnTermination; } @Override @@ -568,6 +572,13 @@ final class Http3ExchangeImpl extends Http3Stream { registerResponseSubscriber(this); } + @Override + protected void onTermination() { + if (cancelTimerOnTermination) { + exchange.multi.cancelTimer(); + } + } + @Override protected void logComplete(Throwable error) { if (error == null) { @@ -590,9 +601,10 @@ final class Http3ExchangeImpl extends Http3Stream { Http3StreamResponseSubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { if (debug.on()) debug.log("Creating body subscriber"); - Http3StreamResponseSubscriber subscriber = - new Http3StreamResponseSubscriber<>(handler.apply(response)); - return subscriber; + var cancelTimerOnTermination = + cancelTimerOnResponseBodySubscriberTermination( + exchange.request().isWebSocket(), response.statusCode()); + return new Http3StreamResponseSubscriber<>(handler.apply(response), cancelTimerOnTermination); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java index d02930f4f31..ff130e90358 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java @@ -1880,6 +1880,13 @@ final class HttpClientImpl extends HttpClient implements Trackable { } } + // Visible for tests + List timers() { + synchronized (this) { + return new ArrayList<>(timeouts); + } + } + /** * Purges ( handles ) timer events that have passed their deadline, and * returns the amount of time, in milliseconds, until the next earliest diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java index ec621f7f955..60eb55ec0ad 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java @@ -25,7 +25,6 @@ package jdk.internal.net.http; -import java.io.IOError; import java.io.IOException; import java.lang.ref.WeakReference; import java.net.ConnectException; @@ -254,7 +253,7 @@ class MultiExchange implements Cancelable { .map(ConnectTimeoutTracker::getRemaining); } - private void cancelTimer() { + void cancelTimer() { if (responseTimerEvent != null) { client.cancelTimer(responseTimerEvent); responseTimerEvent = null; @@ -404,6 +403,8 @@ class MultiExchange implements Cancelable { processAltSvcHeader(r, client(), currentreq); Exchange exch = getExchange(); if (bodyNotPermitted(r)) { + // No response body consumption is expected, we can cancel the timer right away + cancelTimer(); if (bodyIsPresent(r)) { IOException ioe = new IOException( "unexpected content length header with 204 response"); @@ -467,6 +468,8 @@ class MultiExchange implements Cancelable { private CompletableFuture responseAsyncImpl(final boolean applyReqFilters) { if (currentreq.timeout().isPresent()) { + // Retried/Forwarded requests should reset the timer, if present + cancelTimer(); responseTimerEvent = ResponseTimerEvent.of(this); client.registerTimer(responseTimerEvent); } @@ -502,7 +505,6 @@ class MultiExchange implements Cancelable { } return completedFuture(response); } else { - cancelTimer(); setNewResponse(currentreq, response, null, exch); if (currentreq.isWebSocket()) { // need to close the connection and open a new one. @@ -520,11 +522,18 @@ class MultiExchange implements Cancelable { } }) .handle((response, ex) -> { // 5. handle errors and cancel any timer set - cancelTimer(); if (ex == null) { assert response != null; return completedFuture(response); } + + // Cancel the timer. Note that we only do so if the + // response has completed exceptionally. That is, we don't + // cancel the timer if there are no exceptions, since the + // response body might still get consumed, and it is + // still subject to the response timer. + cancelTimer(); + // all exceptions thrown are handled here final RetryContext retryCtx = checkRetryEligible(ex, exch); assert retryCtx != null : "retry context is null"; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index 9a7ccd8f3a1..bf9170f8f51 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -390,9 +390,10 @@ class Stream extends ExchangeImpl { @Override Http2StreamResponseSubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { - Http2StreamResponseSubscriber subscriber = - new Http2StreamResponseSubscriber<>(handler.apply(response)); - return subscriber; + var cancelTimerOnTermination = + cancelTimerOnResponseBodySubscriberTermination( + exchange.request().isWebSocket(), response.statusCode()); + return new Http2StreamResponseSubscriber<>(handler.apply(response), cancelTimerOnTermination); } // The Http2StreamResponseSubscriber is registered with the HttpClient @@ -1694,6 +1695,11 @@ class Stream extends ExchangeImpl { .whenComplete((v, t) -> pushGroup.pushError(t)); } + @Override + Http2StreamResponseSubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { + return new Http2StreamResponseSubscriber(handler.apply(response), false); + } + @Override void completeResponse(Response r) { Log.logResponse(r::toString); @@ -1924,8 +1930,12 @@ class Stream extends ExchangeImpl { } final class Http2StreamResponseSubscriber extends HttpBodySubscriberWrapper { - Http2StreamResponseSubscriber(BodySubscriber subscriber) { + + private final boolean cancelTimerOnTermination; + + Http2StreamResponseSubscriber(BodySubscriber subscriber, boolean cancelTimerOnTermination) { super(subscriber); + this.cancelTimerOnTermination = cancelTimerOnTermination; } @Override @@ -1938,6 +1948,13 @@ class Stream extends ExchangeImpl { unregisterResponseSubscriber(this); } + @Override + protected void onTermination() { + if (cancelTimerOnTermination) { + exchange.multi.cancelTimer(); + } + } + } private static final VarHandle DEREGISTERED; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java index 1c483ce99f4..f1c1f6f2d2a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ import java.util.Objects; import java.util.concurrent.CompletionStage; import java.util.concurrent.Flow; import java.util.concurrent.Flow.Subscription; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; @@ -51,7 +50,6 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { public static final Comparator> COMPARE_BY_ID = Comparator.comparing(HttpBodySubscriberWrapper::id); - public static final Flow.Subscription NOP = new Flow.Subscription() { @Override public void request(long n) { } @@ -75,7 +73,18 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { this.userSubscriber = userSubscriber; } - private class SubscriptionWrapper implements Subscription { + /** + * A callback to be invoked before termination, whether due to the + * completion or failure of the subscriber, or cancellation of the + * subscription. To be precise, this method is called before + * {@link #onComplete()}, {@link #onError(Throwable) onError()}, or + * {@link #onCancel()}. + */ + protected void onTermination() { + // Do nothing + } + + private final class SubscriptionWrapper implements Subscription { final Subscription subscription; SubscriptionWrapper(Subscription s) { this.subscription = Objects.requireNonNull(s); @@ -92,6 +101,7 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { subscription.cancel(); } finally { if (markCancelled()) { + onTermination(); onCancel(); } } @@ -284,6 +294,7 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { */ public final void complete(Throwable t) { if (markCompleted()) { + onTermination(); logComplete(t); tryUnregister(); t = withError = Utils.getCompletionCause(t); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java index 240f90852bc..c07df1c6eb2 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java @@ -174,17 +174,29 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece public static final int SMALLEST_MAXIMUM_DATAGRAM_SIZE = QuicClient.SMALLEST_MAXIMUM_DATAGRAM_SIZE; + // The default value for the Quic maxInitialTimeout, in seconds. Will be clamped to [1, Integer.MAX_vALUE] public static final int DEFAULT_MAX_INITIAL_TIMEOUT = Math.clamp( Utils.getIntegerProperty("jdk.httpclient.quic.maxInitialTimeout", 30), 1, Integer.MAX_VALUE); + // The default value for the initial_max_data transport parameter that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. public static final long DEFAULT_INITIAL_MAX_DATA = Math.clamp( Utils.getLongProperty("jdk.httpclient.quic.maxInitialData", 15 << 20), 0, 1L << 60); + // The default value for the initial_max_stream_data_bidi_local, initial_max_stream_data_bidi_remote, + // and initial_max_stream_data_uni transport parameters that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. public static final long DEFAULT_INITIAL_STREAM_MAX_DATA = Math.clamp( Utils.getIntegerProperty("jdk.httpclient.quic.maxStreamInitialData", 6 << 20), 0, 1L << 60); + // The default value for the initial_max_streams_bidi transport parameter that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. + // The Http3ClientImpl typically provides a value of 0, so this property has no effect + // on QuicConnectionImpl instances created on behalf of the HTTP/3 client public static final int DEFAULT_MAX_BIDI_STREAMS = - Utils.getIntegerProperty("jdk.httpclient.quic.maxBidiStreams", 100); + Utils.getIntegerProperty("jdk.internal.httpclient.quic.maxBidiStreams", 100); + // The default value for the initial_max_streams_uni transport parameter that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. public static final int DEFAULT_MAX_UNI_STREAMS = Utils.getIntegerProperty("jdk.httpclient.quic.maxUniStreams", 100); public static final boolean USE_DIRECT_BUFFER_POOL = Utils.getBooleanProperty( diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java index d0cb45ebc09..84a823f785f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java @@ -158,6 +158,11 @@ public enum Source { * 26, tbd */ JDK26("26"), + + /** + * 27, tbd + */ + JDK27("27"), ; // Reduce code churn when appending new constants private static final Context.Key sourceKey = new Context.Key<>(); @@ -210,6 +215,7 @@ public enum Source { public Target requiredTarget() { return switch(this) { + case JDK27 -> Target.JDK1_27; case JDK26 -> Target.JDK1_26; case JDK25 -> Target.JDK1_25; case JDK24 -> Target.JDK1_24; @@ -366,6 +372,7 @@ public enum Source { case JDK24 -> RELEASE_24; case JDK25 -> RELEASE_25; case JDK26 -> RELEASE_26; + case JDK27 -> RELEASE_27; default -> null; }; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java index e5adecdb107..ae1aab1cefd 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java @@ -130,6 +130,7 @@ public class ClassFile { V68(68, 0), // JDK 24 V69(69, 0), // JDK 25 V70(70, 0), // JDK 26 + V71(71, 0), // JDK 27 ; // Reduce code churn when appending new constants Version(int major, int minor) { this.major = major; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java index f60adcb3b80..b0a298fc845 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java @@ -113,6 +113,9 @@ public enum Target { /** JDK 26. */ JDK1_26("26", 70, 0), + + /** JDK 27. */ + JDK1_27("27", 71, 0), ; // Reduce code churn when appending new constants private static final Context.Key targetKey = new Context.Key<>(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java index c14767a7a8c..664ebc4c9c6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java @@ -33,6 +33,8 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.text.Collator; +import java.util.Collection; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; @@ -45,7 +47,6 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.StringJoiner; import java.util.TreeMap; -import java.util.TreeSet; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -323,12 +324,13 @@ public enum Option { @Override protected void help(Log log) { - StringJoiner sj = new StringJoiner(", "); + List releases = new ArrayList<>(); for(Source source : Source.values()) { if (source.isSupported()) - sj.add(source.name); + releases.add(source.name); } - super.help(log, log.localize(PrefixKind.JAVAC, descrKey, sj.toString())); + String formatted = formatAbbreviatedList(releases); + super.help(log, log.localize(PrefixKind.JAVAC, descrKey, formatted)); } }, @@ -344,12 +346,13 @@ public enum Option { @Override protected void help(Log log) { - StringJoiner sj = new StringJoiner(", "); + List releases = new ArrayList<>(); for(Target target : Target.values()) { if (target.isSupported()) - sj.add(target.name); + releases.add(target.name); } - super.help(log, log.localize(PrefixKind.JAVAC, descrKey, sj.toString())); + String formatted = formatAbbreviatedList(releases); + super.help(log, log.localize(PrefixKind.JAVAC, descrKey, formatted)); } }, @@ -364,15 +367,8 @@ public enum Option { false)) .collect(Collectors.toCollection(LinkedHashSet :: new)); - StringBuilder targets = new StringBuilder(); - String delim = ""; - for (String platform : platforms) { - targets.append(delim); - targets.append(platform); - delim = ", "; - } - - super.help(log, log.localize(PrefixKind.JAVAC, descrKey, targets.toString())); + String formatted = formatAbbreviatedList(platforms); + super.help(log, log.localize(PrefixKind.JAVAC, descrKey, formatted)); } }, @@ -1369,6 +1365,41 @@ public enum Option { log.printRawLines(WriterKind.STDOUT, LARGE_INDENT + descr.replace("\n", "\n" + LARGE_INDENT)); } + /** + * Formats a collection of values as an abbreviated, comma separated list + * for use in javac help output. + * + * This helper assumes that the supported values form a dense sequence + * between the fourth and the (n - 3)rd entries. + * That matches the current policy for these values but is not + * guaranteed, and should be reconsidered if the structure of the values changes. + * + * @param values the values to format + * @return a comma separated representation of the values + */ + private static String formatAbbreviatedList(Collection values) { + List list = (values instanceof List) + ? (List) values + : new ArrayList<>(values); + + int size = list.size(); + if (size == 0) { + return ""; + } + if (size <= 6) { + return String.join(", ", list); + } + StringJoiner sj = new StringJoiner(", "); + for (int i = 0; i < 3; i++) { + sj.add(list.get(i)); + } + sj.add("..."); + for (int i = size - 3; i < size; i++) { + sj.add(list.get(i)); + } + return sj.toString(); + } + /** * Composes the initial synopsis of one of the forms for this option. * @param name the name of this form of the option diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java index 7aaf035fd36..bcc9ccd0113 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java @@ -55,7 +55,7 @@ import com.sun.tools.javac.util.StringUtils; * deletion without notice. */ @SupportedAnnotationTypes("*") -@SupportedSourceVersion(SourceVersion.RELEASE_26) +@SupportedSourceVersion(SourceVersion.RELEASE_27) public class PrintingProcessor extends AbstractProcessor { PrintWriter writer; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties index d5ee9469d22..7824772b1f3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties @@ -100,7 +100,8 @@ javac.opt.arg.Werror=\ (,)* javac.opt.Werror.custom=\ Specify lint categories for which warnings should terminate compilation,\n\ - separated by comma. Precede a key by ''-'' to exclude the specified category.\n\ + separated by comma.\n\ + Precede a key by ''-'' to exclude the specified category.\n\ Use --help-lint to see the supported keys. javac.opt.A=\ Options to pass to annotation processors @@ -358,7 +359,8 @@ javac.opt.prefer=\ are found for an implicitly compiled class # L10N: do not localize: ''preview'' javac.opt.preview=\ - Enable preview language features. Also disables the ''preview'' lint category.\n\ + Enable preview language features.\n\ + Also disables the ''preview'' lint category.\n\ To be used in conjunction with either -source or --release. javac.opt.AT=\ Read options and filenames from file diff --git a/src/jdk.compiler/share/data/symbols/README b/src/jdk.compiler/share/data/symbols/README index 4c9f38f77b0..50f68bbe2f2 100644 --- a/src/jdk.compiler/share/data/symbols/README +++ b/src/jdk.compiler/share/data/symbols/README @@ -1,3 +1,3 @@ This directory contains history data for -release. -Please see $JDK_TOP_DIR/make/scripts/generate-symbol-data.sh for main usage. +Please see $JDK_TOP_DIR/bin/generate-symbol-data.sh for main usage. diff --git a/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt new file mode 100644 index 00000000000..fb1ec6ec7bb --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt @@ -0,0 +1,558 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name java.base +header exports java/io,java/lang,java/lang/annotation,java/lang/classfile,java/lang/classfile/attribute,java/lang/classfile/constantpool,java/lang/classfile/instruction,java/lang/constant,java/lang/foreign,java/lang/invoke,java/lang/module,java/lang/ref,java/lang/reflect,java/lang/runtime,java/math,java/net,java/net/spi,java/nio,java/nio/channels,java/nio/channels/spi,java/nio/charset,java/nio/charset/spi,java/nio/file,java/nio/file/attribute,java/nio/file/spi,java/security,java/security/cert,java/security/interfaces,java/security/spec,java/text,java/text/spi,java/time,java/time/chrono,java/time/format,java/time/temporal,java/time/zone,java/util,java/util/concurrent,java/util/concurrent/atomic,java/util/concurrent/locks,java/util/function,java/util/jar,java/util/random,java/util/regex,java/util/spi,java/util/stream,java/util/zip,javax/crypto,javax/crypto/interfaces,javax/crypto/spec,javax/net,javax/net/ssl,javax/security/auth,javax/security/auth/callback,javax/security/auth/login,javax/security/auth/spi,javax/security/auth/x500,javax/security/cert,jdk/internal/event[jdk.jfr],jdk/internal/javac[java.compiler\u005C;u002C;jdk.compiler],jdk/internal/vm/vector[jdk.incubator.vector] extraModulePackages jdk/internal/access/foreign,jdk/internal/classfile/impl,jdk/internal/constant,jdk/internal/foreign/abi,jdk/internal/foreign/abi/aarch64/linux,jdk/internal/foreign/abi/aarch64/macos,jdk/internal/foreign/abi/aarch64/windows,jdk/internal/foreign/abi/fallback,jdk/internal/foreign/abi/ppc64/aix,jdk/internal/foreign/abi/ppc64/linux,jdk/internal/foreign/abi/riscv64/linux,jdk/internal/foreign/abi/s390/linux,jdk/internal/foreign/abi/x64/sysv,jdk/internal/foreign/abi/x64/windows,jdk/internal/foreign/layout,jdk/internal/lang,sun/nio,sun/nio/ch,sun/net,jdk/internal/foreign,jdk/internal/foreign,sun/net,sun/nio/ch uses java/lang/System$LoggerFinder,java/net/ContentHandlerFactory,java/net/spi/InetAddressResolverProvider,java/net/spi/URLStreamHandlerProvider,java/nio/channels/spi/AsynchronousChannelProvider,java/nio/channels/spi/SelectorProvider,java/nio/charset/spi/CharsetProvider,java/nio/file/spi/FileSystemProvider,java/nio/file/spi/FileTypeDetector,java/security/Provider,java/text/spi/BreakIteratorProvider,java/text/spi/CollatorProvider,java/text/spi/DateFormatProvider,java/text/spi/DateFormatSymbolsProvider,java/text/spi/DecimalFormatSymbolsProvider,java/text/spi/NumberFormatProvider,java/time/chrono/AbstractChronology,java/time/chrono/Chronology,java/time/zone/ZoneRulesProvider,java/util/spi/CalendarDataProvider,java/util/spi/CalendarNameProvider,java/util/spi/CurrencyNameProvider,java/util/spi/LocaleNameProvider,java/util/spi/ResourceBundleControlProvider,java/util/spi/ResourceBundleProvider,java/util/spi/TimeZoneNameProvider,java/util/spi/ToolProvider,javax/security/auth/spi/LoginModule,jdk/internal/io/JdkConsoleProvider,jdk/internal/logger/DefaultLoggerFinder,sun/text/spi/JavaTimeDateTimePatternProvider,sun/util/locale/provider/LocaleDataMetaInfo,sun/util/resources/LocaleData$LocaleDataResourceBundleProvider,sun/util/spi/CalendarProvider provides interface\u0020;java/nio/file/spi/FileSystemProvider\u0020;impls\u0020;jdk/internal/jrtfs/JrtFileSystemProvider target macos-aarch64 flags 8000 + +class name java/lang/Character$UnicodeBlock +field name SIDETIC descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name SHARADA_SUPPLEMENT descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name TOLONG_SIKI descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name BERIA_ERFE descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name TANGUT_COMPONENTS_SUPPLEMENT descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name MISCELLANEOUS_SYMBOLS_SUPPLEMENT descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name TAI_YO descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name CJK_UNIFIED_IDEOGRAPHS_EXTENSION_J descriptor Ljava/lang/Character$UnicodeBlock; flags 19 + +class name java/lang/Character$UnicodeScript +field name SIDETIC descriptor Ljava/lang/Character$UnicodeScript; flags 4019 +field name TOLONG_SIKI descriptor Ljava/lang/Character$UnicodeScript; flags 4019 +field name BERIA_ERFE descriptor Ljava/lang/Character$UnicodeScript; flags 4019 +field name TAI_YO descriptor Ljava/lang/Character$UnicodeScript; flags 4019 + +class name java/lang/Class +header extends java/lang/Object implements java/io/Serializable,java/lang/reflect/GenericDeclaration,java/lang/reflect/Type,java/lang/reflect/AnnotatedElement,java/lang/invoke/TypeDescriptor$OfField,java/lang/constant/Constable flags 31 signature Ljava/lang/Object;Ljava/io/Serializable;Ljava/lang/reflect/GenericDeclaration;Ljava/lang/reflect/Type;Ljava/lang/reflect/AnnotatedElement;Ljava/lang/invoke/TypeDescriptor$OfField;>;Ljava/lang/constant/Constable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/TypeDescriptor$OfField outerClass java/lang/invoke/TypeDescriptor innerClassName OfField flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/ClassLoader +header extends java/lang/Object flags 421 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/LazyConstant +header extends java/lang/Object implements java/util/function/Supplier sealed true permittedSubclasses jdk/internal/lang/LazyConstantImpl flags 601 signature Ljava/lang/Object;Ljava/util/function/Supplier; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LAZY_CONSTANTS;) +method name orElse descriptor (Ljava/lang/Object;)Ljava/lang/Object; flags 401 signature (TT;)TT; +method name get descriptor ()Ljava/lang/Object; flags 401 signature ()TT; +method name isInitialized descriptor ()Z flags 401 +method name equals descriptor (Ljava/lang/Object;)Z flags 401 +method name hashCode descriptor ()I flags 401 +method name toString descriptor ()Ljava/lang/String; flags 401 +method name of descriptor (Ljava/util/function/Supplier;)Ljava/lang/LazyConstant; flags 9 signature (Ljava/util/function/Supplier<+TT;>;)Ljava/lang/LazyConstant; + +class name java/lang/Math +-method name sinh descriptor (D)D +method name sinh descriptor (D)D flags 9 runtimeAnnotations @Ljdk/internal/vm/annotation/IntrinsicCandidate; + +class name java/lang/Object +header flags 21 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/lang/Process +header extends java/lang/Object implements java/io/Closeable flags 421 +innerclass innerClass java/util/concurrent/ForkJoinPool$ManagedBlocker outerClass java/util/concurrent/ForkJoinPool innerClassName ManagedBlocker flags 609 +innerclass innerClass java/lang/ProcessHandle$Info outerClass java/lang/ProcessHandle innerClassName Info flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name close descriptor ()V thrownTypes java/io/IOException flags 1 + +-class name java/lang/StableValue + +class name java/lang/Thread +-method name stop descriptor ()V + +class name java/lang/classfile/ClassFile +field name JAVA_26_VERSION descriptor I constantValue 70 flags 19 + +class name java/lang/classfile/Signature$ClassTypeSig +-method name of descriptor (Ljava/lang/classfile/Signature$ClassTypeSig;Ljava/lang/constant/ClassDesc;[Ljava/lang/classfile/Signature$TypeArg;)Ljava/lang/classfile/Signature$ClassTypeSig; +method name of descriptor (Ljava/lang/classfile/Signature$ClassTypeSig;Ljava/lang/constant/ClassDesc;[Ljava/lang/classfile/Signature$TypeArg;)Ljava/lang/classfile/Signature$ClassTypeSig; flags 89 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +-class name java/lang/constant/AsTypeMethodHandleDesc + +class name java/lang/constant/ConstantDescs +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 + +class name java/lang/constant/DynamicConstantDesc +header extends java/lang/Object implements java/lang/constant/ConstantDesc flags 421 signature Ljava/lang/Object;Ljava/lang/constant/ConstantDesc; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/Enum$EnumDesc outerClass java/lang/Enum innerClassName EnumDesc flags 19 +innerclass innerClass java/lang/invoke/VarHandle$VarHandleDesc outerClass java/lang/invoke/VarHandle innerClassName VarHandleDesc flags 19 + +class name java/lang/constant/MethodHandleDesc +header extends java/lang/Object implements java/lang/constant/ConstantDesc sealed true permittedSubclasses jdk/internal/constant/AsTypeMethodHandleDesc,java/lang/constant/DirectMethodHandleDesc flags 601 +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/invoke/BoundMethodHandle +header extends java/lang/invoke/MethodHandle flags 420 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/lang/invoke/DelegatingMethodHandle +header extends java/lang/invoke/MethodHandle sealed true permittedSubclasses java/lang/invoke/MethodHandleImpl$AsVarargsCollector,java/lang/invoke/MethodHandleImpl$WrappedMember,java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle,java/lang/invoke/MethodHandleImpl$CountingWrapper flags 420 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$AsVarargsCollector outerClass java/lang/invoke/MethodHandleImpl innerClassName AsVarargsCollector flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$WrappedMember outerClass java/lang/invoke/MethodHandleImpl innerClassName WrappedMember flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle outerClass java/lang/invoke/MethodHandleImpl innerClassName IntrinsicMethodHandle flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$CountingWrapper outerClass java/lang/invoke/MethodHandleImpl innerClassName CountingWrapper flags 18 + +class name java/lang/invoke/DirectMethodHandle +header extends java/lang/invoke/MethodHandle nestMembers java/lang/invoke/DirectMethodHandle$StaticAccessor,java/lang/invoke/DirectMethodHandle$Accessor,java/lang/invoke/DirectMethodHandle$Constructor,java/lang/invoke/DirectMethodHandle$Interface,java/lang/invoke/DirectMethodHandle$Special sealed true permittedSubclasses java/lang/invoke/DirectMethodHandle$Special,java/lang/invoke/DirectMethodHandle$Interface,java/lang/invoke/DirectMethodHandle$Constructor,java/lang/invoke/DirectMethodHandle$Accessor,java/lang/invoke/DirectMethodHandle$StaticAccessor flags 20 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/DirectMethodHandle$Special outerClass java/lang/invoke/DirectMethodHandle innerClassName Special flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$Interface outerClass java/lang/invoke/DirectMethodHandle innerClassName Interface flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$StaticAccessor outerClass java/lang/invoke/DirectMethodHandle innerClassName StaticAccessor flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$Accessor outerClass java/lang/invoke/DirectMethodHandle innerClassName Accessor flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$Constructor outerClass java/lang/invoke/DirectMethodHandle innerClassName Constructor flags 18 + +class name java/lang/invoke/DirectMethodHandle$Constructor +header extends java/lang/invoke/DirectMethodHandle nestHost java/lang/invoke/DirectMethodHandle flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/DirectMethodHandle$Constructor outerClass java/lang/invoke/DirectMethodHandle innerClassName Constructor flags 18 + +class name java/lang/invoke/LambdaForm +header extends java/lang/Object flags 20 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/lang/invoke/LambdaMetafactory +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/invoke/MethodHandle +header extends java/lang/Object implements java/lang/constant/Constable sealed true permittedSubclasses java/lang/invoke/NativeMethodHandle,java/lang/invoke/DirectMethodHandle,java/lang/invoke/DelegatingMethodHandle,java/lang/invoke/BoundMethodHandle flags 421 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 + +class name java/lang/invoke/MethodHandleImpl +header extends java/lang/Object nestMembers java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle,java/lang/invoke/MethodHandleImpl$WrappedMember,java/lang/invoke/MethodHandleImpl$CountingWrapper,java/lang/invoke/MethodHandleImpl$AsVarargsCollector flags 420 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/MethodHandleImpl$AsVarargsCollector outerClass java/lang/invoke/MethodHandleImpl innerClassName AsVarargsCollector flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$CountingWrapper outerClass java/lang/invoke/MethodHandleImpl innerClassName CountingWrapper flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$WrappedMember outerClass java/lang/invoke/MethodHandleImpl innerClassName WrappedMember flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle outerClass java/lang/invoke/MethodHandleImpl innerClassName IntrinsicMethodHandle flags 18 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/invoke/MethodHandleImpl$AsVarargsCollector +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$AsVarargsCollector outerClass java/lang/invoke/MethodHandleImpl innerClassName AsVarargsCollector flags 18 + +class name java/lang/invoke/MethodHandleImpl$CountingWrapper +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$CountingWrapper outerClass java/lang/invoke/MethodHandleImpl innerClassName CountingWrapper flags 18 + +class name java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle outerClass java/lang/invoke/MethodHandleImpl innerClassName IntrinsicMethodHandle flags 18 + +class name java/lang/invoke/MethodHandleImpl$WrappedMember +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$WrappedMember outerClass java/lang/invoke/MethodHandleImpl innerClassName WrappedMember flags 18 + +class name java/lang/invoke/MethodHandles +header extends java/lang/Object nestMembers java/lang/invoke/MethodHandles$Lookup,java/lang/invoke/MethodHandles$Lookup$ClassOption flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/invoke/VarHandle$AccessMode outerClass java/lang/invoke/VarHandle innerClassName AccessMode flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup$ClassOption outerClass java/lang/invoke/MethodHandles$Lookup innerClassName ClassOption flags 4019 + +class name java/lang/invoke/StringConcatFactory +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/module/ModuleDescriptor +header extends java/lang/Object implements java/lang/Comparable nestMembers java/lang/module/ModuleDescriptor$Builder,java/lang/module/ModuleDescriptor$Version,java/lang/module/ModuleDescriptor$Provides,java/lang/module/ModuleDescriptor$Opens,java/lang/module/ModuleDescriptor$Opens$Modifier,java/lang/module/ModuleDescriptor$Exports,java/lang/module/ModuleDescriptor$Exports$Modifier,java/lang/module/ModuleDescriptor$Requires,java/lang/module/ModuleDescriptor$Requires$Modifier,java/lang/module/ModuleDescriptor$Modifier flags 31 signature Ljava/lang/Object;Ljava/lang/Comparable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/module/ModuleDescriptor$Version outerClass java/lang/module/ModuleDescriptor innerClassName Version flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Modifier outerClass java/lang/module/ModuleDescriptor innerClassName Modifier flags 4019 +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/lang/module/ModuleDescriptor$Builder outerClass java/lang/module/ModuleDescriptor innerClassName Builder flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Provides outerClass java/lang/module/ModuleDescriptor innerClassName Provides flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Opens outerClass java/lang/module/ModuleDescriptor innerClassName Opens flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Exports outerClass java/lang/module/ModuleDescriptor innerClassName Exports flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Requires outerClass java/lang/module/ModuleDescriptor innerClassName Requires flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Opens$Modifier outerClass java/lang/module/ModuleDescriptor$Opens innerClassName Modifier flags 4019 +innerclass innerClass java/lang/module/ModuleDescriptor$Exports$Modifier outerClass java/lang/module/ModuleDescriptor$Exports innerClassName Modifier flags 4019 +innerclass innerClass java/lang/module/ModuleDescriptor$Requires$Modifier outerClass java/lang/module/ModuleDescriptor$Requires innerClassName Modifier flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/ref/PhantomReference +header extends java/lang/ref/Reference flags 21 signature Ljava/lang/ref/Reference; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/ref/Reference +header extends java/lang/Object sealed true permittedSubclasses java/lang/ref/PhantomReference,java/lang/ref/SoftReference,java/lang/ref/WeakReference,java/lang/ref/FinalReference flags 421 signature Ljava/lang/Object; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} +-method name get descriptor ()Ljava/lang/Object; +method name get descriptor ()Ljava/lang/Object; flags 1 signature ()TT; + +class name java/lang/ref/ReferenceQueue +header extends java/lang/Object flags 21 signature Ljava/lang/Object; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/ref/SoftReference +header extends java/lang/ref/Reference flags 21 signature Ljava/lang/ref/Reference; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/ref/WeakReference +header extends java/lang/ref/Reference flags 21 signature Ljava/lang/ref/Reference; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/reflect/ClassFileFormatVersion +field name RELEASE_26 descriptor Ljava/lang/reflect/ClassFileFormatVersion; flags 4019 + +class name java/lang/reflect/Field +header extends java/lang/reflect/AccessibleObject implements java/lang/reflect/Member flags 31 +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/lang/StackWalker$Option outerClass java/lang/StackWalker innerClassName Option flags 4019 +innerclass innerClass java/lang/StackWalker$StackFrame outerClass java/lang/StackWalker innerClassName StackFrame flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/runtime/ObjectMethods +header extends java/lang/Object flags 31 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/classfile/ClassFile$Option outerClass java/lang/classfile/ClassFile innerClassName Option flags 609 +innerclass innerClass java/lang/classfile/ClassFile$ClassHierarchyResolverOption outerClass java/lang/classfile/ClassFile innerClassName ClassHierarchyResolverOption flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup$ClassOption outerClass java/lang/invoke/MethodHandles$Lookup innerClassName ClassOption flags 4019 + +class name java/math/BigInteger +method name rootn descriptor (I)Ljava/math/BigInteger; flags 1 +method name rootnAndRemainder descriptor (I)[Ljava/math/BigInteger; flags 1 + +class name java/net/DatagramSocketImpl +-method name setTTL descriptor (B)V +-method name getTTL descriptor ()B + +class name java/net/MulticastSocket +-method name setTTL descriptor (B)V +-method name getTTL descriptor ()B +-method name send descriptor (Ljava/net/DatagramPacket;B)V + +class name java/net/ServerSocket +-method name setPerformancePreferences descriptor (III)V +method name setPerformancePreferences descriptor (III)V flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/net/Socket +-method name setPerformancePreferences descriptor (III)V +method name setPerformancePreferences descriptor (III)V flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/net/SocketImpl +-method name setPerformancePreferences descriptor (III)V +method name setPerformancePreferences descriptor (III)V flags 4 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/net/SocketPermission +header extends java/security/Permission implements java/io/Serializable flags 31 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/net/URI +header extends java/lang/Object implements java/lang/Comparable,java/io/Serializable flags 31 signature Ljava/lang/Object;Ljava/lang/Comparable;Ljava/io/Serializable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/text/Normalizer$Form outerClass java/text/Normalizer innerClassName Form flags 4019 + +class name java/net/URL +header extends java/lang/Object implements java/io/Serializable flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/ScopedValue$Carrier outerClass java/lang/ScopedValue innerClassName Carrier flags 19 +innerclass innerClass java/lang/ScopedValue$CallableOp outerClass java/lang/ScopedValue innerClassName CallableOp flags 609 +innerclass innerClass java/io/ObjectInputStream$GetField outerClass java/io/ObjectInputStream innerClassName GetField flags 409 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/nio/ByteOrder +header extends java/lang/Enum flags 4031 signature Ljava/lang/Enum; +-field name BIG_ENDIAN descriptor Ljava/nio/ByteOrder; +-field name LITTLE_ENDIAN descriptor Ljava/nio/ByteOrder; +-method name toString descriptor ()Ljava/lang/String; +field name LITTLE_ENDIAN descriptor Ljava/nio/ByteOrder; flags 4019 +field name BIG_ENDIAN descriptor Ljava/nio/ByteOrder; flags 4019 +method name values descriptor ()[Ljava/nio/ByteOrder; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljava/nio/ByteOrder; flags 9 methodParameters 8000:null + +class name java/nio/DirectByteBuffer +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectCharBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectCharBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectDoubleBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectDoubleBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectFloatBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectFloatBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectIntBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectIntBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectLongBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectLongBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectShortBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectShortBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/charset/Charset +header extends java/lang/Object implements java/lang/Comparable flags 421 signature Ljava/lang/Object;Ljava/lang/Comparable; +innerclass innerClass java/lang/ScopedValue$Carrier outerClass java/lang/ScopedValue innerClassName Carrier flags 19 +innerclass innerClass java/lang/ScopedValue$CallableOp outerClass java/lang/ScopedValue innerClassName CallableOp flags 609 + +class name java/security/DEREncodable +header extends java/lang/Object sealed true permittedSubclasses java/security/AsymmetricKey,java/security/KeyPair,java/security/spec/PKCS8EncodedKeySpec,java/security/spec/X509EncodedKeySpec,javax/crypto/EncryptedPrivateKeyInfo,java/security/cert/X509Certificate,java/security/cert/X509CRL,java/security/PEM flags 601 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) + +class name java/security/PEM +header extends java/lang/Record implements java/security/DEREncodable record true flags 31 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +recordcomponent name type descriptor Ljava/lang/String; +recordcomponent name content descriptor Ljava/lang/String; +recordcomponent name leadingData descriptor [B +innerclass innerClass java/util/Base64$Decoder outerClass java/util/Base64 innerClassName Decoder flags 9 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name descriptor (Ljava/lang/String;Ljava/lang/String;[B)V flags 1 methodParameters 8000:type,8000:content,8000:leadingData +method name descriptor (Ljava/lang/String;Ljava/lang/String;)V flags 1 +method name toString descriptor ()Ljava/lang/String; flags 11 +method name decode descriptor ()[B flags 11 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name type descriptor ()Ljava/lang/String; flags 1 +method name content descriptor ()Ljava/lang/String; flags 1 +method name leadingData descriptor ()[B flags 1 + +class name java/security/PEMDecoder +header extends java/lang/Object flags 31 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +innerclass innerClass java/lang/ref/Cleaner$Cleanable outerClass java/lang/ref/Cleaner innerClassName Cleanable flags 609 +innerclass innerClass java/util/Base64$Decoder outerClass java/util/Base64 innerClassName Decoder flags 9 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +-class name java/security/PEMRecord + +class name java/security/SecureRandom +method name nextLong descriptor ()J flags 1 + +class name java/time/Duration +field name MIN descriptor Ljava/time/Duration; flags 19 +field name MAX descriptor Ljava/time/Duration; flags 19 + +class name java/time/Instant +method name plusSaturating descriptor (Ljava/time/Duration;)Ljava/time/Instant; flags 1 + +class name java/util/AbstractMap +header extends java/lang/Object implements java/util/Map nestMembers java/util/AbstractMap$SimpleImmutableEntry,java/util/AbstractMap$SimpleEntry flags 421 signature Ljava/lang/Object;Ljava/util/Map; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/util/AbstractMap$SimpleImmutableEntry outerClass java/util/AbstractMap innerClassName SimpleImmutableEntry flags 9 +innerclass innerClass java/util/AbstractMap$SimpleEntry outerClass java/util/AbstractMap innerClassName SimpleEntry flags 9 + +class name java/util/Collections +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/util/Comparator +method name max descriptor (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; flags 1 signature (TU;TU;)TU; +method name min descriptor (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; flags 1 signature (TU;TU;)TU; + +class name java/util/List +method name ofLazy descriptor (ILjava/util/function/IntFunction;)Ljava/util/List; flags 9 signature (ILjava/util/function/IntFunction<+TE;>;)Ljava/util/List; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LAZY_CONSTANTS;) + +class name java/util/Locale +header extends java/lang/Object implements java/lang/Cloneable,java/io/Serializable nestMembers java/util/Locale$LanguageRange,java/util/Locale$FilteringMode,java/util/Locale$Builder,java/util/Locale$Category,java/util/Locale$IsoCountryCode flags 31 +innerclass innerClass java/util/Locale$Category outerClass java/util/Locale innerClassName Category flags 4019 +innerclass innerClass java/util/Locale$IsoCountryCode outerClass java/util/Locale innerClassName IsoCountryCode flags 4019 +innerclass innerClass java/io/ObjectOutputStream$PutField outerClass java/io/ObjectOutputStream innerClassName PutField flags 409 +innerclass innerClass java/io/ObjectInputStream$GetField outerClass java/io/ObjectInputStream innerClassName GetField flags 409 +innerclass innerClass java/util/Locale$FilteringMode outerClass java/util/Locale innerClassName FilteringMode flags 4019 +innerclass innerClass java/util/Locale$LanguageRange outerClass java/util/Locale innerClassName LanguageRange flags 19 +innerclass innerClass java/util/Locale$Builder outerClass java/util/Locale innerClassName Builder flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/util/Locale$IsoCountryCode +header extends java/lang/Enum nestHost java/util/Locale flags 4031 signature Ljava/lang/Enum; +innerclass innerClass java/util/Locale$IsoCountryCode outerClass java/util/Locale innerClassName IsoCountryCode flags 4019 + +class name java/util/Map +method name ofLazy descriptor (Ljava/util/Set;Ljava/util/function/Function;)Ljava/util/Map; flags 9 signature (Ljava/util/Set<+TK;>;Ljava/util/function/Function<-TK;+TV;>;)Ljava/util/Map; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LAZY_CONSTANTS;) + +class name java/util/UUID +method name ofEpochMillis descriptor (J)Ljava/util/UUID; flags 9 + +class name java/util/WeakHashMap +header extends java/util/AbstractMap implements java/util/Map flags 21 signature Ljava/util/AbstractMap;Ljava/util/Map; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 + +class name java/util/concurrent/ConcurrentHashMap +header extends java/util/AbstractMap implements java/util/concurrent/ConcurrentMap,java/io/Serializable nestMembers java/util/concurrent/ConcurrentHashMap$EntrySetView,java/util/concurrent/ConcurrentHashMap$ValuesView,java/util/concurrent/ConcurrentHashMap$KeySetView,java/util/concurrent/ConcurrentHashMap$CollectionView flags 21 signature Ljava/util/AbstractMap;Ljava/util/concurrent/ConcurrentMap;Ljava/io/Serializable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$KeySetView outerClass java/util/concurrent/ConcurrentHashMap innerClassName KeySetView flags 19 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$ValuesView outerClass java/util/concurrent/ConcurrentHashMap innerClassName ValuesView flags 18 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$EntrySetView outerClass java/util/concurrent/ConcurrentHashMap innerClassName EntrySetView flags 18 +innerclass innerClass java/io/ObjectOutputStream$PutField outerClass java/io/ObjectOutputStream innerClassName PutField flags 409 +innerclass innerClass java/util/AbstractMap$SimpleImmutableEntry outerClass java/util/AbstractMap innerClassName SimpleImmutableEntry flags 9 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$CollectionView outerClass java/util/concurrent/ConcurrentHashMap innerClassName CollectionView flags 408 + +class name java/util/concurrent/StructuredTaskScope +-method name open descriptor (Ljava/util/concurrent/StructuredTaskScope$Joiner;Ljava/util/function/Function;)Ljava/util/concurrent/StructuredTaskScope; +method name open descriptor (Ljava/util/concurrent/StructuredTaskScope$Joiner;Ljava/util/function/UnaryOperator;)Ljava/util/concurrent/StructuredTaskScope; flags 9 signature (Ljava/util/concurrent/StructuredTaskScope$Joiner<-TT;+TR;>;Ljava/util/function/UnaryOperator;)Ljava/util/concurrent/StructuredTaskScope; + +class name java/util/concurrent/StructuredTaskScope$Joiner +header extends java/lang/Object nestHost java/util/concurrent/StructuredTaskScope flags 601 signature Ljava/lang/Object; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;STRUCTURED_CONCURRENCY;) +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 +innerclass innerClass java/util/concurrent/StructuredTaskScope$TimeoutException outerClass java/util/concurrent/StructuredTaskScope innerClassName TimeoutException flags 19 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Joiner outerClass java/util/concurrent/StructuredTaskScope innerClassName Joiner flags 609 +-method name onFork descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +-method name onComplete descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +-method name allSuccessfulOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; +-method name anySuccessfulResultOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; +-method name allUntil descriptor (Ljava/util/function/Predicate;)Ljava/util/concurrent/StructuredTaskScope$Joiner; +method name onFork descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z flags 1 signature (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +method name onComplete descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z flags 1 signature (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +method name onTimeout descriptor ()V flags 1 +method name allSuccessfulOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; flags 9 signature ()Ljava/util/concurrent/StructuredTaskScope$Joiner;>; +method name anySuccessfulOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; flags 9 signature ()Ljava/util/concurrent/StructuredTaskScope$Joiner; +method name allUntil descriptor (Ljava/util/function/Predicate;)Ljava/util/concurrent/StructuredTaskScope$Joiner; flags 9 signature (Ljava/util/function/Predicate;>;)Ljava/util/concurrent/StructuredTaskScope$Joiner;>;>; + +class name java/util/concurrent/StructuredTaskScopeImpl +header extends java/lang/Object implements java/util/concurrent/StructuredTaskScope nestMembers java/util/concurrent/StructuredTaskScopeImpl$ConfigImpl,java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl flags 30 signature Ljava/lang/Object;Ljava/util/concurrent/StructuredTaskScope; +innerclass innerClass java/util/concurrent/StructuredTaskScope$Joiner outerClass java/util/concurrent/StructuredTaskScope innerClassName Joiner flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScopeImpl$ConfigImpl outerClass java/util/concurrent/StructuredTaskScopeImpl innerClassName ConfigImpl flags 18 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Configuration outerClass java/util/concurrent/StructuredTaskScope innerClassName Configuration flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl outerClass java/util/concurrent/StructuredTaskScopeImpl innerClassName SubtaskImpl flags 18 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 +innerclass innerClass java/util/concurrent/StructuredTaskScope$FailedException outerClass java/util/concurrent/StructuredTaskScope innerClassName FailedException flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl +header extends java/lang/Object implements java/util/concurrent/StructuredTaskScope$Subtask,java/lang/Runnable nestHost java/util/concurrent/StructuredTaskScopeImpl flags 30 signature Ljava/lang/Object;Ljava/util/concurrent/StructuredTaskScope$Subtask;Ljava/lang/Runnable; +innerclass innerClass java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl outerClass java/util/concurrent/StructuredTaskScopeImpl innerClassName SubtaskImpl flags 18 +innerclass innerClass java/lang/Thread$State outerClass java/lang/Thread innerClassName State flags 4019 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 + +class name java/util/stream/Collectors +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/stream/Collector$Characteristics outerClass java/util/stream/Collector innerClassName Characteristics flags 4019 +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name javax/crypto/EncryptedPrivateKeyInfo +header extends java/lang/Object implements java/security/DEREncodable flags 21 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +-method name encryptKey descriptor (Ljava/security/PrivateKey;[CLjava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;)Ljavax/crypto/EncryptedPrivateKeyInfo; +-method name encryptKey descriptor (Ljava/security/PrivateKey;[C)Ljavax/crypto/EncryptedPrivateKeyInfo; +-method name encryptKey descriptor (Ljava/security/PrivateKey;Ljava/security/Key;Ljava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;Ljava/security/SecureRandom;)Ljavax/crypto/EncryptedPrivateKeyInfo; +-method name getKey descriptor ([C)Ljava/security/PrivateKey; +-method name getKey descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/PrivateKey; +method name encrypt descriptor (Ljava/security/DEREncodable;[CLjava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;)Ljavax/crypto/EncryptedPrivateKeyInfo; flags 9 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name encrypt descriptor (Ljava/security/DEREncodable;[C)Ljavax/crypto/EncryptedPrivateKeyInfo; flags 9 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name encrypt descriptor (Ljava/security/DEREncodable;Ljava/security/Key;Ljava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;Ljava/security/SecureRandom;)Ljavax/crypto/EncryptedPrivateKeyInfo; flags 9 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKey descriptor ([C)Ljava/security/PrivateKey; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKey descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/PrivateKey; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKeyPair descriptor ([C)Ljava/security/KeyPair; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKeyPair descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/KeyPair; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) + +class name jdk/internal/classfile/impl/DirectCodeBuilder +header extends jdk/internal/classfile/impl/AbstractDirectBuilder implements jdk/internal/classfile/impl/TerminalCodeBuilder flags 31 signature Ljdk/internal/classfile/impl/AbstractDirectBuilder;Ljdk/internal/classfile/impl/TerminalCodeBuilder; +innerclass innerClass jdk/internal/classfile/impl/AbstractPseudoInstruction$ExceptionCatchImpl outerClass jdk/internal/classfile/impl/AbstractPseudoInstruction innerClassName ExceptionCatchImpl flags 19 +innerclass innerClass java/lang/classfile/Opcode$Kind outerClass java/lang/classfile/Opcode innerClassName Kind flags 4019 + +class name jdk/internal/classfile/impl/SignaturesImpl +method name nextIdentifierEnd descriptor (Ljava/lang/String;I)I flags 9 +method name validateIdentifier descriptor (Ljava/lang/String;)Ljava/lang/String; flags 9 +method name validatePackageSpecifierPlusIdentifier descriptor (Ljava/lang/String;)Ljava/lang/String; flags 9 +method name validateNonVoid descriptor (Ljava/lang/classfile/Signature;)Ljava/lang/classfile/Signature; flags 9 +method name validateArgumentList descriptor ([Ljava/lang/classfile/Signature;)Ljava/util/List; flags 9 signature ([Ljava/lang/classfile/Signature;)Ljava/util/List; +method name validateArgumentList descriptor (Ljava/util/List;)Ljava/util/List; flags 9 signature (Ljava/util/List;)Ljava/util/List; + +class name jdk/internal/classfile/impl/Util +header extends java/lang/Object nestMembers jdk/internal/classfile/impl/Util$WritableLocalVariable,jdk/internal/classfile/impl/Util$Writable flags 31 +innerclass innerClass java/lang/classfile/AttributeMapper$AttributeStability outerClass java/lang/classfile/AttributeMapper innerClassName AttributeStability flags 4019 +innerclass innerClass java/lang/classfile/ClassFile$AttributesProcessingOption outerClass java/lang/classfile/ClassFile innerClassName AttributesProcessingOption flags 4019 +innerclass innerClass java/lang/classfile/Opcode$Kind outerClass java/lang/classfile/Opcode innerClassName Kind flags 4019 +innerclass innerClass jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl outerClass jdk/internal/classfile/impl/AbstractPoolEntry innerClassName Utf8EntryImpl flags 19 +innerclass innerClass jdk/internal/classfile/impl/Util$Writable outerClass jdk/internal/classfile/impl/Util innerClassName Writable flags 608 +innerclass innerClass jdk/internal/classfile/impl/Util$WritableLocalVariable outerClass jdk/internal/classfile/impl/Util innerClassName WritableLocalVariable flags 608 +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name sanitizeU1List descriptor (Ljava/util/List;)Ljava/util/List; flags 9 signature (Ljava/util/List;)Ljava/util/List; +method name sanitizeU2List descriptor (Ljava/util/Collection;)Ljava/util/List; flags 9 signature (Ljava/util/Collection;)Ljava/util/List; +method name sanitizeParameterAnnotations descriptor (Ljava/util/List;)Ljava/util/List; flags 9 signature (Ljava/util/List;>;)Ljava/util/List;>; +method name checkU1 descriptor (ILjava/lang/String;)I flags 9 +method name checkU2 descriptor (ILjava/lang/String;)C flags 9 +method name outOfRangeException descriptor (ILjava/lang/String;Ljava/lang/String;)Ljava/lang/IllegalArgumentException; flags 9 +method name checkFlags descriptor (I)C flags 9 + +class name jdk/internal/constant/AsTypeMethodHandleDesc +header extends java/lang/constant/DynamicConstantDesc implements java/lang/constant/MethodHandleDesc flags 31 signature Ljava/lang/constant/DynamicConstantDesc;Ljava/lang/constant/MethodHandleDesc; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 +method name descriptor (Ljava/lang/constant/MethodHandleDesc;Ljava/lang/constant/MethodTypeDesc;)V flags 1 +method name invocationType descriptor ()Ljava/lang/constant/MethodTypeDesc; flags 1 +method name resolveConstantDesc descriptor (Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/invoke/MethodHandle; thrownTypes java/lang/ReflectiveOperationException flags 1 +method name toString descriptor ()Ljava/lang/String; flags 1 +method name resolveConstantDesc descriptor (Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/Object; thrownTypes java/lang/ReflectiveOperationException flags 1041 methodParameters 1000:null + +class name jdk/internal/constant/PrimitiveClassDescImpl +header extends java/lang/constant/DynamicConstantDesc implements java/lang/constant/ClassDesc flags 31 signature Ljava/lang/constant/DynamicConstantDesc;>;Ljava/lang/constant/ClassDesc; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/invoke/TypeDescriptor$OfField outerClass java/lang/invoke/TypeDescriptor innerClassName OfField flags 609 + +class name jdk/internal/lang/LazyConstantImpl +header extends java/lang/Object implements java/lang/LazyConstant flags 31 signature Ljava/lang/Object;Ljava/lang/LazyConstant; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +method name get descriptor ()Ljava/lang/Object; flags 1 signature ()TT; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; +method name orElse descriptor (Ljava/lang/Object;)Ljava/lang/Object; flags 1 signature (TT;)TT; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; +method name isInitialized descriptor ()Z flags 1 runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; +method name toString descriptor ()Ljava/lang/String; flags 1 +method name ofLazy descriptor (Ljava/util/function/Supplier;)Ljdk/internal/lang/LazyConstantImpl; flags 9 signature (Ljava/util/function/Supplier<+TT;>;)Ljdk/internal/lang/LazyConstantImpl; + +-class name jdk/internal/lang/stable/StableValueImpl + +class name jdk/internal/vm/vector/VectorSupport +-method name loadWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)Ljdk/internal/vm/vector/VectorSupport$Vector; +-method name storeWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V +method name loadWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)Ljdk/internal/vm/vector/VectorSupport$Vector; flags 9 signature ;W:Ljdk/internal/vm/vector/VectorSupport$Vector;S:Ljdk/internal/vm/vector/VectorSupport$VectorSpecies;M:Ljdk/internal/vm/vector/VectorSupport$VectorMask;E:Ljava/lang/Object;>(Ljava/lang/Class<+TV;>;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class<+Ljdk/internal/vm/vector/VectorSupport$Vector;>;ILjava/lang/Object;JTW;TW;TW;TW;TM;TC;I[IITS;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)TV; runtimeAnnotations @Ljdk/internal/vm/annotation/IntrinsicCandidate; +method name storeWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V flags 9 signature ;W:Ljdk/internal/vm/vector/VectorSupport$Vector;M:Ljdk/internal/vm/vector/VectorSupport$VectorMask;E:Ljava/lang/Object;>(Ljava/lang/Class<+TV;>;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class<+Ljdk/internal/vm/vector/VectorSupport$Vector;>;ILjava/lang/Object;JTW;TV;TM;TC;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V runtimeAnnotations @Ljdk/internal/vm/annotation/IntrinsicCandidate; + +class name sun/nio/Cleaner +header extends java/lang/Object flags 601 +method name clean descriptor ()V flags 401 + +class name sun/nio/ch/DirectBuffer +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 401 + diff --git a/src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt new file mode 100644 index 00000000000..cb6ad893ace --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt @@ -0,0 +1,85 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name javax/lang/model/SourceVersion +field name RELEASE_26 descriptor Ljavax/lang/model/SourceVersion; flags 4019 + +class name javax/lang/model/util/AbstractAnnotationValueVisitor14 +header extends javax/lang/model/util/AbstractAnnotationValueVisitor9 flags 421 signature Ljavax/lang/model/util/AbstractAnnotationValueVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractAnnotationValueVisitorPreview +header extends javax/lang/model/util/AbstractAnnotationValueVisitor14 flags 421 signature Ljavax/lang/model/util/AbstractAnnotationValueVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractElementVisitor14 +header extends javax/lang/model/util/AbstractElementVisitor9 flags 421 signature Ljavax/lang/model/util/AbstractElementVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractElementVisitorPreview +header extends javax/lang/model/util/AbstractElementVisitor14 flags 421 signature Ljavax/lang/model/util/AbstractElementVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractTypeVisitor14 +header extends javax/lang/model/util/AbstractTypeVisitor9 flags 421 signature Ljavax/lang/model/util/AbstractTypeVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractTypeVisitorPreview +header extends javax/lang/model/util/AbstractTypeVisitor14 flags 421 signature Ljavax/lang/model/util/AbstractTypeVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementKindVisitor14 +header extends javax/lang/model/util/ElementKindVisitor9 flags 21 signature Ljavax/lang/model/util/ElementKindVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementKindVisitorPreview +header extends javax/lang/model/util/ElementKindVisitor14 flags 21 signature Ljavax/lang/model/util/ElementKindVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementScanner14 +header extends javax/lang/model/util/ElementScanner9 flags 21 signature Ljavax/lang/model/util/ElementScanner9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementScannerPreview +header extends javax/lang/model/util/ElementScanner14 flags 21 signature Ljavax/lang/model/util/ElementScanner14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleAnnotationValueVisitor14 +header extends javax/lang/model/util/SimpleAnnotationValueVisitor9 flags 21 signature Ljavax/lang/model/util/SimpleAnnotationValueVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleAnnotationValueVisitorPreview +header extends javax/lang/model/util/SimpleAnnotationValueVisitor14 flags 21 signature Ljavax/lang/model/util/SimpleAnnotationValueVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleElementVisitor14 +header extends javax/lang/model/util/SimpleElementVisitor9 flags 21 signature Ljavax/lang/model/util/SimpleElementVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleElementVisitorPreview +header extends javax/lang/model/util/SimpleElementVisitor14 flags 21 signature Ljavax/lang/model/util/SimpleElementVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleTypeVisitor14 +header extends javax/lang/model/util/SimpleTypeVisitor9 flags 21 signature Ljavax/lang/model/util/SimpleTypeVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleTypeVisitorPreview +header extends javax/lang/model/util/SimpleTypeVisitor14 flags 21 signature Ljavax/lang/model/util/SimpleTypeVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/TypeKindVisitor14 +header extends javax/lang/model/util/TypeKindVisitor9 flags 21 signature Ljavax/lang/model/util/TypeKindVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/TypeKindVisitorPreview +header extends javax/lang/model/util/TypeKindVisitor14 flags 21 signature Ljavax/lang/model/util/TypeKindVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + diff --git a/src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt new file mode 100644 index 00000000000..f75ff5b3fac --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt @@ -0,0 +1,90 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name java.desktop +header exports java/awt,java/awt/color,java/awt/desktop,java/awt/dnd,java/awt/event,java/awt/font,java/awt/geom,java/awt/im,java/awt/im/spi,java/awt/image,java/awt/image/renderable,java/awt/print,java/beans,java/beans/beancontext,javax/accessibility,javax/imageio,javax/imageio/event,javax/imageio/metadata,javax/imageio/plugins/bmp,javax/imageio/plugins/jpeg,javax/imageio/plugins/tiff,javax/imageio/spi,javax/imageio/stream,javax/print,javax/print/attribute,javax/print/attribute/standard,javax/print/event,javax/sound,javax/sound/midi,javax/sound/midi/spi,javax/sound/sampled,javax/sound/sampled/spi,javax/swing,javax/swing/border,javax/swing/colorchooser,javax/swing/event,javax/swing/filechooser,javax/swing/plaf,javax/swing/plaf/basic,javax/swing/plaf/metal,javax/swing/plaf/multi,javax/swing/plaf/nimbus,javax/swing/plaf/synth,javax/swing/table,javax/swing/text,javax/swing/text/html,javax/swing/text/html/parser,javax/swing/text/rtf,javax/swing/tree,javax/swing/undo extraModulePackages sun/print requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;java.prefs\u0020;flags\u0020;0,name\u0020;java.datatransfer\u0020;flags\u0020;20,name\u0020;java.xml\u0020;flags\u0020;20 uses java/awt/im/spi/InputMethodDescriptor,javax/accessibility/AccessibilityProvider,javax/imageio/spi/ImageInputStreamSpi,javax/imageio/spi/ImageOutputStreamSpi,javax/imageio/spi/ImageReaderSpi,javax/imageio/spi/ImageTranscoderSpi,javax/imageio/spi/ImageWriterSpi,javax/print/PrintServiceLookup,javax/print/StreamPrintServiceFactory,javax/sound/midi/spi/MidiDeviceProvider,javax/sound/midi/spi/MidiFileReader,javax/sound/midi/spi/MidiFileWriter,javax/sound/midi/spi/SoundbankReader,javax/sound/sampled/spi/AudioFileReader,javax/sound/sampled/spi/AudioFileWriter,javax/sound/sampled/spi/FormatConversionProvider,javax/sound/sampled/spi/MixerProvider,sun/swing/InteropProvider provides interface\u0020;sun/datatransfer/DesktopDatatransferService\u0020;impls\u0020;sun/awt/datatransfer/DesktopDatatransferServiceImpl,interface\u0020;java/net/ContentHandlerFactory\u0020;impls\u0020;sun/awt/www/content/MultimediaContentHandlers,interface\u0020;javax/print/PrintServiceLookup\u0020;impls\u0020;sun/print/PrintServiceLookupProvider,interface\u0020;javax/print/StreamPrintServiceFactory\u0020;impls\u0020;sun/print/PSStreamPrinterFactory,interface\u0020;javax/sound/midi/spi/MidiDeviceProvider\u0020;impls\u0020;com/sun/media/sound/MidiInDeviceProvider\u005C;u002C;com/sun/media/sound/MidiOutDeviceProvider\u005C;u002C;com/sun/media/sound/RealTimeSequencerProvider\u005C;u002C;com/sun/media/sound/SoftProvider,interface\u0020;javax/sound/midi/spi/MidiFileReader\u0020;impls\u0020;com/sun/media/sound/StandardMidiFileReader,interface\u0020;javax/sound/midi/spi/MidiFileWriter\u0020;impls\u0020;com/sun/media/sound/StandardMidiFileWriter,interface\u0020;javax/sound/midi/spi/SoundbankReader\u0020;impls\u0020;com/sun/media/sound/AudioFileSoundbankReader\u005C;u002C;com/sun/media/sound/DLSSoundbankReader\u005C;u002C;com/sun/media/sound/JARSoundbankReader\u005C;u002C;com/sun/media/sound/SF2SoundbankReader,interface\u0020;javax/sound/sampled/spi/AudioFileReader\u0020;impls\u0020;com/sun/media/sound/AiffFileReader\u005C;u002C;com/sun/media/sound/AuFileReader\u005C;u002C;com/sun/media/sound/SoftMidiAudioFileReader\u005C;u002C;com/sun/media/sound/WaveFileReader\u005C;u002C;com/sun/media/sound/WaveFloatFileReader\u005C;u002C;com/sun/media/sound/WaveExtensibleFileReader,interface\u0020;javax/sound/sampled/spi/AudioFileWriter\u0020;impls\u0020;com/sun/media/sound/AiffFileWriter\u005C;u002C;com/sun/media/sound/AuFileWriter\u005C;u002C;com/sun/media/sound/WaveFileWriter\u005C;u002C;com/sun/media/sound/WaveFloatFileWriter,interface\u0020;javax/sound/sampled/spi/FormatConversionProvider\u0020;impls\u0020;com/sun/media/sound/AlawCodec\u005C;u002C;com/sun/media/sound/AudioFloatFormatConverter\u005C;u002C;com/sun/media/sound/PCMtoPCMCodec\u005C;u002C;com/sun/media/sound/UlawCodec,interface\u0020;javax/sound/sampled/spi/MixerProvider\u0020;impls\u0020;com/sun/media/sound/DirectAudioDeviceProvider\u005C;u002C;com/sun/media/sound/PortMixerProvider target macos-aarch64 flags 8000 + +-class name java/applet/Applet + +-class name java/applet/Applet$AccessibleApplet + +-class name java/applet/AppletContext + +-class name java/applet/AppletStub + +-class name java/applet/AudioClip + +class name java/awt/Robot +field name DEFAULT_DELAY descriptor I constantValue 20 flags 19 +field name DEFAULT_STEP_LENGTH descriptor I constantValue 2 flags 19 +method name click descriptor (I)V flags 1 +method name click descriptor ()V flags 1 +method name waitForIdle descriptor (I)V flags 1 +method name glide descriptor (II)V flags 1 +method name glide descriptor (IIII)V flags 1 +method name glide descriptor (IIIIII)V flags 1 +method name type descriptor (I)V flags 21 +method name type descriptor (C)V flags 21 + +-class name java/beans/AppletInitializer + +class name java/beans/Beans +-method name instantiate descriptor (Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/beans/beancontext/BeanContext;Ljava/beans/AppletInitializer;)Ljava/lang/Object; + +class name javax/imageio/spi/ServiceRegistry +-method name finalize descriptor ()V + +class name javax/imageio/stream/FileCacheImageInputStream +-method name finalize descriptor ()V + +class name javax/imageio/stream/FileImageInputStream +-method name finalize descriptor ()V + +class name javax/imageio/stream/FileImageOutputStream +-method name finalize descriptor ()V + +class name javax/imageio/stream/ImageInputStreamImpl +-method name finalize descriptor ()V + +class name javax/imageio/stream/MemoryCacheImageInputStream +-method name finalize descriptor ()V + +-class name javax/swing/JApplet + +-class name javax/swing/JApplet$AccessibleJApplet + +class name javax/swing/JTable +-method name setShowGrid descriptor (Z)V +method name setShowGrid descriptor (Z)V flags 1 runtimeAnnotations @Ljava/beans/BeanProperty;(description="Whether\u005C;u0020;grid\u005C;u0020;lines\u005C;u0020;are\u005C;u0020;drawn\u005C;u0020;around\u005C;u0020;the\u005C;u0020;cells.") + +class name javax/swing/RepaintManager +-method name addDirtyRegion descriptor (Ljava/applet/Applet;IIII)V + +class name javax/swing/plaf/synth/SynthPasswordFieldUI +-method name installKeyboardActions descriptor ()V + diff --git a/src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt new file mode 100644 index 00000000000..03dacce810b --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt @@ -0,0 +1,37 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name java/lang/management/MemoryMXBean +method name getTotalGcCpuTime descriptor ()J flags 1 + +class name javax/management/modelmbean/DescriptorSupport +-method name descriptor (Ljava/lang/String;)V +-method name toXMLString descriptor ()Ljava/lang/String; + +-class name javax/management/modelmbean/XMLParseException + diff --git a/src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt new file mode 100644 index 00000000000..bddf5c8d137 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt @@ -0,0 +1,125 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name java/net/http/HttpClient$Version +field name HTTP_3 descriptor Ljava/net/http/HttpClient$Version; flags 4019 + +class name java/net/http/HttpOption +header extends java/lang/Object nestMembers java/net/http/HttpOption$Http3DiscoveryMode sealed true permittedSubclasses java/net/http/HttpRequestOptionImpl flags 601 signature Ljava/lang/Object; +innerclass innerClass java/net/http/HttpOption$Http3DiscoveryMode outerClass java/net/http/HttpOption innerClassName Http3DiscoveryMode flags 4019 +field name H3_DISCOVERY descriptor Ljava/net/http/HttpOption; flags 19 signature Ljava/net/http/HttpOption; +method name name descriptor ()Ljava/lang/String; flags 401 +method name type descriptor ()Ljava/lang/Class; flags 401 signature ()Ljava/lang/Class; + +class name java/net/http/HttpOption$Http3DiscoveryMode +header extends java/lang/Enum nestHost java/net/http/HttpOption flags 4031 signature Ljava/lang/Enum; +innerclass innerClass java/net/http/HttpOption$Http3DiscoveryMode outerClass java/net/http/HttpOption innerClassName Http3DiscoveryMode flags 4019 +field name ANY descriptor Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 4019 +field name ALT_SVC descriptor Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 4019 +field name HTTP_3_URI_ONLY descriptor Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 4019 +method name values descriptor ()[Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 9 methodParameters 8000:null + +class name java/net/http/HttpRequest +header extends java/lang/Object nestMembers java/net/http/HttpRequest$BodyPublishers,java/net/http/HttpRequest$BodyPublisher,java/net/http/HttpRequest$Builder flags 421 +innerclass innerClass java/net/http/HttpRequest$Builder outerClass java/net/http/HttpRequest innerClassName Builder flags 609 +innerclass innerClass java/net/http/HttpRequest$BodyPublishers outerClass java/net/http/HttpRequest innerClassName BodyPublishers flags 9 +innerclass innerClass java/net/http/HttpRequest$BodyPublisher outerClass java/net/http/HttpRequest innerClassName BodyPublisher flags 609 +innerclass innerClass java/net/http/HttpClient$Version outerClass java/net/http/HttpClient innerClassName Version flags 4019 +innerclass innerClass java/net/http/HttpOption$Http3DiscoveryMode outerClass java/net/http/HttpOption innerClassName Http3DiscoveryMode flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name getOption descriptor (Ljava/net/http/HttpOption;)Ljava/util/Optional; flags 1 signature (Ljava/net/http/HttpOption;)Ljava/util/Optional; + +class name java/net/http/HttpRequest$BodyPublishers +method name ofFileChannel descriptor (Ljava/nio/channels/FileChannel;JJ)Ljava/net/http/HttpRequest$BodyPublisher; thrownTypes java/io/IOException flags 9 + +class name java/net/http/HttpRequest$Builder +method name setOption descriptor (Ljava/net/http/HttpOption;Ljava/lang/Object;)Ljava/net/http/HttpRequest$Builder; flags 1 signature (Ljava/net/http/HttpOption;TT;)Ljava/net/http/HttpRequest$Builder; + +class name java/net/http/HttpRequestOptionImpl +header extends java/lang/Record implements java/net/http/HttpOption record true flags 30 signature Ljava/lang/Record;Ljava/net/http/HttpOption; +recordcomponent name type descriptor Ljava/lang/Class; signature Ljava/lang/Class; +recordcomponent name name descriptor Ljava/lang/String; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name toString descriptor ()Ljava/lang/String; flags 1 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name type descriptor ()Ljava/lang/Class; flags 1 signature ()Ljava/lang/Class; +method name name descriptor ()Ljava/lang/String; flags 1 + +class name java/net/http/HttpResponse +header extends java/lang/Object nestMembers java/net/http/HttpResponse$BodySubscribers,java/net/http/HttpResponse$BodySubscriber,java/net/http/HttpResponse$PushPromiseHandler,java/net/http/HttpResponse$PushPromiseHandler$PushId,java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId,java/net/http/HttpResponse$BodyHandlers,java/net/http/HttpResponse$BodyHandler,java/net/http/HttpResponse$ResponseInfo flags 601 signature Ljava/lang/Object; +innerclass innerClass java/net/http/HttpResponse$BodySubscribers outerClass java/net/http/HttpResponse innerClassName BodySubscribers flags 9 +innerclass innerClass java/net/http/HttpResponse$BodySubscriber outerClass java/net/http/HttpResponse innerClassName BodySubscriber flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$BodyHandlers outerClass java/net/http/HttpResponse innerClassName BodyHandlers flags 9 +innerclass innerClass java/net/http/HttpResponse$BodyHandler outerClass java/net/http/HttpResponse innerClassName BodyHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$ResponseInfo outerClass java/net/http/HttpResponse innerClassName ResponseInfo flags 609 +innerclass innerClass java/net/http/HttpClient$Version outerClass java/net/http/HttpClient innerClassName Version flags 4019 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId outerClass java/net/http/HttpResponse$PushPromiseHandler$PushId innerClassName Http3PushId flags 19 + +class name java/net/http/HttpResponse$PushPromiseHandler +header extends java/lang/Object nestHost java/net/http/HttpResponse flags 601 signature Ljava/lang/Object; +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$BodyHandler outerClass java/net/http/HttpResponse innerClassName BodyHandler flags 609 +method name applyPushPromise descriptor (Ljava/net/http/HttpRequest;Ljava/net/http/HttpRequest;Ljava/net/http/HttpResponse$PushPromiseHandler$PushId;Ljava/util/function/Function;)V flags 1 signature (Ljava/net/http/HttpRequest;Ljava/net/http/HttpRequest;Ljava/net/http/HttpResponse$PushPromiseHandler$PushId;Ljava/util/function/Function;Ljava/util/concurrent/CompletableFuture;>;>;)V +method name notifyAdditionalPromise descriptor (Ljava/net/http/HttpRequest;Ljava/net/http/HttpResponse$PushPromiseHandler$PushId;)V flags 1 + +class name java/net/http/HttpResponse$PushPromiseHandler$PushId +header extends java/lang/Object nestHost java/net/http/HttpResponse sealed true permittedSubclasses java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId flags 601 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId outerClass java/net/http/HttpResponse$PushPromiseHandler$PushId innerClassName Http3PushId flags 19 + +class name java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId +header extends java/lang/Record implements java/net/http/HttpResponse$PushPromiseHandler$PushId nestHost java/net/http/HttpResponse record true flags 31 +recordcomponent name pushId descriptor J +recordcomponent name connectionLabel descriptor Ljava/lang/String; +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId outerClass java/net/http/HttpResponse$PushPromiseHandler$PushId innerClassName Http3PushId flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name descriptor (JLjava/lang/String;)V flags 1 methodParameters 0:pushId,0:connectionLabel +method name toString descriptor ()Ljava/lang/String; flags 11 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name pushId descriptor ()J flags 1 +method name connectionLabel descriptor ()Ljava/lang/String; flags 1 + +class name java/net/http/StreamLimitException +header extends java/io/IOException flags 31 +innerclass innerClass java/net/http/HttpClient$Version outerClass java/net/http/HttpClient innerClassName Version flags 4019 +method name descriptor (Ljava/net/http/HttpClient$Version;Ljava/lang/String;)V flags 1 +method name version descriptor ()Ljava/net/http/HttpClient$Version; flags 11 + +class name java/net/http/UnsupportedProtocolVersionException +header extends java/io/IOException flags 31 +method name descriptor (Ljava/lang/String;)V flags 1 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt new file mode 100644 index 00000000000..70cc330edca --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt @@ -0,0 +1,32 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name com/sun/net/httpserver/HttpExchange +field name RSPBODY_EMPTY descriptor J constantValue -1 flags 19 +field name RSPBODY_CHUNKED descriptor J constantValue 0 flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt new file mode 100644 index 00000000000..223be24ab56 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt @@ -0,0 +1,32 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name jdk/incubator/vector/VectorOperators +-field name SUADD descriptor Ljdk/incubator/vector/VectorOperators$Binary; +field name SUADD descriptor Ljdk/incubator/vector/VectorOperators$Associative; flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt new file mode 100644 index 00000000000..47838de0844 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jartool +header exports jdk/security/jarsigner requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;jdk.internal.opt\u0020;flags\u0020;0 provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;sun/tools/jar/JarToolProvider target macos-aarch64 moduleMainClass sun/tools/jar/Main flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt new file mode 100644 index 00000000000..e5d0bb627e5 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jdeps +header requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;java.compiler\u0020;flags\u0020;0,name\u0020;jdk.compiler\u0020;flags\u0020;0,name\u0020;jdk.internal.opt\u0020;flags\u0020;0 uses com/sun/tools/javac/platform/PlatformProvider provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;com/sun/tools/javap/Main$JavapToolProvider\u005C;u002C;com/sun/tools/jdeps/Main$JDepsToolProvider\u005C;u002C;com/sun/tools/jnativescan/Main$Provider target macos-aarch64 flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt new file mode 100644 index 00000000000..2e3c13ea64c --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jfr +header exports jdk/jfr,jdk/jfr/consumer requires name\u0020;java.base\u0020;flags\u0020;8000 target macos-aarch64 moduleMainClass jdk/jfr/internal/tool/Main flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt new file mode 100644 index 00000000000..e3e9eadf355 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jlink +header requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;jdk.internal.opt\u0020;flags\u0020;0,name\u0020;jdk.jdeps\u0020;flags\u0020;0 uses jdk/tools/jlink/plugin/Plugin provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;jdk/tools/jmod/Main$JmodToolProvider\u005C;u002C;jdk/tools/jlink/internal/Main$JlinkToolProvider,interface\u0020;jdk/tools/jlink/plugin/Plugin\u0020;impls\u0020;jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludePlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludeFilesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludeJmodSectionPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/LegalNoticeFilePlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/SystemModulesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/StripNativeCommandsPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/OrderResourcesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/DefaultCompressPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludeVMPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/AddOptionsPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/VendorBugURLPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/VendorVMBugURLPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/VendorVersionPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/CDSPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/SaveJlinkArgfilesPlugin target macos-aarch64 flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt new file mode 100644 index 00000000000..1dff60fc776 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt @@ -0,0 +1,169 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jshell +header exports jdk/jshell,jdk/jshell/execution,jdk/jshell/spi,jdk/jshell/tool requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;java.logging\u0020;flags\u0020;0,name\u0020;jdk.compiler\u0020;flags\u0020;0,name\u0020;jdk.internal.ed\u0020;flags\u0020;0,name\u0020;jdk.internal.le\u0020;flags\u0020;0,name\u0020;jdk.internal.md\u0020;flags\u0020;0,name\u0020;jdk.internal.opt\u0020;flags\u0020;0,name\u0020;java.compiler\u0020;flags\u0020;20,name\u0020;java.prefs\u0020;flags\u0020;20,name\u0020;jdk.jdi\u0020;flags\u0020;20 uses jdk/jshell/spi/ExecutionControlProvider,jdk/internal/editor/spi/BuildInEditorProvider provides interface\u0020;javax/tools/Tool\u0020;impls\u0020;jdk/internal/jshell/tool/JShellToolProvider,interface\u0020;jdk/jshell/spi/ExecutionControlProvider\u0020;impls\u0020;jdk/jshell/execution/JdiExecutionControlProvider\u005C;u002C;jdk/jshell/execution/LocalExecutionControlProvider\u005C;u002C;jdk/jshell/execution/FailOverExecutionControlProvider,interface\u0020;jdk/internal/io/JdkConsoleProvider\u0020;impls\u0020;jdk/jshell/execution/impl/ConsoleImpl$ConsoleProviderImpl target macos-aarch64 moduleMainClass jdk/internal/jshell/tool/JShellToolProvider flags 8000 + +class name jdk/jshell/SourceCodeAnalysis +header extends java/lang/Object nestMembers jdk/jshell/SourceCodeAnalysis$Attribute,jdk/jshell/SourceCodeAnalysis$Highlight,jdk/jshell/SourceCodeAnalysis$SnippetWrapper,jdk/jshell/SourceCodeAnalysis$QualifiedNames,jdk/jshell/SourceCodeAnalysis$Documentation,jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor,jdk/jshell/SourceCodeAnalysis$CompletionContext,jdk/jshell/SourceCodeAnalysis$CompletionState,jdk/jshell/SourceCodeAnalysis$ElementSuggestion,jdk/jshell/SourceCodeAnalysis$Suggestion,jdk/jshell/SourceCodeAnalysis$Completeness,jdk/jshell/SourceCodeAnalysis$CompletionInfo flags 421 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Attribute outerClass jdk/jshell/SourceCodeAnalysis innerClassName Attribute flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Highlight outerClass jdk/jshell/SourceCodeAnalysis innerClassName Highlight flags 19 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$SnippetWrapper outerClass jdk/jshell/SourceCodeAnalysis innerClassName SnippetWrapper flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$QualifiedNames outerClass jdk/jshell/SourceCodeAnalysis innerClassName QualifiedNames flags 19 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Documentation outerClass jdk/jshell/SourceCodeAnalysis innerClassName Documentation flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestionConvertor flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Suggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName Suggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Completeness outerClass jdk/jshell/SourceCodeAnalysis innerClassName Completeness flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionInfo outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionInfo flags 609 +method name completionSuggestions descriptor (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; flags 401 signature (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; + +class name jdk/jshell/SourceCodeAnalysis$CompletionContext +header extends java/lang/Enum nestHost jdk/jshell/SourceCodeAnalysis flags 4031 signature Ljava/lang/Enum; +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +field name ANNOTATION_ATTRIBUTE descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +field name NO_PAREN descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +field name TYPES_AS_ANNOTATIONS descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +field name QUALIFIED descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +method name values descriptor ()[Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 9 methodParameters 8000:null + +class name jdk/jshell/SourceCodeAnalysis$CompletionState +header extends java/lang/Object nestHost jdk/jshell/SourceCodeAnalysis sealed true permittedSubclasses jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl flags 601 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName CompletionStateImpl flags 18 +method name availableUsingSimpleName descriptor (Ljavax/lang/model/element/Element;)Z flags 401 +method name completionContext descriptor ()Ljava/util/Set; flags 401 signature ()Ljava/util/Set; +method name selectorType descriptor ()Ljavax/lang/model/type/TypeMirror; flags 401 +method name elementUtils descriptor ()Ljavax/lang/model/util/Elements; flags 401 +method name typeUtils descriptor ()Ljavax/lang/model/util/Types; flags 401 + +class name jdk/jshell/SourceCodeAnalysis$Documentation +method name activeParameterIndex descriptor ()I flags 1 + +class name jdk/jshell/SourceCodeAnalysis$ElementSuggestion +header extends java/lang/Object nestHost jdk/jshell/SourceCodeAnalysis sealed true permittedSubclasses jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl flags 601 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName ElementSuggestionImpl flags 18 +method name element descriptor ()Ljavax/lang/model/element/Element; flags 401 +method name keyword descriptor ()Ljava/lang/String; flags 401 +method name matchesType descriptor ()Z flags 401 +method name anchor descriptor ()I flags 401 +method name documentation descriptor ()Ljava/util/function/Supplier; flags 401 signature ()Ljava/util/function/Supplier; + +class name jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor +header extends java/lang/Object nestHost jdk/jshell/SourceCodeAnalysis flags 601 signature Ljava/lang/Object; +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestionConvertor flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +method name convert descriptor (Ljdk/jshell/SourceCodeAnalysis$CompletionState;Ljava/util/List;)Ljava/util/List; flags 401 signature (Ljdk/jshell/SourceCodeAnalysis$CompletionState;Ljava/util/List<+Ljdk/jshell/SourceCodeAnalysis$ElementSuggestion;>;)Ljava/util/List; + +class name jdk/jshell/SourceCodeAnalysisImpl +header extends jdk/jshell/SourceCodeAnalysis nestMembers jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl,jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl flags 20 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Completeness outerClass jdk/jshell/SourceCodeAnalysis innerClassName Completeness flags 4019 +innerclass innerClass com/sun/source/tree/Tree$Kind outerClass com/sun/source/tree/Tree innerClassName Kind flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestionConvertor flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName ElementSuggestionImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$QualifiedNames outerClass jdk/jshell/SourceCodeAnalysis innerClassName QualifiedNames flags 19 +innerclass innerClass javax/tools/JavaFileManager$Location outerClass javax/tools/JavaFileManager innerClassName Location flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionInfo outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionInfo flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Documentation outerClass jdk/jshell/SourceCodeAnalysis innerClassName Documentation flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Highlight outerClass jdk/jshell/SourceCodeAnalysis innerClassName Highlight flags 19 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Attribute outerClass jdk/jshell/SourceCodeAnalysis innerClassName Attribute flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName CompletionStateImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass java/lang/Thread$UncaughtExceptionHandler outerClass java/lang/Thread innerClassName UncaughtExceptionHandler flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Suggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName Suggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$SnippetWrapper outerClass jdk/jshell/SourceCodeAnalysis innerClassName SnippetWrapper flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name analyzeCompletion descriptor (Ljava/lang/String;)Ljdk/jshell/SourceCodeAnalysis$CompletionInfo; flags 1 +method name completionSuggestions descriptor (Ljava/lang/String;I[I)Ljava/util/List; flags 1 signature (Ljava/lang/String;I[I)Ljava/util/List; +method name completionSuggestions descriptor (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; flags 1 signature (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; +method name wrapper descriptor (Ljdk/jshell/Snippet;)Ljdk/jshell/SourceCodeAnalysis$SnippetWrapper; flags 1 +method name wrappers descriptor (Ljava/lang/String;)Ljava/util/List; flags 1 signature (Ljava/lang/String;)Ljava/util/List; +method name sourceToSnippets descriptor (Ljava/lang/String;)Ljava/util/List; flags 1 signature (Ljava/lang/String;)Ljava/util/List; +method name dependents descriptor (Ljdk/jshell/Snippet;)Ljava/util/Collection; flags 1 signature (Ljdk/jshell/Snippet;)Ljava/util/Collection; +method name highlights descriptor (Ljava/lang/String;)Ljava/util/List; flags 1 signature (Ljava/lang/String;)Ljava/util/List; +method name documentation descriptor (Ljava/lang/String;IZ)Ljava/util/List; flags 1 signature (Ljava/lang/String;IZ)Ljava/util/List; +method name close descriptor ()V flags 1 +method name analyzeType descriptor (Ljava/lang/String;I)Ljava/lang/String; flags 1 +method name listQualifiedNames descriptor (Ljava/lang/String;I)Ljdk/jshell/SourceCodeAnalysis$QualifiedNames; flags 1 +method name suspendIndexing descriptor ()V flags 1 +method name resumeIndexing descriptor ()V flags 1 +method name waitBackgroundTaskFinished descriptor ()V thrownTypes java/lang/Exception flags 1 +method name waitCurrentBackgroundTasksFinished descriptor ()V thrownTypes java/lang/Exception flags 9 + +class name jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl +header extends java/lang/Object implements jdk/jshell/SourceCodeAnalysis$CompletionState nestHost jdk/jshell/SourceCodeAnalysisImpl flags 30 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName CompletionStateImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +method name descriptor (Ljava/util/Collection;Ljava/util/Set;Ljavax/lang/model/type/TypeMirror;Ljavax/lang/model/util/Elements;Ljavax/lang/model/util/Types;)V flags 1 signature (Ljava/util/Collection<+Ljavax/lang/model/element/Element;>;Ljava/util/Set;Ljavax/lang/model/type/TypeMirror;Ljavax/lang/model/util/Elements;Ljavax/lang/model/util/Types;)V +method name availableUsingSimpleName descriptor (Ljavax/lang/model/element/Element;)Z flags 1 +method name completionContext descriptor ()Ljava/util/Set; flags 1 signature ()Ljava/util/Set; +method name selectorType descriptor ()Ljavax/lang/model/type/TypeMirror; flags 1 +method name elementUtils descriptor ()Ljavax/lang/model/util/Elements; flags 1 +method name typeUtils descriptor ()Ljavax/lang/model/util/Types; flags 1 + +class name jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl +header extends java/lang/Record implements jdk/jshell/SourceCodeAnalysis$ElementSuggestion nestHost jdk/jshell/SourceCodeAnalysisImpl record true flags 30 +recordcomponent name element descriptor Ljavax/lang/model/element/Element; +recordcomponent name keyword descriptor Ljava/lang/String; +recordcomponent name matchesType descriptor Z +recordcomponent name anchor descriptor I +recordcomponent name documentation descriptor Ljava/util/function/Supplier; signature Ljava/util/function/Supplier; +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName ElementSuggestionImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name toString descriptor ()Ljava/lang/String; flags 11 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name element descriptor ()Ljavax/lang/model/element/Element; flags 1 +method name keyword descriptor ()Ljava/lang/String; flags 1 +method name matchesType descriptor ()Z flags 1 +method name anchor descriptor ()I flags 1 +method name documentation descriptor ()Ljava/util/function/Supplier; flags 1 signature ()Ljava/util/function/Supplier; + +class name jdk/jshell/execution/LocalExecutionControl +header extends jdk/jshell/execution/DirectExecutionControl flags 21 +innerclass innerClass jdk/jshell/spi/ExecutionControl$ClassBytecodes outerClass jdk/jshell/spi/ExecutionControl innerClassName ClassBytecodes flags 19 +innerclass innerClass java/lang/classfile/ClassFile$Option outerClass java/lang/classfile/ClassFile innerClassName Option flags 609 +innerclass innerClass java/lang/classfile/ClassFile$ClassHierarchyResolverOption outerClass java/lang/classfile/ClassFile innerClassName ClassHierarchyResolverOption flags 609 +innerclass innerClass jdk/jshell/spi/ExecutionControl$StoppedException outerClass jdk/jshell/spi/ExecutionControl innerClassName StoppedException flags 9 +innerclass innerClass jdk/jshell/spi/ExecutionControl$InternalException outerClass jdk/jshell/spi/ExecutionControl innerClassName InternalException flags 9 +innerclass innerClass java/lang/classfile/CodeBuilder$BlockCodeBuilder outerClass java/lang/classfile/CodeBuilder innerClassName BlockCodeBuilder flags 609 +innerclass innerClass jdk/jshell/spi/ExecutionControl$ClassInstallException outerClass jdk/jshell/spi/ExecutionControl innerClassName ClassInstallException flags 9 +innerclass innerClass jdk/jshell/spi/ExecutionControl$NotImplementedException outerClass jdk/jshell/spi/ExecutionControl innerClassName NotImplementedException flags 9 +innerclass innerClass jdk/jshell/spi/ExecutionControl$EngineTerminationException outerClass jdk/jshell/spi/ExecutionControl innerClassName EngineTerminationException flags 9 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt new file mode 100644 index 00000000000..c8b83f6800b --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt @@ -0,0 +1,34 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +-module name jdk.jsobject + +-class name netscape/javascript/JSException + +-class name netscape/javascript/JSObject + diff --git a/src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt new file mode 100644 index 00000000000..71d9c3fea14 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.localedata +header requires name\u0020;java.base\u0020;flags\u0020;8000 provides interface\u0020;sun/util/locale/provider/LocaleDataMetaInfo\u0020;impls\u0020;sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo\u005C;u002C;sun/util/resources/provider/NonBaseLocaleDataMetaInfo,interface\u0020;sun/util/resources/LocaleData$LocaleDataResourceBundleProvider\u0020;impls\u0020;sun/util/resources/provider/LocaleDataProvider target macos-aarch64 flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/symbols b/src/jdk.compiler/share/data/symbols/symbols index 34619bed887..4bc5127310f 100644 --- a/src/jdk.compiler/share/data/symbols/symbols +++ b/src/jdk.compiler/share/data/symbols/symbols @@ -29,7 +29,7 @@ #command used to generate this file: #build.tools.symbolgenerator.CreateSymbols build-description-incremental symbols include.list # -generate platforms 8:9:A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P +generate platforms 8:9:A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q platform version 8 files java.activation-8.sym.txt:java.base-8.sym.txt:java.compiler-8.sym.txt:java.corba-8.sym.txt:java.datatransfer-8.sym.txt:java.desktop-8.sym.txt:java.instrument-8.sym.txt:java.logging-8.sym.txt:java.management-8.sym.txt:java.management.rmi-8.sym.txt:java.naming-8.sym.txt:java.prefs-8.sym.txt:java.rmi-8.sym.txt:java.scripting-8.sym.txt:java.security.jgss-8.sym.txt:java.security.sasl-8.sym.txt:java.sql-8.sym.txt:java.sql.rowset-8.sym.txt:java.transaction-8.sym.txt:java.xml-8.sym.txt:java.xml.bind-8.sym.txt:java.xml.crypto-8.sym.txt:java.xml.ws-8.sym.txt:java.xml.ws.annotation-8.sym.txt:jdk.httpserver-8.sym.txt:jdk.management-8.sym.txt:jdk.net-8.sym.txt:jdk.scripting.nashorn-8.sym.txt:jdk.sctp-8.sym.txt:jdk.security.auth-8.sym.txt:jdk.security.jgss-8.sym.txt platform version 9 base 8 files java.activation-9.sym.txt:java.base-9.sym.txt:java.compiler-9.sym.txt:java.corba-9.sym.txt:java.datatransfer-9.sym.txt:java.desktop-9.sym.txt:java.instrument-9.sym.txt:java.logging-9.sym.txt:java.management-9.sym.txt:java.management.rmi-9.sym.txt:java.naming-9.sym.txt:java.prefs-9.sym.txt:java.rmi-9.sym.txt:java.scripting-9.sym.txt:java.se-9.sym.txt:java.se.ee-9.sym.txt:java.security.jgss-9.sym.txt:java.security.sasl-9.sym.txt:java.smartcardio-9.sym.txt:java.sql-9.sym.txt:java.sql.rowset-9.sym.txt:java.transaction-9.sym.txt:java.xml-9.sym.txt:java.xml.bind-9.sym.txt:java.xml.crypto-9.sym.txt:java.xml.ws-9.sym.txt:java.xml.ws.annotation-9.sym.txt:jdk.accessibility-9.sym.txt:jdk.attach-9.sym.txt:jdk.charsets-9.sym.txt:jdk.compiler-9.sym.txt:jdk.crypto.cryptoki-9.sym.txt:jdk.crypto.ec-9.sym.txt:jdk.dynalink-9.sym.txt:jdk.editpad-9.sym.txt:jdk.hotspot.agent-9.sym.txt:jdk.httpserver-9.sym.txt:jdk.incubator.httpclient-9.sym.txt:jdk.jartool-9.sym.txt:jdk.javadoc-9.sym.txt:jdk.jcmd-9.sym.txt:jdk.jconsole-9.sym.txt:jdk.jdeps-9.sym.txt:jdk.jdi-9.sym.txt:jdk.jdwp.agent-9.sym.txt:jdk.jlink-9.sym.txt:jdk.jshell-9.sym.txt:jdk.jsobject-9.sym.txt:jdk.jstatd-9.sym.txt:jdk.localedata-9.sym.txt:jdk.management-9.sym.txt:jdk.management.agent-9.sym.txt:jdk.naming.dns-9.sym.txt:jdk.naming.rmi-9.sym.txt:jdk.net-9.sym.txt:jdk.pack-9.sym.txt:jdk.policytool-9.sym.txt:jdk.rmic-9.sym.txt:jdk.scripting.nashorn-9.sym.txt:jdk.sctp-9.sym.txt:jdk.security.auth-9.sym.txt:jdk.security.jgss-9.sym.txt:jdk.unsupported-9.sym.txt:jdk.xml.dom-9.sym.txt:jdk.zipfs-9.sym.txt platform version A base 9 files java.activation-A.sym.txt:java.base-A.sym.txt:java.compiler-A.sym.txt:java.corba-A.sym.txt:java.datatransfer-A.sym.txt:java.desktop-A.sym.txt:java.instrument-A.sym.txt:java.logging-A.sym.txt:java.management-A.sym.txt:java.management.rmi-A.sym.txt:java.naming-A.sym.txt:java.prefs-A.sym.txt:java.rmi-A.sym.txt:java.scripting-A.sym.txt:java.se-A.sym.txt:java.se.ee-A.sym.txt:java.security.jgss-A.sym.txt:java.security.sasl-A.sym.txt:java.smartcardio-A.sym.txt:java.sql-A.sym.txt:java.sql.rowset-A.sym.txt:java.transaction-A.sym.txt:java.xml-A.sym.txt:java.xml.bind-A.sym.txt:java.xml.crypto-A.sym.txt:java.xml.ws-A.sym.txt:java.xml.ws.annotation-A.sym.txt:jdk.accessibility-A.sym.txt:jdk.attach-A.sym.txt:jdk.charsets-A.sym.txt:jdk.compiler-A.sym.txt:jdk.crypto.cryptoki-A.sym.txt:jdk.crypto.ec-A.sym.txt:jdk.dynalink-A.sym.txt:jdk.editpad-A.sym.txt:jdk.hotspot.agent-A.sym.txt:jdk.httpserver-A.sym.txt:jdk.incubator.httpclient-A.sym.txt:jdk.jartool-A.sym.txt:jdk.javadoc-A.sym.txt:jdk.jcmd-A.sym.txt:jdk.jconsole-A.sym.txt:jdk.jdeps-A.sym.txt:jdk.jdi-A.sym.txt:jdk.jdwp.agent-A.sym.txt:jdk.jlink-A.sym.txt:jdk.jshell-A.sym.txt:jdk.jsobject-A.sym.txt:jdk.jstatd-A.sym.txt:jdk.localedata-A.sym.txt:jdk.management-A.sym.txt:jdk.management.agent-A.sym.txt:jdk.naming.dns-A.sym.txt:jdk.naming.rmi-A.sym.txt:jdk.net-A.sym.txt:jdk.pack-A.sym.txt:jdk.policytool-A.sym.txt:jdk.rmic-A.sym.txt:jdk.scripting.nashorn-A.sym.txt:jdk.sctp-A.sym.txt:jdk.security.auth-A.sym.txt:jdk.security.jgss-A.sym.txt:jdk.unsupported-A.sym.txt:jdk.xml.dom-A.sym.txt:jdk.zipfs-A.sym.txt @@ -48,3 +48,4 @@ platform version M base L files java.base-M.sym.txt:java.compiler-M.sym.txt:java platform version N base M files java.base-N.sym.txt:java.compiler-N.sym.txt:java.desktop-N.sym.txt:java.management-N.sym.txt:java.management.rmi-N.sym.txt:jdk.compiler-N.sym.txt:jdk.httpserver-N.sym.txt:jdk.incubator.foreign-N.sym.txt:jdk.javadoc-N.sym.txt:jdk.jshell-N.sym.txt:jdk.localedata-N.sym.txt:jdk.unsupported-N.sym.txt platform version O base N files java.base-O.sym.txt:java.compiler-O.sym.txt:java.datatransfer-O.sym.txt:java.desktop-O.sym.txt:java.instrument-O.sym.txt:java.logging-O.sym.txt:java.management-O.sym.txt:java.management.rmi-O.sym.txt:java.naming-O.sym.txt:java.net.http-O.sym.txt:java.prefs-O.sym.txt:java.rmi-O.sym.txt:java.scripting-O.sym.txt:java.se-O.sym.txt:java.security.jgss-O.sym.txt:java.security.sasl-O.sym.txt:java.smartcardio-O.sym.txt:java.sql-O.sym.txt:java.sql.rowset-O.sym.txt:java.transaction.xa-O.sym.txt:java.xml-O.sym.txt:java.xml.crypto-O.sym.txt:jdk.accessibility-O.sym.txt:jdk.attach-O.sym.txt:jdk.charsets-O.sym.txt:jdk.compiler-O.sym.txt:jdk.crypto.cryptoki-O.sym.txt:jdk.dynalink-O.sym.txt:jdk.editpad-O.sym.txt:jdk.hotspot.agent-O.sym.txt:jdk.httpserver-O.sym.txt:jdk.incubator.foreign-O.sym.txt:jdk.incubator.vector-O.sym.txt:jdk.jartool-O.sym.txt:jdk.javadoc-O.sym.txt:jdk.jcmd-O.sym.txt:jdk.jconsole-O.sym.txt:jdk.jdeps-O.sym.txt:jdk.jdi-O.sym.txt:jdk.jdwp.agent-O.sym.txt:jdk.jfr-O.sym.txt:jdk.jlink-O.sym.txt:jdk.jpackage-O.sym.txt:jdk.jshell-O.sym.txt:jdk.jsobject-O.sym.txt:jdk.jstatd-O.sym.txt:jdk.localedata-O.sym.txt:jdk.management-O.sym.txt:jdk.management.agent-O.sym.txt:jdk.management.jfr-O.sym.txt:jdk.naming.dns-O.sym.txt:jdk.naming.rmi-O.sym.txt:jdk.net-O.sym.txt:jdk.nio.mapmode-O.sym.txt:jdk.sctp-O.sym.txt:jdk.security.auth-O.sym.txt:jdk.security.jgss-O.sym.txt:jdk.unsupported-O.sym.txt:jdk.xml.dom-O.sym.txt:jdk.zipfs-O.sym.txt platform version P base O files java.base-P.sym.txt:java.compiler-P.sym.txt:java.desktop-P.sym.txt:java.logging-P.sym.txt:java.management-P.sym.txt:java.net.http-P.sym.txt:java.security.jgss-P.sym.txt:java.xml.crypto-P.sym.txt:jdk.attach-P.sym.txt:jdk.compiler-P.sym.txt:jdk.incubator.foreign-P.sym.txt:jdk.incubator.vector-P.sym.txt:jdk.jdi-P.sym.txt:jdk.jfr-P.sym.txt:jdk.jpackage-P.sym.txt:jdk.jshell-P.sym.txt:jdk.net-P.sym.txt:jdk.security.jgss-P.sym.txt +platform version Q base P files java.base-Q.sym.txt:java.compiler-Q.sym.txt:java.desktop-Q.sym.txt:java.management-Q.sym.txt:java.net.http-Q.sym.txt:jdk.httpserver-Q.sym.txt:jdk.incubator.vector-Q.sym.txt:jdk.jartool-Q.sym.txt:jdk.jdeps-Q.sym.txt:jdk.jfr-Q.sym.txt:jdk.jlink-Q.sym.txt:jdk.jshell-Q.sym.txt:jdk.jsobject-Q.sym.txt:jdk.localedata-Q.sym.txt diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index 0cd743372d5..785bb85e640 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -62,6 +62,16 @@ public class InstanceKlass extends Klass { private static int CLASS_STATE_FULLY_INITIALIZED; private static int CLASS_STATE_INITIALIZATION_ERROR; + public long getAccessFlags() { return accessFlags.getValue(this); } + // Convenience routine + public AccessFlags getAccessFlagsObj() { return new AccessFlags(getAccessFlags()); } + + public boolean isPublic() { return getAccessFlagsObj().isPublic(); } + public boolean isFinal() { return getAccessFlagsObj().isFinal(); } + public boolean isInterface() { return getAccessFlagsObj().isInterface(); } + public boolean isAbstract() { return getAccessFlagsObj().isAbstract(); } + public boolean isSuper() { return getAccessFlagsObj().isSuper(); } + public boolean isSynthetic() { return getAccessFlagsObj().isSynthetic(); } private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("InstanceKlass"); @@ -88,6 +98,7 @@ public class InstanceKlass extends Klass { breakpoints = type.getAddressField("_breakpoints"); } headerSize = type.getSize(); + accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0); // read internal field flags constants FIELD_FLAG_IS_INITIALIZED = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_initialized"); @@ -150,6 +161,7 @@ public class InstanceKlass extends Klass { private static CIntField initState; private static CIntField itableLen; private static CIntField nestHostIndex; + private static CIntField accessFlags; private static AddressField breakpoints; // type safe enum for ClassState from instanceKlass.hpp @@ -499,7 +511,7 @@ public class InstanceKlass extends Klass { } } - public boolean implementsInterface(Klass k) { + public boolean implementsInterface(InstanceKlass k) { if (Assert.ASSERTS_ENABLED) { Assert.that(k.isInterface(), "should not reach here"); } @@ -511,7 +523,7 @@ public class InstanceKlass extends Klass { return false; } - boolean computeSubtypeOf(Klass k) { + boolean computeSubtypeOf(InstanceKlass k) { if (k.isInterface()) { return implementsInterface(k); } else { @@ -535,6 +547,7 @@ public class InstanceKlass extends Klass { visitor.doCInt(nonstaticOopMapSize, true); visitor.doCInt(initState, true); visitor.doCInt(itableLen, true); + visitor.doCInt(accessFlags, true); } /* diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java index 1b8a9d0ef69..561c4683d29 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,6 @@ public class Klass extends Metadata implements ClassConstants { superField = new MetadataField(type.getAddressField("_super"), 0); layoutHelper = new IntField(type.getJIntField("_layout_helper"), 0); name = type.getAddressField("_name"); - accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0); try { traceIDField = type.getField("_trace_id"); } catch(Exception e) { @@ -95,7 +94,6 @@ public class Klass extends Metadata implements ClassConstants { private static MetadataField superField; private static IntField layoutHelper; private static AddressField name; - private static CIntField accessFlags; private static MetadataField subklass; private static MetadataField nextSibling; private static MetadataField nextLink; @@ -117,9 +115,6 @@ public class Klass extends Metadata implements ClassConstants { public Klass getJavaSuper() { return null; } public int getLayoutHelper() { return layoutHelper.getValue(this); } public Symbol getName() { return getSymbol(name); } - public long getAccessFlags() { return accessFlags.getValue(this); } - // Convenience routine - public AccessFlags getAccessFlagsObj(){ return new AccessFlags(getAccessFlags()); } public Klass getSubklassKlass() { return (Klass) subklass.getValue(this); } public Klass getNextSiblingKlass() { return (Klass) nextSibling.getValue(this); } public Klass getNextLinkKlass() { return (Klass) nextLink.getValue(this); } @@ -175,7 +170,6 @@ public class Klass extends Metadata implements ClassConstants { visitor.doMetadata(superField, true); visitor.doInt(layoutHelper, true); // visitor.doOop(name, true); - visitor.doCInt(accessFlags, true); visitor.doMetadata(subklass, true); visitor.doMetadata(nextSibling, true); visitor.doCInt(vtableLen, true); @@ -205,12 +199,4 @@ public class Klass extends Metadata implements ClassConstants { // The subclasses override this to produce the correct form, eg // Ljava/lang/String; For ArrayKlasses getName itself is the signature. public String signature() { return getName().asString(); } - - // Convenience routines - public boolean isPublic() { return getAccessFlagsObj().isPublic(); } - public boolean isFinal() { return getAccessFlagsObj().isFinal(); } - public boolean isInterface() { return getAccessFlagsObj().isInterface(); } - public boolean isAbstract() { return getAccessFlagsObj().isAbstract(); } - public boolean isSuper() { return getAccessFlagsObj().isSuper(); } - public boolean isSynthetic() { return getAccessFlagsObj().isSynthetic(); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java index a4cdb671959..c71cb3156ea 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,7 +107,7 @@ public class ObjectHeap { /** iterate objects of given Klass. param 'includeSubtypes' tells whether to * include objects of subtypes or not */ - public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k, boolean includeSubtypes) { + public void iterateObjectsOfKlass(HeapVisitor visitor, final InstanceKlass k, boolean includeSubtypes) { if (includeSubtypes) { if (k.isFinal()) { // do the simpler "exact" klass loop @@ -124,7 +124,7 @@ public class ObjectHeap { } /** iterate objects of given Klass (objects of subtypes included) */ - public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k) { + public void iterateObjectsOfKlass(HeapVisitor visitor, final InstanceKlass k) { iterateObjectsOfKlass(visitor, k, true); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java index fa28a96e333..c4abb3e946d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ public class ConcurrentLocksPrinter { private void fillLocks() { VM vm = VM.getVM(); SystemDictionary sysDict = vm.getSystemDictionary(); - Klass absOwnSyncKlass = sysDict.getAbstractOwnableSynchronizerKlass(); + InstanceKlass absOwnSyncKlass = sysDict.getAbstractOwnableSynchronizerKlass(); ObjectHeap heap = vm.getObjectHeap(); // may be not loaded at all if (absOwnSyncKlass != null) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java index e23e63806bd..1dc67330d3d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java @@ -76,9 +76,10 @@ public class ThreadLocalAllocBuffer extends VMObject { private long endReserve() { long labAlignmentReserve = VM.getVM().getLabAlignmentReserve(); + long reserveForAllocationPrefetch = VM.getVM().getReserveForAllocationPrefetch(); long heapWordSize = VM.getVM().getHeapWordSize(); - return labAlignmentReserve * heapWordSize; + return Math.max(labAlignmentReserve, reserveForAllocationPrefetch) * heapWordSize; } /** Support for iteration over heap -- not sure how this will diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java index 1607563150a..dc27a4fc59e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -123,6 +123,7 @@ public class VM { private int invocationEntryBCI; private ReversePtrs revPtrs; private VMRegImpl vmregImpl; + private int reserveForAllocationPrefetch; private int labAlignmentReserve; // System.getProperties from debuggee VM @@ -446,6 +447,8 @@ public class VM { boolType = (CIntegerType) db.lookupType("bool"); Type threadLocalAllocBuffer = db.lookupType("ThreadLocalAllocBuffer"); + CIntegerField reserveForAllocationPrefetchField = threadLocalAllocBuffer.getCIntegerField("_reserve_for_allocation_prefetch"); + reserveForAllocationPrefetch = (int)reserveForAllocationPrefetchField.getCInteger(intType); Type collectedHeap = db.lookupType("CollectedHeap"); CIntegerField labAlignmentReserveField = collectedHeap.getCIntegerField("_lab_alignment_reserve"); @@ -912,6 +915,10 @@ public class VM { return vmInternalInfo; } + public int getReserveForAllocationPrefetch() { + return reserveForAllocationPrefetch; + } + public int getLabAlignmentReserve() { return labAlignmentReserve; } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java index b7c470e3477..0e65a41c571 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,7 +90,7 @@ public class ClassLoaderStats extends Tool { VM vm = VM.getVM(); ObjectHeap heap = vm.getObjectHeap(); - Klass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass(); + InstanceKlass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass(); try { heap.iterateObjectsOfKlass(new DefaultHeapVisitor() { public boolean doObj(Oop oop) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 46e53411dee..6074b2b32dc 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -165,8 +165,12 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem } public int getAccessFlags() { - HotSpotVMConfig config = config(); - return UNSAFE.getInt(getKlassPointer() + config.klassAccessFlagsOffset); + if (isArray()) { + return 0; // Array Metadata doesn't set access_flags + } else { + HotSpotVMConfig config = config(); + return UNSAFE.getInt(getKlassPointer() + config.instanceKlassAccessFlagsOffset); + } } public int getMiscFlags() { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index e4e23c6d8b8..c058f785715 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -84,7 +84,6 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { */ final int javaMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle"); - final int klassAccessFlagsOffset = getFieldOffset("Klass::_access_flags", Integer.class, "AccessFlags"); final int klassLayoutHelperOffset = getFieldOffset("Klass::_layout_helper", Integer.class, "jint"); final int klassLayoutHelperNeutralValue = getConstant("Klass::_lh_neutral_value", Integer.class); @@ -93,6 +92,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { final int vtableEntrySize = getFieldValue("CompilerToVM::Data::sizeof_vtableEntry", Integer.class, "int"); final int vtableEntryMethodOffset = getFieldOffset("vtableEntry::_method", Integer.class, "Method*"); + final int instanceKlassAccessFlagsOffset = getFieldOffset("InstanceKlass::_access_flags", Integer.class, "AccessFlags"); final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "InstanceKlass::ClassState"); final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*"); final int instanceKlassFieldInfoStreamOffset = getFieldOffset("InstanceKlass::_fieldinfo_stream", Integer.class, "Array*"); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_en.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_en.properties new file mode 100644 index 00000000000..e1312e77aa4 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard_en.properties @@ -0,0 +1,28 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# + +# Empty resource bundle to be used with English default bundle as parent. +# This is necessary to make English resources available on systems using +# one of the supported non-English locales as default locale. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_en.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_en.properties new file mode 100644 index 00000000000..e1312e77aa4 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_en.properties @@ -0,0 +1,28 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# + +# Empty resource bundle to be used with English default bundle as parent. +# This is necessary to make English resources available on systems using +# one of the supported non-English locales as default locale. diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java index 19e8b45c491..9a13eb3dca5 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import com.sun.jdi.InternalException; import com.sun.jdi.Locatable; import com.sun.jdi.Location; import com.sun.jdi.Method; +import com.sun.jdi.ObjectCollectedException; import com.sun.jdi.ObjectReference; import com.sun.jdi.ReferenceType; import com.sun.jdi.ThreadReference; @@ -206,6 +207,19 @@ public class EventSetImpl extends ArrayList implements EventSet { } + /* Safely fetch the thread name in case there is an ObjectCollectedException. + * This can happen when dealing with SUSPEND_NONE events. + */ + private static String getThreadName(ThreadReference thread) { + String name; + try { + name = thread.name(); + } catch (ObjectCollectedException oce) { + name = ""; + } + return name; + } + abstract class ThreadedEventImpl extends EventImpl { private ThreadReference thread; @@ -220,7 +234,7 @@ public class EventSetImpl extends ArrayList implements EventSet { } public String toString() { - return eventName() + " in thread " + thread.name(); + return eventName() + " in thread " + getThreadName(thread); } } @@ -249,7 +263,7 @@ public class EventSetImpl extends ArrayList implements EventSet { public String toString() { return eventName() + "@" + ((location() == null) ? " null" : location().toString()) + - " in thread " + thread().name(); + " in thread " + getThreadName(thread()); } } diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 491182a583f..8a02f3f9ee9 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -70,6 +70,7 @@ typedef struct ThreadNode { unsigned int popFrameEvent : 1; unsigned int popFrameProceed : 1; unsigned int popFrameThread : 1; + unsigned int frameGeneration_accessed:1; /* true if frameGeneration accessed to produce a FrameID */ EventIndex current_ei; /* Used to determine if we are currently handling an event on this thread. */ jobject pendingStop; /* Object we are throwing to stop the thread (ThreadReferenceImpl.stop). */ jint suspendCount; /* Number of outstanding suspends from the debugger. */ @@ -157,11 +158,24 @@ setThreadLocalStorage(jthread thread, ThreadNode *node) error = JVMTI_FUNC_PTR(gdata->jvmti,SetThreadLocalStorage) (gdata->jvmti, thread, (void*)node); - if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE && node == NULL) { - /* Just return. This can happen when clearing the TLS. */ + if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) { + if (node == NULL) { + // Just return. This can happen when clearing the TLS. + return; + } + if (isVThread(thread)) { + // Just return. This can happen with a vthread that is running and we + // had to create a ThreadNode for it. By the time we get here, it may + // have already terminated. + return; + } + } + if (error == JVMTI_ERROR_WRONG_PHASE && gdata->vmDead && isVThread(thread)) { + // Just return. This can happen with vthreads when the vm is exiting. return; - } else if ( error != JVMTI_ERROR_NONE ) { - /* The jthread object must be valid, so this must be a fatal error */ + } + if (error != JVMTI_ERROR_NONE) { + // The jthread object must be valid, so this must be a fatal error. EXIT_ERROR(error, "cannot set thread local storage"); } } @@ -251,9 +265,10 @@ findThread(ThreadList *list, jthread thread) * Otherwise the thread should not be on the runningThreads. */ if ( !gdata->jvmtiCallBacksCleared ) { - /* The thread better not be on either list if the TLS lookup failed. */ + // The thread better not be on the runningThreads list if the TLS lookup failed. + // It might be on the runningVThreads list because of how ThreadNodes for vthreads + // can be recreated just before terminating, so we don't check runningVThreads. JDI_ASSERT(!nonTlsSearch(getEnv(), &runningThreads, thread)); - JDI_ASSERT(!nonTlsSearch(getEnv(), &runningVThreads, thread)); } else { /* * Search the runningThreads and runningVThreads lists. The TLS lookup may have @@ -606,6 +621,7 @@ freeUnusedVThreadNode(JNIEnv *env, ThreadNode* node) !node->popFrameEvent && !node->popFrameProceed && !node->popFrameThread && + !node->frameGeneration_accessed && node->pendingStop == NULL) { removeNode(node); @@ -2673,6 +2689,7 @@ threadControl_getFrameGeneration(jthread thread) if (node != NULL) { frameGeneration = node->frameGeneration; + node->frameGeneration_accessed = JNI_TRUE; } } debugMonitorExit(threadLock); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java index eaba86e6327..1180ebd6ea2 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java @@ -34,6 +34,7 @@ import jdk.jfr.internal.periodic.PeriodicEvents; import jdk.jfr.internal.util.ImplicitFields; import jdk.jfr.internal.util.TimespanRate; import jdk.jfr.internal.util.Utils; +import jdk.jfr.internal.settings.CPUThrottleSetting; import jdk.jfr.internal.settings.Throttler; import jdk.jfr.internal.tracing.Modification; @@ -60,7 +61,7 @@ public final class PlatformEventType extends Type { private boolean stackTraceEnabled = true; private long thresholdTicks = 0; private long period = 0; - private TimespanRate cpuRate; + private TimespanRate cpuRate = TimespanRate.of(CPUThrottleSetting.DEFAULT_VALUE); private boolean hasHook; private boolean beginChunk; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java index b07a71dd4d5..64454fc3cb4 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java @@ -34,6 +34,7 @@ import static jdk.jfr.internal.LogTag.JFR; import java.io.IOException; import java.io.InputStream; import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.StandardOpenOption; @@ -744,7 +745,14 @@ public final class PlatformRecording implements AutoCloseable { } private void transferChunks(WriteablePath path) throws IOException { - try (ChunksChannel cc = new ChunksChannel(chunks); FileChannel fc = FileChannel.open(path.getReal(), StandardOpenOption.WRITE, StandardOpenOption.APPEND)) { + // Before writing, wipe the file if it already exists. + try (ChunksChannel cc = new ChunksChannel(chunks); FileChannel fc = FileChannel.open(path.getReal(), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)) { + // Mitigate races against other processes + FileLock l = fc.tryLock(); + if (l == null) { + Logger.log(LogTag.JFR, LogLevel.INFO, "Dump operation skipped for recording \"" + name + "\" (" + id + "). File " + path.getRealPathText() + " is locked by other dump operation or activity."); + return; + } long bytes = cc.transferTo(fc); Logger.log(LogTag.JFR, LogLevel.INFO, "Transferred " + bytes + " bytes from the disk repository"); // No need to force if no data was transferred, which avoids IOException when device is /dev/null diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini index 91decb1aa20..5d72a9f85dc 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini @@ -110,6 +110,15 @@ table = "COLUMN 'Time', 'Requested By', 'Operation', 'Classes' GROUP BY redefinitionId ORDER BY duration DESC" +[jvm.classes-by-source] + label = "Classes by Source" + table = "COLUMN 'Source', 'Count' + FORMAT truncate-beginning, none + SELECT source, COUNT(*) AS C + FROM jdk.ClassDefine + GROUP BY source + ORDER BY C DESC" + [jvm.compiler-configuration] label = "Compiler Configuration" form = "SELECT LAST(threadCount), LAST(dynamicCompilerThreadCount), LAST(tieredCompilation) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java index 944827f6d6f..7ea0ace21bb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java @@ -65,7 +65,7 @@ public final class CPUThrottleSetting extends SettingControl { } } } - return Objects.requireNonNullElse(highestRate.toString(), DEFAULT_VALUE); + return highestRate == null ? DEFAULT_VALUE : highestRate.toString(); } @Override diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java index 2632cd63848..0a7b14965cb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ public record Rate(long amount, TimespanUnit unit) { String value = splitted[0].strip(); String unit = splitted[1].strip(); TimespanUnit tu = TimespanUnit.fromText(unit); - if (unit == null) { + if (tu == null) { return null; } try { diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index 928b9a47934..03b9611c179 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -27,9 +27,11 @@ package jdk.tools.jlink.internal; import static jdk.tools.jlink.internal.TaskHelper.JLINK_BUNDLE; import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.UncheckedIOException; import java.lang.module.Configuration; @@ -56,6 +58,7 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -238,6 +241,27 @@ public class JlinkTask { } public static final String OPTIONS_RESOURCE = "jdk/tools/jlink/internal/options"; + // Release information stored in the java.base module + private static final String JDK_RELEASE_RESOURCE = "jdk/internal/misc/resources/release.txt"; + + /** + * Read the release.txt from the module. + */ + private static Optional getReleaseInfo(ModuleReference mref) { + try { + Optional release = mref.open().open(JDK_RELEASE_RESOURCE); + + if (release.isEmpty()) { + return Optional.empty(); + } + + try (var r = new BufferedReader(new InputStreamReader(release.get()))) { + return Optional.of(r.readLine()); + } + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } int run(String[] args) { if (log == null) { @@ -410,7 +434,8 @@ public class JlinkTask { // Sanity check version if we use JMODs if (!isLinkFromRuntime) { - checkJavaBaseVersion(finder); + assert(finder.find("java.base").isPresent()); + checkJavaBaseVersion(finder.find("java.base").get()); } // Determine the roots set @@ -561,32 +586,34 @@ public class JlinkTask { return finder; } + private static String getCurrentRuntimeVersion() { + ModuleReference current = ModuleLayer.boot() + .configuration() + .findModule("java.base") + .get() + .reference(); + // This jlink runtime should always have the release.txt + return getReleaseInfo(current).get(); + } + /* - * Checks the version of the module descriptor of java.base for compatibility - * with the current runtime version. + * Checks the release information of the java.base used for target image + * for compatibility with the java.base used by jlink. * - * @throws IllegalArgumentException the descriptor of java.base has no - * version or the java.base version is not the same as the current runtime's - * version. + * @throws IllegalArgumentException If the `java.base` module reference `target` + * is not compatible with this jlink. */ - private static void checkJavaBaseVersion(ModuleFinder finder) { - assert finder.find("java.base").isPresent(); + private static void checkJavaBaseVersion(ModuleReference target) { + String currentRelease = getCurrentRuntimeVersion(); - // use the version of java.base module, if present, as - // the release version for multi-release JAR files - ModuleDescriptor.Version v = finder.find("java.base").get() - .descriptor().version().orElseThrow(() -> - new IllegalArgumentException("No version in java.base descriptor") - ); + String targetRelease = getReleaseInfo(target).orElseThrow(() -> new IllegalArgumentException( + taskHelper.getMessage("err.jlink.version.missing", currentRelease))); - Runtime.Version version = Runtime.Version.parse(v.toString()); - if (Runtime.version().feature() != version.feature() || - Runtime.version().interim() != version.interim()) { - // jlink version and java.base version do not match. - // We do not (yet) support this mode. + if (!currentRelease.equals(targetRelease)) { + // Current runtime image and the target runtime image are not compatible build throw new IllegalArgumentException(taskHelper.getMessage("err.jlink.version.mismatch", - Runtime.version().feature(), Runtime.version().interim(), - version.feature(), version.interim())); + currentRelease, + targetRelease)); } } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java index d53589dc388..dca4d57f764 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java @@ -362,10 +362,13 @@ public final class TaskHelper { if (plugin instanceof DefaultCompressPlugin) { plugOption - = new PluginOption(false, + = new PluginOption(true, (task, opt, arg) -> { Map m = addArgumentMap(plugin); - m.put(plugin.getName(), DefaultCompressPlugin.LEVEL_2); + String level = (arg != null && !arg.isEmpty()) + ? arg + :"zip-6"; + m.put(plugin.getName(), level); }, false, "--compress", "-c"); mainOptions.add(plugOption); } else if (plugin instanceof DefaultStripDebugPlugin) { diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties index 080d51506a6..374ed78f608 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties @@ -130,7 +130,9 @@ err.runtime.link.patched.module=jlink does not support linking from the run-time err.no.module.path=--module-path option must be specified with --add-modules ALL-MODULE-PATH err.empty.module.path=No module found in module path ''{0}'' with --add-modules ALL-MODULE-PATH err.limit.modules=--limit-modules not allowed with --add-modules ALL-MODULE-PATH -err.jlink.version.mismatch=jlink version {0}.{1} does not match target java.base version {2}.{3} +err.jlink.version.mismatch=jlink build ''{0}'' does not match target java.base build ''{1}'' +err.jlink.version.missing=jlink build ''{0}'' cannot find the build signature\ +\ in the java.base specified on module path, likely from an earlier build. err.automatic.module:automatic module cannot be used with jlink: {0} from {1} err.unknown.byte.order:unknown byte order {0} err.launcher.main.class.empty:launcher main class name cannot be empty: {0} diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties index e9be0b4e587..7e3c26fa7b8 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties @@ -61,14 +61,14 @@ Class optimization: convert Class.forName calls to constant loads. class-for-name.usage=\ \ --class-for-name Class optimization: convert Class.forName calls to constant loads. -compress.argument=[:filter=] +compress.argument=[:filter=] compress.description= Compression to use in compressing resources. compress.usage=\ \ --compress Compression to use in compressing resources:\n\ \ Accepted values are:\n\ -\ zip-[0-9], where zip-0 provides no compression,\n\ +\ zip-'{0-9}', where zip-0 provides no compression,\n\ \ and zip-9 provides the best compression.\n\ \ Default is zip-6. @@ -307,15 +307,15 @@ plugin.opt.disable-plugin=\ \ --disable-plugin Disable the plugin mentioned plugin.opt.compress=\ -\ --compress Compression to use in compressing resources:\n\ +\ --compress Compress all resources in the output image:\n\ \ Accepted values are:\n\ -\ zip-[0-9], where zip-0 provides no compression,\n\ +\ zip-'{0-9}', where zip-0 provides no compression,\n\ \ and zip-9 provides the best compression.\n\ \ Default is zip-6.\n\ \ Deprecated values to be removed in a future release:\n\ -\ 0: No compression. Equivalent to zip-0.\n\ +\ 0: No compression. Use zip-0 instead.\n\ \ 1: Constant String Sharing\n\ -\ 2: Equivalent to zip-6. +\ 2: ZIP. Use zip-6 instead. plugin.opt.strip-debug=\ \ -G, --strip-debug Strip debug information diff --git a/src/jdk.jlink/share/man/jlink.md b/src/jdk.jlink/share/man/jlink.md index dc256af43b5..0d16e69c9ef 100644 --- a/src/jdk.jlink/share/man/jlink.md +++ b/src/jdk.jlink/share/man/jlink.md @@ -64,12 +64,15 @@ Developers are responsible for updating their custom runtime images. `--bind-services` : Link service provider modules and their dependencies. -`-c ={0|1|2}` or `--compress={0|1|2}` -: Enable compression of resources: +`-c zip-{0-9}` or `--compress=zip-{0-9}` +: Enable compression of resources. The accepted values are: + zip-{0-9}, where zip-0 provides no compression, + and zip-9 provides the best compression. Default is zip-6. - - `0`: No compression +: Deprecated values to be removed in a future release: + - `0`: No compression. Use zip-0 instead. - `1`: Constant string sharing - - `2`: ZIP + - `2`: ZIP. Use zip-6 instead. `--disable-plugin` *pluginname* : Disables the specified plug-in. See [jlink Plug-ins] for the list of @@ -170,14 +173,18 @@ For a complete list of all available plug-ins, run the command ### Plugin `compress` Options -: `--compress=`{`0`\|`1`\|`2`}\[`:filter=`*pattern-list*\] +: `--compress=zip-`{`0`-`9`}\[`:filter=`*pattern-list*\] Description : Compresses all resources in the output image. + Accepted values are: + zip-{0-9}, where zip-0 provides no compression, + and zip-9 provides the best compression. Default is zip-6. - - Level 0: No compression +: Deprecated values to be removed in a future release: + - Level 0: No compression. Use zip-0 instead. - Level 1: Constant string sharing - - Level 2: ZIP + - Level 2: ZIP. Use zip-6 instead. An optional *pattern-list* filter can be specified to list the pattern of files to include. diff --git a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp index 927b5ff3d42..775f0e17409 100644 --- a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp +++ b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp @@ -97,7 +97,6 @@ struct Config : public AllStatic { }; typedef ConcurrentHashTable SimpleTestTable; -typedef ConcurrentHashTable::MultiGetHandle SimpleTestGetHandle; typedef ConcurrentHashTable CustomTestTable; struct SimpleTestLookup { @@ -345,10 +344,6 @@ static void cht_scope(Thread* thr) { SimpleTestLookup stl(val); SimpleTestTable* cht = new SimpleTestTable(); EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed."; - { - SimpleTestGetHandle get_handle(thr, cht); - EXPECT_EQ(*get_handle.get(stl), val) << "Getting a pre-existing value failed."; - } // We do remove here to make sure the value-handle 'unlocked' the table when leaving the scope. EXPECT_TRUE(cht->remove(thr, stl)) << "Removing a pre-existing value failed."; EXPECT_FALSE(cht_get_copy(cht, thr, stl) == val) << "Got a removed value."; @@ -556,7 +551,6 @@ public: }; typedef ConcurrentHashTable TestTable; -typedef ConcurrentHashTable::MultiGetHandle TestGetHandle; struct TestLookup { uintptr_t _val; @@ -788,15 +782,8 @@ public: bool test_loop() { for (uintptr_t v = 0x1; v < 0xFFF; v++ ) { uintptr_t tv; - if (v & 0x1) { - TestLookup tl(v); - tv = cht_get_copy(_cht, this, tl); - } else { - TestLookup tl(v); - TestGetHandle value_handle(this, _cht); - uintptr_t* tmp = value_handle.get(tl); - tv = tmp != nullptr ? *tmp : 0; - } + TestLookup tl(v); + tv = cht_get_copy(_cht, this, tl); EXPECT_TRUE(tv == 0 || tv == v) << "Got unknown value."; } return true; diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index a51e8aef5ee..ddc6e55dc05 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -49,7 +49,6 @@ compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java 8190680 generic-all compiler/runtime/Test8168712.java#with-dtrace 8211769,8211771 generic-ppc64,generic-ppc64le,linux-s390x compiler/runtime/Test8168712.java#without-dtrace 8211769,8211771 generic-ppc64,generic-ppc64le,linux-s390x -compiler/loopopts/TestUnreachableInnerLoop.java 8288981 linux-s390x compiler/c2/Test8004741.java 8235801 generic-all compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all @@ -79,8 +78,6 @@ compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64 serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java 8369150 generic-all -compiler/arguments/TestCodeEntryAlignment.java 8372703 generic-x64 - ############################################################################# # :hotspot_gc @@ -97,6 +94,7 @@ gc/shenandoah/TestEvilSyncBug.java#generational 8345501 generic-all gc/shenandoah/TestRetainObjects.java#no-tlab 8361099 generic-all gc/shenandoah/TestSieveObjects.java#no-tlab 8361099 generic-all gc/shenandoah/TestSieveObjects.java#no-tlab-genshen 8361099 generic-all +gc/cslocker/TestCSLocker.java 8373025 generic-all ############################################################################# @@ -142,6 +140,9 @@ serviceability/sa/ClhsdbPstack.java#core 8318754 macosx-aarch64 serviceability/sa/TestJmapCore.java 8318754 macosx-aarch64 serviceability/sa/TestJmapCoreMetaspace.java 8318754 macosx-aarch64 +serviceability/sa/ClhsdbScanOops.java#parallel 8373022 generic-all +serviceability/sa/ClhsdbScanOops.java#serial 8373022 generic-all + serviceability/sa/ClhsdbThreadContext.java 8356704 windows-x64 serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64 diff --git a/test/hotspot/jtreg/applications/jcstress/JcstressRunner.java b/test/hotspot/jtreg/applications/jcstress/JcstressRunner.java index a0c9488dfe3..eb785b06330 100644 --- a/test/hotspot/jtreg/applications/jcstress/JcstressRunner.java +++ b/test/hotspot/jtreg/applications/jcstress/JcstressRunner.java @@ -45,7 +45,7 @@ import java.util.List; revision = JcstressRunner.VERSION, extension = "jar", unpack = false) public class JcstressRunner { - public static final String VERSION = "0.17-SNAPSHOT-20241217"; + public static final String VERSION = "0.17-SNAPSHOT-20250619"; public static final String MAIN_CLASS = "org.openjdk.jcstress.Main"; public static final String TIME_BUDGET_PROPERTY = "jcstress.time_budget"; diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyDisjoint.java b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyDisjoint.java index 162ba20048d..73b1af90548 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyDisjoint.java +++ b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyDisjoint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ import java.util.Random; /** * @test - * @bug 8251871 8285301 + * @bug 8251871 8285301 8371964 * @summary Optimize arrayCopy using AVX-512 masked instructions. * * @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch -XX:+IgnoreUnrecognizedVMOptions @@ -52,6 +52,9 @@ import java.util.Random; * compiler.arraycopy.TestArrayCopyDisjoint * @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch -XX:+UnlockExperimentalVMOptions -XX:+AlwaysAtomicAccesses * compiler.arraycopy.TestArrayCopyDisjoint + * @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:UseAVX=3 -XX:MaxVectorSize=32 -XX:ArrayOperationPartialInlineSize=32 -XX:+StressIGVN + * compiler.arraycopy.TestArrayCopyDisjoint * */ diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java index fdc0a83fb8b..bfcc775efeb 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java @@ -30,7 +30,7 @@ import jdk.test.lib.Utils; /* * @test - * @bug 8324655 8329797 8331090 + * @bug 8324655 8331090 * @key randomness * @summary Test that if expressions are properly folded into min/max nodes * @library /test/lib / @@ -139,42 +139,6 @@ public class TestIfMinMax { return a <= b ? b : a; } - public class Dummy { - long l; - public Dummy(long l) { this.l = l; } - } - - @Setup - Object[] setupDummyArray() { - Dummy[] arr = new Dummy[512]; - for (int i = 0; i < 512; i++) { - arr[i] = new Dummy(RANDOM.nextLong()); - } - return new Object[] { arr }; - } - - @Test - @Arguments(setup = "setupDummyArray") - @IR(failOn = { IRNode.MAX_L }) - public long testMaxLAndBarrierInLoop(Dummy[] arr) { - long result = 0; - for (int i = 0; i < arr.length; ++i) { - result += Math.max(arr[i].l, 1); - } - return result; - } - - @Test - @Arguments(setup = "setupDummyArray") - @IR(failOn = { IRNode.MIN_L }) - public long testMinLAndBarrierInLoop(Dummy[] arr) { - long result = 0; - for (int i = 0; i < arr.length; ++i) { - result += Math.min(arr[i].l, 1); - } - return result; - } - @Setup static Object[] setupIntArrays() { int[] a = new int[512]; diff --git a/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm b/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm index beeffa69a97..78be0bbb177 100644 --- a/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm +++ b/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm @@ -46,6 +46,7 @@ super class IllegalAccessInCatch idiv; endtry t0; ireturn; + catch t0 java/lang/IllegalAccessError; catch t0 jdk/internal/agent/AgentConfigurationError; // loadable but not accessible from unnamed module stack_frame_type full; stack_map class java/lang/Throwable; diff --git a/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java index 46541d76016..fa81fa93f11 100644 --- a/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java +++ b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java @@ -23,16 +23,18 @@ /* * @test - * @bug 8367002 + * @bug 8367002 8370766 * @summary Compilers might not generate handlers for recursive exceptions * * @compile IllegalAccessInCatch.jasm * @run main/othervm -Xbatch * -XX:CompileCommand=compileonly,IllegalAccessInCatch*::test + * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack * -XX:-TieredCompilation * TestAccessErrorInCatch * @run main/othervm -Xbatch * -XX:CompileCommand=compileonly,IllegalAccessInCatch*::test + * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack * -XX:TieredStopAtLevel=3 * TestAccessErrorInCatch */ @@ -62,6 +64,11 @@ public class TestAccessErrorInCatch { } private static int invoke(MethodHandle mh) throws Throwable { - return (int) mh.invokeExact(); + int expected = 1; + int ret = (int) mh.invokeExact(); + if (ret != expected) { + throw new RuntimeException("Returned " + ret + " but expected " + expected); + } + return ret; } } diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestMinMaxLongLoopBarrier.java b/test/hotspot/jtreg/compiler/gcbarriers/TestMinMaxLongLoopBarrier.java new file mode 100644 index 00000000000..9f2ddc0d20e --- /dev/null +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestMinMaxLongLoopBarrier.java @@ -0,0 +1,86 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * 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.gcbarriers; + +import compiler.lib.ir_framework.Arguments; +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.IRNode; +import compiler.lib.ir_framework.Setup; +import compiler.lib.ir_framework.Test; +import compiler.lib.ir_framework.TestFramework; +import jdk.test.lib.Utils; + +import java.util.Random; + +/* + * @test + * @bug 8329797 + * @key randomness + * @summary Test that MinL/MaxL nodes are removed when GC barriers in loop + * @library /test/lib / + * @run driver ${test.main.class} + */ +public class TestMinMaxLongLoopBarrier { + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + TestFramework.run(); + } + + public class Dummy { + long l; + public Dummy(long l) { this.l = l; } + } + + @Setup + Object[] setupDummyArray() { + Dummy[] arr = new Dummy[512]; + for (int i = 0; i < 512; i++) { + arr[i] = new Dummy(RANDOM.nextLong()); + } + return new Object[] { arr }; + } + + @Test + @Arguments(setup = "setupDummyArray") + @IR(failOn = { IRNode.MAX_L }) + public long testMaxLAndBarrierInLoop(Dummy[] arr) { + long result = 0; + for (int i = 0; i < arr.length; ++i) { + result += Math.max(arr[i].l, 1); + } + return result; + } + + @Test + @Arguments(setup = "setupDummyArray") + @IR(failOn = { IRNode.MIN_L }) + public long testMinLAndBarrierInLoop(Dummy[] arr) { + long result = 0; + for (int i = 0; i < arr.length; ++i) { + result += Math.min(arr[i].l, 1); + } + return result; + } +} diff --git a/test/hotspot/jtreg/compiler/inlining/TestLateMHClonedCallNode.java b/test/hotspot/jtreg/compiler/inlining/TestLateMHClonedCallNode.java new file mode 100644 index 00000000000..417fe60ebae --- /dev/null +++ b/test/hotspot/jtreg/compiler/inlining/TestLateMHClonedCallNode.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025 IBM Corporation. All rights reserved. + * 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 8370939 + * @summary C2: SIGSEGV in SafePointNode::verify_input when processing MH call from Compile::process_late_inline_calls_no_inline() + * @run main/othervm -XX:-BackgroundCompilation -XX:CompileOnly=TestLateMHClonedCallNode::test1 + * -XX:CompileOnly=TestLateMHClonedCallNode::test2 TestLateMHClonedCallNode + * @run main TestLateMHClonedCallNode + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class TestLateMHClonedCallNode { + private static int field; + + public static void main(String[] args) throws Throwable { + for (int i = 0; i < 20_000; i++) { + test1(true); + test1(false); + test2(true); + test2(false); + } + } + + private static int test1(boolean flag) throws Throwable { + return inlined1(flag); + } + + private static int inlined1(boolean flag) throws Throwable { + MethodHandle mh = mh1; + for (int i = 0; i < 3; ++i) { + if (i > 1) { + mh = mh2; + } + } + int res = 0; + for (int i = 0; i < 2; i++) { + if (!flag) { + field = 42; + } + res += (int) mh.invokeExact(); + } + return res; + } + + private static int test2(boolean flag) throws Throwable { + int res = (int)unknownMh.invokeExact(); + return inlined2(flag); + } + + private static int inlined2(boolean flag) throws Throwable { + MethodHandle mh = mh1; + for (int i = 0; i < 3; ++i) { + if (i > 1) { + mh = mh2; + } + } + int res = 0; + for (int i = 0; i < 2; i++) { + if (!flag) { + field = 42; + } + res += (int) mh.invokeExact(); + } + return res; + } + + static final MethodHandle mh1; + static final MethodHandle mh2; + static MethodHandle unknownMh; + + static { + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + mh1 = lookup.findStatic(TestLateMHClonedCallNode.class, "method1", MethodType.methodType(int.class)); + mh2 = lookup.findStatic(TestLateMHClonedCallNode.class, "method2", MethodType.methodType(int.class)); + unknownMh = mh1; + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + throw new RuntimeException("Method handle lookup failed"); + } + } + + static int method1() { return 0; } + static int method2() { return 42; } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 787dedba9c6..85595b9b632 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1257,6 +1257,12 @@ public class IRNode { machOnly(MEM_TO_REG_SPILL_COPY, "MemToRegSpillCopy"); } + public static final String MEM_TO_REG_SPILL_COPY_TYPE = COMPOSITE_PREFIX + "MEM_TO_REG_SPILL_COPY_TYPE" + POSTFIX; + static { + String regex = START + "MemToRegSpillCopy" + MID + IS_REPLACED + ".*" + END; + machOnly(MEM_TO_REG_SPILL_COPY_TYPE, regex); + } + public static final String MIN = PREFIX + "MIN" + POSTFIX; static { beforeMatchingNameRegex(MIN, "Min(I|L)"); diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestABSMaskedMaxByteVector.java b/test/hotspot/jtreg/compiler/vectorapi/TestABSMaskedMaxByteVector.java new file mode 100644 index 00000000000..356892fadf8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestABSMaskedMaxByteVector.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.vectorapi; + +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.*; + +/* + * @test + * @bug 8337791 + * @summary Test byte vector predicated ABS with UseAVX=0 and MaxVectorSize=8 + * @modules jdk.incubator.vector + * @library /test/lib / + * @run driver compiler.vectorapi.TestABSMaskedMaxByteVector + */ + +public class TestABSMaskedMaxByteVector { + public static final VectorSpecies BSP = ByteVector.SPECIES_MAX; + public static int idx = 0; + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-ea", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:UseAVX=0", "-XX:MaxVectorSize=8"); + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-ea"); + } + + @Test + @IR(failOn = {IRNode.ABS_VB}, applyIfAnd = {"MaxVectorSize", " <= 8 ", "UseAVX", "0"}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"sse4.1", "true"}) + @IR(counts = {IRNode.ABS_VB, "1"}, applyIf = {"MaxVectorSize", " > 8 "}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"sse4.1", "true"}) + public void test() { + assert ByteVector.broadcast(BSP, (byte)-4) + .lanewise(VectorOperators.ABS, VectorMask.fromLong(BSP, 0xF)) + .lane(idx++ & 3) == 4; + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorSpilling.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorSpilling.java new file mode 100644 index 00000000000..9d9a85e174c --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorSpilling.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package compiler.vectorapi; + +import compiler.lib.ir_framework.*; + +import jdk.incubator.vector.IntVector; +import jdk.incubator.vector.VectorSpecies; + +import jdk.test.lib.Asserts; + +/** + * @test + * @bug 8370473 + * @library /test/lib / + * @summary Test alignment of vector spill slots. It should match the vector size. + * @modules jdk.incubator.vector + * @requires vm.opt.final.MaxVectorSize == null | vm.opt.final.MaxVectorSize >= 16 + * + * @run driver compiler.vectorapi.TestVectorSpilling + */ + +public class TestVectorSpilling { + + private static final VectorSpecies I_SPECIES = IntVector.SPECIES_128; + private static int LENGTH = 1024; + + private static int[] ia1; + private static int[] ia2; + private static int[] ir ; + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + } + + static class LData { + // Rading from a volatile field prevents cse optimization + static volatile long vF = 1042; + + long l1, l2, l3, l4, l5, l6, l7, l8; + public LData() { + l1 = vF; l2 = vF; l3 = vF; l4 = vF; l5 = vF; l6 = vF; l7 = vF; l8 = vF; + } + public long sum() { + return l1 + l2 + l3 + l4 + l5 + l6 + l7 + l8; + } + } + + + @Run(test = "test16ByteSpilling") + static void test16ByteSpilling_runner() { + test16ByteSpilling(1, 2, 3, 4, 5, 6, 7, 8, 9); + } + + @Test + @IR(counts = {IRNode.MEM_TO_REG_SPILL_COPY_TYPE, "vectorx", "> 0"}, + phase = {CompilePhase.FINAL_CODE}, + applyIfCPUFeature= {"rvv", "false"}) + static long test16ByteSpilling(long l1, long l2, long l3, long l4, long l5, long l6, long l7, long l8, + long l9 /* odd stack arg */) { + // To be scalar replaced and spilled to stack + LData d1 = new LData(); + LData d2 = new LData(); + LData d3 = new LData(); + + for (int i = 0; i < LENGTH; i += I_SPECIES.length()) { + IntVector a1v = IntVector.fromArray(I_SPECIES, ia1, i); + IntVector a2v = IntVector.fromArray(I_SPECIES, ia2, i); + int scalar = spillPoint(); + a1v.add(a2v) + .add(scalar).intoArray(ir, i); + } + + return l1 + l2 + l3 + l4 + l5 + l6 + l7 + l8 + l9 + d1.sum() + d2.sum() + d3.sum(); + } + + @DontInline + static int spillPoint() { + return 42; + } + + static { + ia1 = new int[LENGTH]; + ia2 = new int[LENGTH]; + ir = new int[LENGTH]; + } + +} diff --git a/test/hotspot/jtreg/containers/docker/DockerBasicTest.java b/test/hotspot/jtreg/containers/docker/DockerBasicTest.java index 8e2c0b6a85a..e564cae9d8e 100644 --- a/test/hotspot/jtreg/containers/docker/DockerBasicTest.java +++ b/test/hotspot/jtreg/containers/docker/DockerBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build HelloDocker @@ -45,10 +46,7 @@ public class DockerBasicTest { private static final String imageNameAndTag = Common.imageName("basic"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageNameAndTag); try { diff --git a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java index 9a4748563bd..a84cdacefa1 100644 --- a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java +++ b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build WaitForFlagFile * @run driver ShareTmpDir */ @@ -50,10 +51,7 @@ public class ShareTmpDir { private static final String imageName = Common.imageName("sharetmpdir"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java index 99220201f66..26f160ab27d 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,9 +48,8 @@ public class TestCPUAwareness { private static final int availableCPUs = Runtime.getRuntime().availableProcessors(); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestCPUSets.java b/test/hotspot/jtreg/containers/docker/TestCPUSets.java index 7894172e401..001914a6686 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUSets.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUSets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ * @requires (os.arch != "s390x") * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build AttemptOOM jdk.test.whitebox.WhiteBox PrintContainerInfo @@ -52,11 +53,8 @@ public class TestCPUSets { private static final String imageName = Common.imageName("cpusets"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestContainerInfo.java b/test/hotspot/jtreg/containers/docker/TestContainerInfo.java index b9b6fb65b75..a5579aa9528 100644 --- a/test/hotspot/jtreg/containers/docker/TestContainerInfo.java +++ b/test/hotspot/jtreg/containers/docker/TestContainerInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,6 +31,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build CheckContainerized jdk.test.whitebox.WhiteBox PrintContainerInfo @@ -49,10 +50,7 @@ public class TestContainerInfo { private static final String imageName = Common.imageName("container-info"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestJFREvents.java b/test/hotspot/jtreg/containers/docker/TestJFREvents.java index 4c33ecfc79b..d46c422723b 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFREvents.java +++ b/test/hotspot/jtreg/containers/docker/TestJFREvents.java @@ -34,6 +34,7 @@ * @modules java.base/jdk.internal.platform * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build JfrReporter jdk.test.whitebox.WhiteBox @@ -61,9 +62,7 @@ public class TestJFREvents { public static void main(String[] args) throws Exception { System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); // If cgroups is not configured, report success. Metrics metrics = Metrics.systemMetrics(); diff --git a/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java index c0dde368d1e..2c7120c577c 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java +++ b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build JfrNetwork @@ -48,10 +49,7 @@ public class TestJFRNetworkEvents { public static void main(String[] args) throws Exception { System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java b/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java index efe1fa4ffbc..7c26af9b27a 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java +++ b/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build EventProducer @@ -73,9 +74,7 @@ public class TestJFRWithJMX { static final AtomicReference ipAddr = new AtomicReference(); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - throw new SkippedException("Docker is not supported on this host"); - } + DockerTestUtils.checkCanTestDocker(); if (DockerTestUtils.isPodman() & !Platform.isRoot()) { throw new SkippedException("test cannot be run under rootless podman configuration"); diff --git a/test/hotspot/jtreg/containers/docker/TestJcmd.java b/test/hotspot/jtreg/containers/docker/TestJcmd.java index 8c210544bb6..3cfe2945e92 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmd.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmd.java @@ -29,6 +29,7 @@ * @requires container.support * @requires vm.flagless * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @library /test/lib @@ -62,7 +63,7 @@ public class TestJcmd { public static void main(String[] args) throws Exception { - DockerTestUtils.canTestDocker(); + DockerTestUtils.checkCanTestDocker(); // podman versions below 3.3.1 hava a bug where cross-container testing with correct // permissions fails. See JDK-8273216 diff --git a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java index 91a07012f00..28a7a20553f 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ * @requires vm.flagless * @requires !vm.asan * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @library /test/lib @@ -95,10 +96,7 @@ public class TestJcmdWithSideCar { private static final String NET_BIND_SERVICE = "--cap-add=NET_BIND_SERVICE"; public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(IMAGE_NAME); try { diff --git a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java index 7b05669085c..df8ba5b6161 100644 --- a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java +++ b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -32,6 +32,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build jdk.test.whitebox.WhiteBox LimitUpdateChecker * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox * @run driver TestLimitsUpdating @@ -54,10 +55,8 @@ public class TestLimitsUpdating { private static final String imageName = Common.imageName("limitsUpdating"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java index 10db6487fa2..4cf895156fe 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java @@ -59,10 +59,7 @@ public class TestMemoryAwareness { } public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java b/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java index 68331f26766..4854f663101 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java @@ -55,10 +55,7 @@ public class TestMemoryInvisibleParent { System.out.println("Cgroup not configured."); return; } - if (!DockerTestUtils.canTestDocker()) { - System.out.println("Unable to run docker tests."); - return; - } + DockerTestUtils.checkCanTestDocker(); ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java b/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java index 3340f9de03c..1edc98035e4 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2022, Tencent. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,10 +52,8 @@ public class TestMemoryWithCgroupV1 { return; } if ("cgroupv1".equals(metrics.getProvider())) { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java b/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java index 3b901765ee9..35b7bf993f7 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java @@ -52,10 +52,7 @@ public class TestMemoryWithSubgroups { System.out.println("Cgroup not configured."); return; } - if (!DockerTestUtils.canTestDocker()) { - System.out.println("Unable to run docker tests."); - return; - } + DockerTestUtils.checkCanTestDocker(); ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); diff --git a/test/hotspot/jtreg/containers/docker/TestMisc.java b/test/hotspot/jtreg/containers/docker/TestMisc.java index 400119dac9d..fca3cef5513 100644 --- a/test/hotspot/jtreg/containers/docker/TestMisc.java +++ b/test/hotspot/jtreg/containers/docker/TestMisc.java @@ -46,14 +46,10 @@ import jtreg.SkippedException; public class TestMisc { - private static final Metrics metrics = Metrics.systemMetrics(); private static final String imageName = Common.imageName("misc"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); @@ -102,14 +98,8 @@ public class TestMisc { // Test the mapping function on cgroups v2. Should also pass on cgroups v1 as it's // a direct mapping there. private static void testPrintContainerInfoCPUShares() throws Exception { - // Test won't work on cgv1 rootless podman since resource limits don't - // work there. - if ("cgroupv1".equals(metrics.getProvider()) && - DockerTestUtils.isPodman() && - DockerTestUtils.isRootless()) { - throw new SkippedException("Resource limits required for testPrintContainerInfoCPUShares(). " + - "This is cgv1 with podman in rootless mode. Test skipped."); - } + // Test won't work on cgv1 rootless since resource limits don't work there. + DockerTestUtils.checkCanUseResourceLimits(); // Anything less than 1024 should return the back-mapped cpu-shares value without // rounding to next multiple of 1024 (on cg v2). Only ensure that we get // 'cpu_shares: ' over 'cpu_shares: no shares'. diff --git a/test/hotspot/jtreg/containers/docker/TestPids.java b/test/hotspot/jtreg/containers/docker/TestPids.java index 7d5f1b0cdf9..0e39268184e 100644 --- a/test/hotspot/jtreg/containers/docker/TestPids.java +++ b/test/hotspot/jtreg/containers/docker/TestPids.java @@ -31,6 +31,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * @build jdk.test.whitebox.WhiteBox PrintContainerInfo * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox @@ -54,10 +55,8 @@ public class TestPids { static final String warning_kernel_no_pids_support = "WARNING: Your kernel does not support pids limit capabilities"; public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java b/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java index 6912499e53f..38eb07139bd 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java +++ b/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java @@ -28,6 +28,7 @@ package gc.arguments; * @bug 8006088 * @requires vm.gc.Parallel * @requires vm.compMode != "Xcomp" + * @requires !vm.opt.final.UseLargePages * @summary Test Parallel GC ergonomics decisions related to minimum and initial heap size. * @library /test/lib * @library / diff --git a/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java b/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java index 2f454940863..f65f211b812 100644 --- a/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java @@ -286,6 +286,20 @@ public class TestNewSizeFlags { if (YOUNG_GC_TYPE == GCTypes.YoungGCType.G1) { return new MemoryUsage(edenUsageInit + survivorUsageInit, 0, edenUsageCommited + survivorUsageCommited, Long.MAX_VALUE); + } else if (YOUNG_GC_TYPE == GCTypes.YoungGCType.DefNew) { + // Eden might grow to be almost the entire young generation, + // so it is approximated as the size for the entire young + // generation. + long youngGenUsageMax = edenUsage.getMax(); + + long combinedSurvivorUsageMax = 2 * survivorUsage.getMax(); + if (combinedSurvivorUsageMax > youngGenUsageMax) { + throw new RuntimeException("Unexpectedly large survivorUsage combined maximum value: " + combinedSurvivorUsageMax); + } + + return new MemoryUsage(edenUsageInit + survivorUsageInit * 2, 0, + edenUsageCommited + survivorUsageCommited * 2, + youngGenUsageMax); } else { return new MemoryUsage(edenUsageInit + survivorUsageInit * 2, 0, edenUsageCommited + survivorUsageCommited * 2, diff --git a/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java b/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java index 1590d7ac967..ed087480815 100644 --- a/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,8 @@ package gc.arguments; /* * @test TestObjectTenuringFlags * @bug 6521376 - * @requires vm.gc.Parallel + * @requires vm.gc.Parallel & vm.opt.NeverTenure == null & vm.opt.AlwaysTenure == null + * & vm.opt.MaxTenuringThreshold == null & vm.opt.InitialTenuringThreshold == null * @summary Tests argument processing for NeverTenure, AlwaysTenure, * and MaxTenuringThreshold * @library /test/lib @@ -161,7 +162,7 @@ public class TestObjectTenuringFlags { } Collections.addAll(vmOpts, "-XX:+UseParallelGC", "-XX:+PrintFlagsFinal", "-version"); - OutputAnalyzer output = GCArguments.executeLimitedTestJava(vmOpts); + OutputAnalyzer output = GCArguments.executeTestJava(vmOpts); if (shouldFail) { output.shouldHaveExitValue(1); diff --git a/test/hotspot/jtreg/runtime/CommandLine/PrintAllFlags.java b/test/hotspot/jtreg/runtime/CommandLine/PrintAllFlags.java new file mode 100644 index 00000000000..13b0dd70d4e --- /dev/null +++ b/test/hotspot/jtreg/runtime/CommandLine/PrintAllFlags.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, IBM Corporation. + * 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 8372802 + * @summary Test that +PrintFlagsFinal print the same options when +UnlockExperimentalVMOptions and + * +UnlockDiagnosticVMOptions are set than when they aren't. + * @requires vm.flagless + * @library /test/lib + * @run driver PrintAllFlags + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +import java.io.IOException; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class PrintAllFlags { + private static final Pattern optPattern = Pattern.compile("\\s*\\w+\\s\\w+\\s+="); + + public static void main(String args[]) throws Exception { + var flagsFinal = runAndMakeVMOptionSet("-XX:+PrintFlagsFinal", "-version"); + var flagsFinalUnlocked = runAndMakeVMOptionSet( + "-XX:+UnlockExperimentalVMOptions", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintFlagsFinal", "-version"); + if (!flagsFinal.equals(flagsFinalUnlocked)) { + throw new RuntimeException("+PrintFlagsFinal should produce the same output" + + " whether or not UnlockExperimentalVMOptions and UnlockDiagnosticVMOptions are set"); + } + } + + private static Set runAndMakeVMOptionSet(String... args) throws IOException { + var output = new OutputAnalyzer(ProcessTools.createLimitedTestJavaProcessBuilder(args).start()); + Set optNameSet = output.asLines().stream() + .map(optPattern::matcher) + .filter(Matcher::find) + .map(Matcher::group) + .collect(Collectors.toSet()); + if (optNameSet.isEmpty()) { + throw new RuntimeException("Sanity test failed: no match for option pattern in process output"); + } + return optNameSet; + } + +} diff --git a/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java b/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java index 28af0692721..66c256be3cc 100644 --- a/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java +++ b/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java @@ -63,10 +63,9 @@ public class CheckForProperDetailStackTrace { private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); private static final Path MODS_DIR = Paths.get(TEST_CLASSES, "mods"); - // Windows has source information only in full pdbs, not in stripped pdbs - private static boolean expectSourceInformation = Platform.isLinux() || Platform.isWindows(); - - static WhiteBox wb = WhiteBox.getWhiteBox(); + // In some configurations on Windows, we could have stripped pdbs which do not have source information. + private static boolean expectSourceInformation = (Platform.isLinux() || Platform.isWindows()) && + WhiteBox.getWhiteBox().shipsFullDebugInfo(); /* The stack trace we look for by default. Note that :: has been replaced by .* to make sure it matches even if the symbol is not unmangled. @@ -145,12 +144,8 @@ public class CheckForProperDetailStackTrace { throw new RuntimeException("Expected stack trace missing from output"); } - if (wb.hasExternalSymbolsStripped()) { - expectSourceInformation = false; - } - - System.out.println("Looking for source information:"); if (expectSourceInformation) { + System.out.println("Looking for source information:"); if (!stackTraceMatches(".*moduleEntry.cpp.*", output)) { output.reportDiagnosticSummary(); throw new RuntimeException("Expected source information missing from output"); diff --git a/test/hotspot/jtreg/runtime/Thread/AsyncExceptionOnMonitorEnter.java b/test/hotspot/jtreg/runtime/Thread/AsyncExceptionOnMonitorEnter.java index a4aa0fe3797..409313b9626 100644 --- a/test/hotspot/jtreg/runtime/Thread/AsyncExceptionOnMonitorEnter.java +++ b/test/hotspot/jtreg/runtime/Thread/AsyncExceptionOnMonitorEnter.java @@ -25,7 +25,6 @@ * @test * @bug 8283044 * @summary Stress delivery of asynchronous exceptions while target is at monitorenter - * @requires test.thread.factory == null * @library /test/hotspot/jtreg/testlibrary * @run main/othervm/native AsyncExceptionOnMonitorEnter 0 * @run main/othervm/native -agentlib:AsyncExceptionOnMonitorEnter AsyncExceptionOnMonitorEnter 1 @@ -45,9 +44,13 @@ public class AsyncExceptionOnMonitorEnter extends Thread { public static native int exitRawMonitor(); public static native void destroyRawMonitor(); + // Avoid using CountDownLatch or similar objects that require unparking the + // main thread. Otherwise, if the main thread is run as a virtual thread, the + // async exception could be sent while the target is still executing FJP logic. + public volatile boolean started = false; + public volatile boolean gotMonitor = false; + private static Object o1 = new Object(); - private static boolean firstWorker = true; - private static Semaphore sem = new Semaphore(0); @Override public void run() { @@ -60,11 +63,9 @@ public class AsyncExceptionOnMonitorEnter extends Thread { public void testWithJavaMonitor() { try { + started = true; synchronized (o1) { - if (firstWorker) { - firstWorker = false; - sem.release(); - } + gotMonitor = true; Thread.sleep(1000); } } catch (ThreadDeath td) { @@ -75,20 +76,16 @@ public class AsyncExceptionOnMonitorEnter extends Thread { public void testWithJVMTIRawMonitor() { - boolean savedFirst = false; try { + started = true; int retCode = enterRawMonitor(); - if (retCode != 0 && firstWorker) { + if (retCode != 0) { throw new RuntimeException("error in JVMTI RawMonitorEnter: retCode=" + retCode); } - if (firstWorker) { - firstWorker = false; - savedFirst = true; - sem.release(); - } - Thread.sleep(1000); + gotMonitor = true; + Thread.sleep(500); retCode = exitRawMonitor(); - if (retCode != 0 && savedFirst) { + if (retCode != 0) { throw new RuntimeException("error in JVMTI RawMonitorExit: retCode=" + retCode); } } catch (ThreadDeath td) { @@ -134,15 +131,18 @@ public class AsyncExceptionOnMonitorEnter extends Thread { AsyncExceptionOnMonitorEnter worker2 = new AsyncExceptionOnMonitorEnter(); try { - // Start firstWorker worker and wait until monitor is acquired - firstWorker = true; + // Start first worker and wait until monitor is acquired worker1.start(); - sem.acquire(); + while (!worker1.gotMonitor) { + Thread.sleep(1); + } // Start second worker and allow some time for target to block on monitorenter // before executing Thread.stop() worker2.start(); - Thread.sleep(300); + while (!worker2.started) { + Thread.sleep(10); + } while (true) { JVMTIUtils.stopThread(worker2); @@ -151,6 +151,8 @@ public class AsyncExceptionOnMonitorEnter extends Thread { // not released worker2 will deadlock on enter JVMTIUtils.stopThread(worker1); } + // Give time to throw exception + Thread.sleep(10); if (!worker1.isAlive() && !worker2.isAlive()) { // Done with Thread.stop() calls since diff --git a/test/hotspot/jtreg/runtime/Thread/AsyncExceptionTest.java b/test/hotspot/jtreg/runtime/Thread/AsyncExceptionTest.java index 52fc4ca1d56..e15022a9fed 100644 --- a/test/hotspot/jtreg/runtime/Thread/AsyncExceptionTest.java +++ b/test/hotspot/jtreg/runtime/Thread/AsyncExceptionTest.java @@ -49,9 +49,11 @@ public class AsyncExceptionTest extends Thread { private final static int DEF_TIME_MAX = 30; // default max # secs to test private final static String PROG_NAME = "AsyncExceptionTest"; - public CountDownLatch startSyncObj = new CountDownLatch(1); + // Avoid using CountDownLatch or similar objects that require unparking the + // main thread. Otherwise, if the main thread is run as a virtual thread, the + // async exception could be sent while the target is still executing FJP logic. + public volatile boolean started = false; - private boolean firstEntry = true; private boolean receivedThreadDeathinInternal1 = false; private boolean receivedThreadDeathinInternal2 = false; private volatile RuntimeException error = null; @@ -77,6 +79,7 @@ public class AsyncExceptionTest extends Thread { public void internalRun1() { try { + started = true; while (!receivedThreadDeathinInternal2) { internalRun2(); } @@ -87,16 +90,10 @@ public class AsyncExceptionTest extends Thread { public void internalRun2() { try { - Integer myLocalCount = 1; - Integer myLocalCount2 = 1; + int myLocalCount = 1; + int myLocalCount2 = 1; - if (firstEntry) { - // Tell main thread we have started. - startSyncObj.countDown(); - firstEntry = false; - } - - while(myLocalCount > 0) { + while (myLocalCount > 0) { myLocalCount2 = (myLocalCount % 3) / 2; myLocalCount -= 1; } @@ -128,7 +125,9 @@ public class AsyncExceptionTest extends Thread { thread.start(); try { // Wait for the worker thread to get going. - thread.startSyncObj.await(); + while (!thread.started) { + Thread.sleep(1); + } // Send async exception and wait until it is thrown JVMTIUtils.stopThread(thread); thread.join(); diff --git a/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java b/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java index af43c6059d5..600ef6089a6 100644 --- a/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java +++ b/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ public class HandshakeDirectTest implements Runnable { static Object[] locks = new Object[WORKING_THREADS]; static AtomicInteger handshakeCount = new AtomicInteger(0); - static void suspendThread(Thread t) { + static boolean suspendThread(Thread t) { try { JVMTIUtils.suspendThread(t); } catch (JVMTIUtils.JvmtiException e) { @@ -56,7 +56,9 @@ public class HandshakeDirectTest implements Runnable { && e.getCode() != JVMTIUtils.JVMTI_ERROR_WRONG_PHASE) { throw e; } + return false; // failed to suspend } + return true; // suspended } static void resumeThread(Thread t) { @@ -115,7 +117,10 @@ public class HandshakeDirectTest implements Runnable { public void run() { while (true) { int i = ThreadLocalRandom.current().nextInt(0, WORKING_THREADS - 1); - suspendThread(workingThreads[i]); + boolean suspended = suspendThread(workingThreads[i]); + if (!suspended) { + continue; // skip resumeThread call if thread was not suspended + } try { Thread.sleep(1); // sleep for 1 ms } catch(InterruptedException ie) { diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/SamplingDuringInit.java b/test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/SamplingDuringInit.java new file mode 100644 index 00000000000..1dc885180c1 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/SamplingDuringInit.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8372039 + * @summary The test verifies that object allocation sampling is disabled during AOT. + * + * Don't remove 'modules' line, it triggers the crash. + * @modules java.management + * + * @run main/othervm/native -agentlib:SamplingDuringInit SamplingDuringInit + * @run main/othervm/native -agentlib:SamplingDuringInit -XX:-UseCompressedOops SamplingDuringInit + */ + +public class SamplingDuringInit { + + public static Object[] tmp = new Object[1000]; + public static void main(String[] args) throws Exception { + // Allocate some objects to trigger Sampling even if + // all JDK classes are preloaded. + for (int i = 0; i < tmp.length; i++) { + tmp[i] = new String("tmp" + i); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/libSamplingDuringInit.cpp b/test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/libSamplingDuringInit.cpp new file mode 100644 index 00000000000..709012dfb57 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/events/SampledObjectAlloc/SamplingDuringInit/libSamplingDuringInit.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvmti.h" +#include "jvmti_common.hpp" + +#include + +extern "C" { + +// SampledObjectAlloc event might be triggered on any thread +static std::atomic events_counter(0); + +JNIEXPORT void JNICALL +SampledObjectAlloc(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread, jobject object, jclass object_klass, jlong size) { + events_counter++; + LOG("Sampled object, events_counter = %d\n", events_counter.load()); +} + +void JNICALL +VMDeath(jvmtiEnv *jvmti, JNIEnv* jni) { + if (events_counter == 0) { + fatal(jni, "SampledObjectAlloc events counter shouldn't be zero"); + } +} + +jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { + jvmtiEnv* jvmti = nullptr; + jvmtiCapabilities caps; + jvmtiEventCallbacks callbacks; + jvmtiError err; + jint res; + + LOG("AGENT INIT"); + res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_9); + if (res != JNI_OK || jvmti == nullptr) { + LOG("Wrong result of a valid call to GetEnv!\n"); + return JNI_ERR; + } + + memset(&caps, 0, sizeof(caps)); + caps.can_generate_sampled_object_alloc_events = 1; + if (jvmti->AddCapabilities(&caps) != JVMTI_ERROR_NONE) { + return JNI_ERR; + } + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.SampledObjectAlloc = &SampledObjectAlloc; + callbacks.VMDeath = &VMDeath; + + err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); + check_jvmti_error(err, "SetEventCallbacks"); + /* + * Interval should be small enough to triggger sampling event while objects are init by VM. + */ + err = jvmti->SetHeapSamplingInterval(10); + check_jvmti_error(err, "SetHeapSamplingInterval"); + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, nullptr); + check_jvmti_error(err, "SetEventNotificationMode"); + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, nullptr); + check_jvmti_error(err, "SetEventNotificationMode"); + + 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); +} +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java index a684c03e67a..5fbb4d2444e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java @@ -92,7 +92,8 @@ public class isexceeded001 { // but cannot assume this affects the pool we are testing. b = new byte[INCREMENT]; - isExceeded = monitor.isUsageThresholdExceeded(pool); + // Ensure the observation of isExceeded is sticky to match peakUsage. + isExceeded = isExceeded || monitor.isUsageThresholdExceeded(pool); log.display(" Allocated heap. isExceeded = " + isExceeded); // Fetch usage information: use peak usage in comparisons below, in case usage went up and then down. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryUsage/from/from001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryUsage/from/from001/TestDescription.java index a066b636bb3..083e91243e8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryUsage/from/from001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryUsage/from/from001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ * 5014783 Move ThreadState class from java.lang.management to java.lang * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.MemoryUsage.from.from001 -testMode=server diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/from_c/from_c001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/from_c/from_c001/TestDescription.java index 9ff6e066fe1..6483673deef 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/from_c/from_c001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/from_c/from_c001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ * 5014783 Move ThreadState class from java.lang.management to java.lang * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.ThreadInfo.from_c.from_c001 -testMode=server -MBeanServer=custom diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockName/getlockname001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockName/getlockname001/TestDescription.java index 571f121beac..8e956e98929 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockName/getlockname001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockName/getlockname001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ * Updated according to: * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.ThreadInfo.getLockName.getlockname001 diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockOwnerName/getlockownername001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockOwnerName/getlockownername001/TestDescription.java index 1b2e7d90eb2..0cc78a6ad97 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockOwnerName/getlockownername001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockOwnerName/getlockownername001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ * Updated according to: * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.ThreadInfo.getLockOwnerName.getlockownername001 diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isInNative/isinnative001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isInNative/isinnative001/TestDescription.java index a411958c852..3cce37baa4d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isInNative/isinnative001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isInNative/isinnative001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ * Updated according to: * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.ThreadInfo.isInNative.isinnative001 diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadAllocatedBytes/BaseBehaviorTest.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadAllocatedBytes/BaseBehaviorTest.java index bc0af5ae1cd..c338d392416 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadAllocatedBytes/BaseBehaviorTest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadAllocatedBytes/BaseBehaviorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,16 +59,30 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { + "return -1 if ThreadAllocatedMemoryEnabled is set to false. " + "Received : " + result); threadMXBean.setThreadAllocatedMemoryEnabled(true); - // Expect >= 0 value for current thread + // Expect >= 0 value for current platform thread. result = threadMXBean.getCurrentThreadAllocatedBytes(); - if (result < 0) - throw new TestFailure("Failure! getCurrentThreadAllocatedBytes() should " - + "return >= 0 value for current thread. Received : " + result); - // Expect >= 0 value for current thread from getThreadAllocatedBytes(id) + if (Thread.currentThread().isVirtual()) { + if (result != -1) + throw new TestFailure("Failure! getCurrentThreadAllocatedBytes() should " + + "return -1 for virtual thread. " + + "Received : " + result); + } else { + if (result < 0) + throw new TestFailure("Failure! getCurrentThreadAllocatedBytes() should " + + "return >= 0 value for current thread. Received : " + result); + } + // Expect >= 0 value for current iplatform thread from getThreadAllocatedBytes(id). result = threadMXBean.getThreadAllocatedBytes(Thread.currentThread().getId()); - if (result < 0) - throw new TestFailure("Failure! getThreadAllocatedBytes(id) should " - + "return >= 0 value for current thread. Received : " + result); + if (Thread.currentThread().isVirtual()) { + if (result != -1) + throw new TestFailure("Failure! getThreadAllocatedBytes(id) should " + + "return -1 for virtual thread. " + + "Received : " + result); + } else { + if (result < 0) + throw new TestFailure("Failure! getThreadAllocatedBytes(id) should " + + "return >= 0 value for current thread. Received : " + result); + } MXBeanTestThread thread = new MXBeanTestThread(); long id = thread.getId(); @@ -79,11 +93,11 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { result = threadMXBean.getThreadAllocatedBytes(id); if (result != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " - + "return -1 for not started threads. Recieved : " + result); + + "return -1 for not started threads. Received : " + result); resultArr = threadMXBean.getThreadAllocatedBytes(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " - + "return -1 for not started threads. Recieved : " + resultArr[0]); + + "return -1 for not started threads. Received : " + resultArr[0]); BarrierHandler handler = startThreads(thread); try { handler.proceed(); @@ -93,23 +107,37 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { if (result != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " + "return -1 if ThreadAllocatedMemoryEnabled is set to false. " - + "Recieved : " + result); + + "Received : " + result); resultArr = threadMXBean.getThreadAllocatedBytes(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " + "return -1 if ThreadAllocatedMemoryEnabled is set to false. " - + "Recieved : " + resultArr[0]); + + "Received : " + resultArr[0]); threadMXBean.setThreadAllocatedMemoryEnabled(true); // Expect >= 0 value for running threads result = threadMXBean.getThreadAllocatedBytes(id); - if (result < 0) - throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " - + "return > 0 value for RUNNING thread. Recieved : " + result); + if (thread.isVirtual()) { + if (result != -1) + throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " + + "return -1 for virtual thread. " + + "Received : " + result); + } else { + if (result < 0) + throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " + + "return > 0 value for RUNNING thread. Received : " + result); + } resultArr = threadMXBean.getThreadAllocatedBytes(idArr); - if (resultArr[0] < 0) - throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " - + "return > 0 value for RUNNING thread. Recieved : " + resultArr[0]); + if (thread.isVirtual()) { + if (resultArr[0] != -1) + throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " + + "return -1 for virtual thread. " + + "Received : " + resultArr[0]); + } else { + if (resultArr[0] < 0) + throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " + + "return > 0 value for RUNNING thread. Received : " + resultArr[0]); + } } finally { // Let thread finish handler.finish(); @@ -121,11 +149,11 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { result = threadMXBean.getThreadAllocatedBytes(id); if (result != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " - + "return -1 for finished threads. Recieved : " + result); + + "return -1 for finished threads. Received : " + result); resultArr = threadMXBean.getThreadAllocatedBytes(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " - + "return -1 for finished threads. Recieved : " + resultArr[0]); + + "return -1 for finished threads. Received : " + resultArr[0]); log.info("BaseBehaviorTest passed."); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadCpuTime/BaseBehaviorTest.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadCpuTime/BaseBehaviorTest.java index 5a16a1ba815..d639ba8b825 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadCpuTime/BaseBehaviorTest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadCpuTime/BaseBehaviorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,11 +57,11 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { resultArr = threadMXBean.getThreadCpuTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " - + "return -1 for not started threads. Recieved : " + resultArr[0]); + + "return -1 for not started threads. Received : " + resultArr[0]); resultArr = threadMXBean.getThreadUserTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " - + "return -1 for not started threads. Recieved : " + resultArr[0]); + + "return -1 for not started threads. Received : " + resultArr[0]); BarrierHandler handler = startThreads(thread); try { handler.proceed(); @@ -71,22 +71,36 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " + "return -1 if threadCpuTimeEnabled is set to false. " - + "Recieved : " + resultArr[0]); + + "Received : " + resultArr[0]); resultArr = threadMXBean.getThreadUserTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " + "return -1 if threadCpuTimeEnabled is set to false. " - + "Recieved : " + resultArr[0]); + + "Received : " + resultArr[0]); threadMXBean.setThreadCpuTimeEnabled(true); - // Expect > 0 value for running threads + // Expect > 0 value for running platform threads and -1 for virtual threads. resultArr = threadMXBean.getThreadCpuTime(idArr); - if (resultArr[0] < 0) - throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " - + "return > 0 value for RUNNING thread. Recieved : " + resultArr[0]); + if (thread.isVirtual()) { + if (resultArr[0] != -1) + throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " + + "return -1 for virtual threads." + + "Received : " + resultArr[0]); + } else { + if (resultArr[0] < 0) + throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " + + "return > 0 value for RUNNING thread. Received : " + resultArr[0]); + } resultArr = threadMXBean.getThreadUserTime(idArr); - if (resultArr[0] < 0) - throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " - + "return > 0 value for RUNNING thread. Recieved : " + resultArr[0]); + if (thread.isVirtual()) { + if (resultArr[0] != -1) + throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " + + "return -1 for virtual threads." + + "Received : " + resultArr[0]); + } else { + if (resultArr[0] < 0) + throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " + + "return > 0 value for RUNNING thread. Received : " + resultArr[0]); + } } finally { // Let thread finish handler.finish(); @@ -98,11 +112,11 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { resultArr = threadMXBean.getThreadCpuTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " - + "return -1 for finished threads. Recieved : " + resultArr[0]); + + "return -1 for finished threads. Received : " + resultArr[0]); resultArr = threadMXBean.getThreadUserTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " - + "return -1 for finished threads. Recieved : " + resultArr[0]); + + "return -1 for finished threads. Received : " + resultArr[0]); log.info("BaseBehaviorTest passed."); } diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java index 29980ac2117..2b3f5a479b6 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import jdk.test.lib.thread.TestThreadFactory; import nsk.share.jdi.Binder; import nsk.share.jdi.Debugee; import vm.mlvm.share.Env; @@ -437,10 +438,22 @@ public abstract class JDIBreakpointTest extends MlvmTest { for (StackFrame f : frames) { Location l = f.location(); + String sourcePath; + try { + sourcePath = l.sourcePath(); + } catch (AbsentInformationException aie) { + // Test Thread Factory support has generated methods in MainWrapper class. + if (TestThreadFactory.isTestThreadFactorySet()) { + sourcePath = "unknown"; + } else { + throw aie; + } + } + buf.append(String.format("#%-4d", frameNum)) .append(l.method()) .append("\n source: ") - .append(l.sourcePath()) + .append(sourcePath) .append(":") .append(l.lineNumber()) .append("; bci=") diff --git a/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/StressTest.java b/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/StressTest.java index e8fe73cb48b..4106f12587b 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/StressTest.java +++ b/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/StressTest.java @@ -44,6 +44,7 @@ import java.util.Arrays; import java.util.List; import java.util.Random; +import jdk.test.lib.thread.TestThreadFactory; import nsk.share.TestFailure; import nsk.share.test.StressOptions; import nsk.share.test.Stresser; @@ -82,16 +83,18 @@ public class StressTest implements Runnable { @Option(name="ignoreTestFailures", default_value="false", description="ignore failures of the executed tests") private boolean ignoreTestFailures; - class Worker extends Thread { + class Worker implements Runnable { private final Random rand; private volatile DefMethTest failedTest; private Throwable reason; private volatile long executedTests = 0; - public Worker(String id, long seed) { - setName(id); - this.rand = new Random(seed); + private final Thread thread; + + Worker(String id, long seed) { + this.rand = new Random(seed); + this.thread = TestThreadFactory.newThread(this, id); } @Override @@ -247,13 +250,13 @@ public class StressTest implements Runnable { } for (Worker worker : workers) { - worker.start(); + worker.thread.start(); } } private void interruptWorkers() { for (Worker worker : workers) { - worker.interrupt(); + worker.thread.interrupt(); } } @@ -261,14 +264,14 @@ public class StressTest implements Runnable { boolean isFailed = false; for (Worker worker : workers) { - while (worker.isAlive()) { + while (worker.thread.isAlive()) { try { - worker.join(); + worker.thread.join(); } catch (InterruptedException e) {} } System.out.printf("%s: %s (executed: %d)\n", - worker.getName(), + worker.thread.getName(), worker.isFailed() ? "FAILED: " + worker.getFailedTest() : "PASSED", worker.getExecutedTests()); @@ -288,7 +291,7 @@ public class StressTest implements Runnable { private boolean workersAlive() { for (Worker worker : workers) { - if (!worker.isAlive()) { + if (!worker.thread.isAlive()) { return false; } } diff --git a/test/jdk/ProblemList-jvmti-stress-agent.txt b/test/jdk/ProblemList-jvmti-stress-agent.txt index 4a6e80a9402..09be19c3d94 100644 --- a/test/jdk/ProblemList-jvmti-stress-agent.txt +++ b/test/jdk/ProblemList-jvmti-stress-agent.txt @@ -21,22 +21,6 @@ # questions. # -############################################################################# -# -# List of quarantined tests failing with jvmti stress agent in any mode. -# -############################################################################# - - -sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/MultiNSTClient.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java 8362658 generic-all -sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java 8362658 generic-all - - # List of tests incompatible with jvmti stress agent or requiring more investigation com/sun/jdi/EATests.java#id0 0000000 generic-all diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 9904bd88626..0076b1cf891 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -500,6 +500,7 @@ java/awt/GraphicsDevice/DisplayModes/UnknownRefrshRateTest.java 8286436 macosx-a java/awt/image/multiresolution/MultiresolutionIconTest.java 8291979 linux-x64,windows-all java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java 8305061 macosx-x64 sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java 8301177 linux-x64 +sun/awt/image/bug8038000.java 8373065 generic-all # Several tests which fail on some hidpi systems/macosx12-aarch64 system java/awt/Window/8159168/SetShapeTest.java 8274106 macosx-aarch64 @@ -750,6 +751,7 @@ jdk/jfr/event/compiler/TestCodeSweeper.java 8338127 generic- jdk/jfr/event/oldobject/TestEmergencyDumpAtOOM.java 8371014 aix-ppc64,linux-ppc64le jdk/jfr/event/oldobject/TestShenandoah.java 8342951 generic-all jdk/jfr/event/runtime/TestResidentSetSizeEvent.java 8309846 aix-ppc64 +jdk/jfr/jvm/TestWaste.java 8371630 generic-all ############################################################################ @@ -815,3 +817,4 @@ java/awt/Cursor/CursorDragTest/ListDragCursor.java 7177297 macosx-all # jdk_since_checks tools/sincechecker/modules/jdk.management.jfr/JdkManagementJfrCheckSince.java 8354921 generic-all +tools/sincechecker/modules/java.base/JavaBaseCheckSince.java 8372801 generic-all diff --git a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWhenParking.java b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWhenParking.java new file mode 100644 index 00000000000..bd7dc014460 --- /dev/null +++ b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWhenParking.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=transitions + * @bug 8364343 + * @summary HotSpotDiagnosticMXBean.dumpThreads while virtual threads are parking and unparking + * @requires vm.continuations + * @modules jdk.management + * @library /test/lib + * @run main/othervm/timeout=200 DumpThreadsWhenParking 1000 1 100 + */ + +/* + * @test id=concurrent + * @summary HotSpotDiagnosticMXBean.dumpThreads from concurrent threads while virtual threads + * are parking and unparking + * @requires vm.continuations + * @modules jdk.management + * @library /test/lib + * @run main/othervm/timeout=200 DumpThreadsWhenParking 100 4 100 + */ + +/* + * @test id=concurrent_gcstress + * @summary HotSpotDiagnosticMXBean.dumpThreads from concurrent threads while virtual threads + * are parking and unparking + * @requires vm.debug == true & vm.continuations + * @modules jdk.management + * @library /test/lib + * @run main/othervm/timeout=200 -XX:+UnlockDiagnosticVMOptions -XX:+FullGCALot -XX:FullGCALotInterval=10000 DumpThreadsWhenParking 100 4 100 + */ + +import java.lang.management.ManagementFactory; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.LockSupport; +import java.util.stream.IntStream; +import com.sun.management.HotSpotDiagnosticMXBean; +import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.threaddump.ThreadDump; + +public class DumpThreadsWhenParking { + + public static void main(String... args) throws Throwable { + int vthreadCount = Integer.parseInt(args[0]); + int concurrentDumpers = Integer.parseInt(args[1]); + int iterations = Integer.parseInt(args[2]); + + // need >=2 carriers to make progress + VThreadRunner.ensureParallelism(2); + + try (var executor = Executors.newVirtualThreadPerTaskExecutor(); + var pool = Executors.newCachedThreadPool()) { + + // start virtual threads that park and unpark + var done = new AtomicBoolean(); + var phaser = new Phaser(vthreadCount + 1); + for (int i = 0; i < vthreadCount; i++) { + executor.submit(() -> { + phaser.arriveAndAwaitAdvance(); + while (!done.get()) { + LockSupport.parkNanos(1); + } + }); + } + // wait for all virtual threads to start so all have a non-empty stack + System.out.format("Waiting for %d virtual threads to start ...%n", vthreadCount); + phaser.arriveAndAwaitAdvance(); + System.out.format("%d virtual threads started.%n", vthreadCount); + + // Bash on HotSpotDiagnosticMXBean.dumpThreads from >= 1 threads + try { + String containerName = Objects.toIdentityString(executor); + for (int i = 1; i <= iterations; i++) { + System.out.format("%s %d of %d ...%n", Instant.now(), i, iterations); + List> futures = IntStream.of(0, concurrentDumpers) + .mapToObj(_ -> pool.submit(() -> dumpThreads(containerName, vthreadCount))) + .toList(); + for (Future future : futures) { + future.get(); + } + } + } finally { + done.set(true); + } + } + } + + /** + * Invoke HotSpotDiagnosticMXBean.dumpThreads to generate a thread dump to a file in + * JSON format. Parse the thread dump to ensure it contains a thread grouping with + * the expected number of virtual threads. + */ + static Void dumpThreads(String containerName, int expectedVThreadCount) throws Exception { + long tid = Thread.currentThread().threadId(); + Path file = Path.of("threads-" + tid + ".json").toAbsolutePath(); + Files.deleteIfExists(file); + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) + .dumpThreads(file.toString(), HotSpotDiagnosticMXBean.ThreadDumpFormat.JSON); + + // read and parse the dump + String jsonText = Files.readString(file); + ThreadDump threadDump = ThreadDump.parse(jsonText); + var container = threadDump.findThreadContainer(containerName).orElse(null); + if (container == null) { + fail(containerName + " not found in thread dump"); + } + + // check expected virtual thread count + long threadCount = container.threads().count(); + if (threadCount != expectedVThreadCount) { + fail(threadCount + " virtual threads found, expected " + expectedVThreadCount); + } + + // check each thread is a virtual thread with stack frames + container.threads().forEach(t -> { + if (!t.isVirtual()) { + fail("#" + t.tid() + "(" + t.name() + ") is not a virtual thread"); + } + long stackFrameCount = t.stack().count(); + if (stackFrameCount == 0) { + fail("#" + t.tid() + " has empty stack"); + } + }); + return null; + } + + private static void fail(String message) { + throw new RuntimeException(message); + } +} diff --git a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java index 4cbd0de460c..787d53ae045 100644 --- a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java +++ b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java @@ -43,6 +43,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -73,9 +74,11 @@ public class DumpThreadsWithEliminatedLock { // A thread that spins creating and adding to a StringBuffer. StringBuffer is // synchronized, assume object will be scalar replaced and the lock eliminated. + var started = new CountDownLatch(1); var done = new AtomicBoolean(); var ref = new AtomicReference(); Thread thread = factory.newThread(() -> { + started.countDown(); while (!done.get()) { StringBuffer sb = new StringBuffer(); sb.append(System.currentTimeMillis()); @@ -85,6 +88,7 @@ public class DumpThreadsWithEliminatedLock { }); try { thread.start(); + started.await(); if (plain) { testPlainFormat(); } else { diff --git a/test/jdk/java/awt/image/AffineTransformOp/AffineTxOpSizeTest.java b/test/jdk/java/awt/image/AffineTransformOp/AffineTxOpSizeTest.java new file mode 100644 index 00000000000..86f0c1030d6 --- /dev/null +++ b/test/jdk/java/awt/image/AffineTransformOp/AffineTxOpSizeTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 4690476 + * @summary Verify behaviour with transform which creates too large an image. + */ + +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import static java.awt.image.AffineTransformOp.*; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.awt.image.RasterFormatException; + +public class AffineTxOpSizeTest { + + static final int W = 2552, H = 3300; + // This transform will require an approx 60_000 x 60_000 raster which is too large + static final AffineTransform AT = new AffineTransform(0.2, 23, 18, 0.24, -70.0, -90.0); + + public static void main(String[] args) { + BufferedImage src = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); + testAOP(src, TYPE_BICUBIC); + testAOP(src, TYPE_BILINEAR); + testAOP(src, TYPE_NEAREST_NEIGHBOR); + } + + static void testAOP(BufferedImage src, int iType) { + AffineTransformOp aop = new AffineTransformOp(AT, iType); + System.out.println("Bounds=" + aop.getBounds2D(src)); + + aop.filter(src, null); + aop.filter(src.getRaster(), null); + try { + aop.createCompatibleDestImage(src, src.getColorModel()); + throw new RuntimeException("No exception for image"); + } catch (RasterFormatException e) { + } + try { + aop.createCompatibleDestRaster(src.getRaster()); + throw new RuntimeException("No exception for raster"); + } catch (RasterFormatException e) { + } + } + +} diff --git a/test/jdk/java/awt/image/ConvolveOp/KernelInitialisationTest.java b/test/jdk/java/awt/image/ConvolveOp/KernelInitialisationTest.java index 607f0a7a8dc..0d58472385c 100644 --- a/test/jdk/java/awt/image/ConvolveOp/KernelInitialisationTest.java +++ b/test/jdk/java/awt/image/ConvolveOp/KernelInitialisationTest.java @@ -25,36 +25,49 @@ * @test * @bug 8368729 * @summary Tests that passing invalid values to Kernel constructor - * throws only IllegalArgumentException + * throws only IllegalArgumentException or NullPointerException */ import java.awt.image.Kernel; public class KernelInitialisationTest { - private static void expectIllegalArgumentException(Runnable code) { + + private static void test(int width, int height, float[] data, + Class expected) + { + System.out.printf("Testing for width: %d, height: %d, data: %s%n", + width, height, data == null ? "null" : "not null"); + Class actual = null; try { - code.run(); - throw new RuntimeException("Expected IllegalArgumentException" + - " but no exception was thrown"); - } catch (IllegalArgumentException e) { - // we expect IllegalArgumentException + new Kernel(width, height, data); + } catch (Exception e) { + actual = e.getClass(); + } + if (actual != expected) { + System.err.println("Expected: " + expected); + System.err.println("Actual: " + actual); + throw new RuntimeException("Test failed"); } } - private static void testKernel(int width, int height, float[] data) { - System.out.println("Testing for width: " + width + ", height: " - + height + ", data: " + (data == null ? "null" : "not null")); - expectIllegalArgumentException(() -> new Kernel(width, height, data)); + private static void testIAE(int width, int height, int len) { + test(width, height, new float[len], IllegalArgumentException.class); + } + + private static void testNPE(int width, int height) { + test(width, height, null, NullPointerException.class); } public static void main(String[] args) { - testKernel(-1, 1, new float[100]); - testKernel(1, -1, new float[100]); - testKernel(-1, -1, new float[100]); - testKernel(1, 1, null); - - int width = 50; - int height = Integer.MAX_VALUE; - testKernel(width, height, new float[100]); + int[][] sizes = {{-1, 1}, {1, -1}, {-1, -1}, {50, Integer.MAX_VALUE}}; + int[] lens = {1, 100}; + for (int[] kernelSize : sizes) { + for (int len : lens) { + testIAE(kernelSize[0], kernelSize[1], len); + } + testNPE(kernelSize[0], kernelSize[1]); + } + testNPE(10, 10); // NPE on valid width and height + testIAE(10, 10, 10); // IAE on valid width and height but small data } } diff --git a/test/jdk/java/awt/image/SampleModelGetSamplesAndPixelsTest.java b/test/jdk/java/awt/image/SampleModelGetSamplesAndPixelsTest.java new file mode 100644 index 00000000000..483bbe43d9e --- /dev/null +++ b/test/jdk/java/awt/image/SampleModelGetSamplesAndPixelsTest.java @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6185110 + * @summary Verify get/set/Pixels/Samples APIs for bad parameters. + * + * @run main SampleModelGetSamplesAndPixelsTest + */ + +import java.awt.image.BandedSampleModel; +import java.awt.image.ComponentSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.PixelInterleavedSampleModel; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.util.Vector; + +public class SampleModelGetSamplesAndPixelsTest { + + static final int WIDTH = 100; + static final int HEIGHT = 100; + static final int DATATYPE = DataBuffer.TYPE_BYTE; + static final int NUMBANDS = 4; + static final int[] INTS = new int[WIDTH * HEIGHT + NUMBANDS]; + static final float[] FLOATS = new float[WIDTH * HEIGHT + NUMBANDS]; + static final double[] DOUBLES = new double[WIDTH * HEIGHT + NUMBANDS]; + static final int[][] COORDS = { + { 1, 1, 1, 1, -1 }, // bad band + { 1, 1, 1, 1, NUMBANDS }, // bad band + { 1, 1, -1, 1, 0 }, // negative w + { 1, 1, -1, -1, 0 }, // negative w and h + { -4, 1, 1, 1, 0 }, // negative x + { -4, -4, 1, 1, 0 }, // negative x and y + { WIDTH+10, 0, 1, 1, 0 }, // x > width + { 0, HEIGHT+10, 1, 1, 0 }, // y > height + { WIDTH+10, HEIGHT+10, 1, 1, 0 }, // both x > width and y > height + }; + + public static void main(String[] args) { + Vector> classes = new Vector>(); + + classes.add(ComponentSampleModel.class); + classes.add(MultiPixelPackedSampleModel.class); + classes.add(SinglePixelPackedSampleModel.class); + classes.add(BandedSampleModel.class); + classes.add(PixelInterleavedSampleModel.class); + + for (Class c : classes) { + doTest(c); + } + } + + static void noException(SampleModel sm) { + System.err.println(sm); + throw new RuntimeException("No expected exception"); + } + + private static void doTest(Class c) { + System.out.println("Test for: " + c.getName()); + SampleModel sm = createSampleModel(c); + doTestNull(sm); + for (int i = 0; i < COORDS.length; i++) { + int x = COORDS[i][0]; + int y = COORDS[i][1]; + int w = COORDS[i][2]; + int h = COORDS[i][3]; + int b = COORDS[i][4]; + doTest(sm, x, y, w, h, b); + } + } + + private static void doTestNull(SampleModel sm) { + doTestNull(sm, INTS); + doTestNull(sm, FLOATS); + doTestNull(sm, DOUBLES); + } + + private static void doTestNull(SampleModel sm, int[] INTS) { + try { + sm.getSamples(1, 1, 1, 1, 0, INTS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.getSamples(1, 1, 1, 1, 0, INTS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.getPixels(1, 1, 1, 1, INTS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setPixels(1, 1, 1, 1, INTS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + } + + private static void doTestNull(SampleModel sm, float[] FLOATS) { + try { + sm.getSamples(1, 1, 1, 1, 0, FLOATS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.getSamples(1, 1, 1, 1, 0, FLOATS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.getPixels(1, 1, 1, 1, FLOATS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setPixels(1, 1, 1, 1, FLOATS, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + } + + private static void doTestNull(SampleModel sm, double[] DOUBLES) { + try { + sm.getSamples(1, 1, 1, 1, 0, DOUBLES, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.getSamples(1, 1, 1, 1, 0, DOUBLES, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.getPixels(1, 1, 1, 1, DOUBLES, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setPixels(1, 1, 1, 1, DOUBLES, null); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + } + + private static void doTest(SampleModel sm, int x, int y, int w, int h, int b) { + doTest(sm, x, y, w, h, b, INTS); + doTest(sm, x, y, w, h, b, FLOATS); + doTest(sm, x, y, w, h, b, DOUBLES); + } + + private static void doTest(SampleModel sm, int x, int y, int w, int h, int b, int[] INTS) { + + // Now test each API with a non-null buffer and the specified values. + DataBuffer db = sm.createDataBuffer(); + + try { + sm.getSamples(x, y, w, h, b, INTS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setSamples(x, y, w, h, b, INTS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + if (b < 0 || b >= NUMBANDS) { + return; // Values were to test illegal bands, skip the rest. + } + + try { + sm.getPixels(x, y, w, h, INTS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setPixels(x, y, w, h, INTS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + } + + private static void doTest(SampleModel sm, int x, int y, int w, int h, int b, float[] FLOATS) { + + // Now test each API with a non-null buffer and the specified values. + DataBuffer db = sm.createDataBuffer(); + + try { + sm.getSamples(x, y, w, h, b, FLOATS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setSamples(x, y, w, h, b, FLOATS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + if (b < 0 || b >= NUMBANDS) { + return; // Values were to test illegal bands, skip the rest. + } + + try { + sm.getPixels(x, y, w, h, FLOATS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setPixels(x, y, w, h, FLOATS, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + } + + private static void doTest(SampleModel sm, int x, int y, int w, int h, int b, double[] DOUBLES) { + + // Now test each API with a non-null buffer and the specified values. + DataBuffer db = sm.createDataBuffer(); + + try { + sm.getSamples(x, y, w, h, b, DOUBLES, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setSamples(x, y, w, h, b, DOUBLES, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + if (b < 0 || b >= NUMBANDS) { + return; // Values were to test illegal bands, skip the rest. + } + + try { + sm.getPixels(x, y, w, h, DOUBLES, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setPixels(x, y, w, h, DOUBLES, db); + noException(sm); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e.getMessage()); + } + + try { + sm.setDataElements(0, 0, null, db); + noException(sm); + } catch (NullPointerException e) { + System.out.println(e.getMessage()); + } + } + + private static SampleModel createSampleModel(Class cls) { + SampleModel res = null; + + if (cls == ComponentSampleModel.class) { + res = new ComponentSampleModel(DATATYPE, WIDTH, HEIGHT, 4, WIDTH * 4, new int[] { 0, 1, 2, 3 } ); + } else if (cls == MultiPixelPackedSampleModel.class) { + res = new MultiPixelPackedSampleModel(DATATYPE, WIDTH, HEIGHT, 4); + } else if (cls == SinglePixelPackedSampleModel.class) { + res = new SinglePixelPackedSampleModel(DATATYPE, WIDTH, HEIGHT, + new int[]{ 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff }); + } else if (cls == BandedSampleModel.class) { + res = new BandedSampleModel(DATATYPE, WIDTH, HEIGHT, NUMBANDS); + } else if (cls == PixelInterleavedSampleModel.class) { + res = new PixelInterleavedSampleModel(DATATYPE, WIDTH, HEIGHT, 4, WIDTH * 4, new int[] { 0, 1, 2, 3 }); + } else { + throw new RuntimeException("Unknown class " + cls); + } + return res; + } +} diff --git a/test/jdk/java/foreign/TestSegments.java b/test/jdk/java/foreign/TestSegments.java index 2942b388d50..e9f3e8a87cc 100644 --- a/test/jdk/java/foreign/TestSegments.java +++ b/test/jdk/java/foreign/TestSegments.java @@ -212,14 +212,32 @@ public class TestSegments { } @Test - public void testSegmentOOBMessage() { + public void testSegmentAccessOOBMessage() { try { var segment = Arena.global().allocate(10, 1); segment.getAtIndex(ValueLayout.JAVA_INT, 2); + fail("Expected IndexOutOfBoundsException was not thrown"); } catch (IndexOutOfBoundsException ex) { - assertTrue(ex.getMessage().contains("Out of bound access")); - assertTrue(ex.getMessage().contains("offset = 8")); - assertTrue(ex.getMessage().contains("length = 4")); + assertTrue(ex.getMessage().startsWith("Out of bound access")); + assertTrue(ex.getMessage().endsWith("attempting to access an element of length 4 at offset 8 " + + "which is outside the valid range 0 <= offset+length < byteSize (=10)")); + } catch (Exception ex) { + fail("Unexpected exception type thrown: " + ex); + } + } + + @Test + public void testSegmentSliceOOBMessage() { + try { + var segment = Arena.global().allocate(10, 1); + var slice = segment.asSlice(8, 4); + fail("Expected IndexOutOfBoundsException was not thrown"); + } catch (IndexOutOfBoundsException ex) { + assertTrue(ex.getMessage().startsWith("Out of bound access")); + assertTrue(ex.getMessage().endsWith("attempting to get slice of length 4 at offset 8 " + + "which is outside the valid range 0 <= offset+length < byteSize (=10)")); + } catch (Exception ex) { + fail("Unexpected exception type thrown: " + ex); } } diff --git a/test/jdk/java/io/File/GetXSpace.java b/test/jdk/java/io/File/GetXSpace.java index e61880edb2c..96ce4ede1b2 100644 --- a/test/jdk/java/io/File/GetXSpace.java +++ b/test/jdk/java/io/File/GetXSpace.java @@ -106,7 +106,7 @@ public class GetXSpace { Space(String name) { this.name = name; long[] sizes = new long[4]; - if (Platform.isWindows() & isCDDrive(name)) { + if (Platform.isWindows() && isCDDrive(name)) { try { getCDDriveSpace(name, sizes); } catch (IOException e) { @@ -114,7 +114,7 @@ public class GetXSpace { throw new RuntimeException("can't get CDDrive sizes"); } } else { - if (getSpace0(name, sizes)) + if (getSpace(name, sizes)) System.err.println("WARNING: total space is estimated"); } this.size = sizes[0]; @@ -184,7 +184,7 @@ public class GetXSpace { out.format("%s (%d):%n", s.name(), s.size()); String fmt = " %-4s total = %12d free = %12d usable = %12d%n"; - String method = Platform.isWindows() & isCDDrive(s.name()) ? "getCDDriveSpace" : "getSpace0"; + String method = Platform.isWindows() && isCDDrive(s.name()) ? "getCDDriveSpace" : "getSpace"; out.format(fmt, method, s.total(), s.free(), s.available()); out.format(fmt, "getXSpace", ts, fs, us); @@ -336,7 +336,7 @@ public class GetXSpace { private static int testVolumes() { out.println("--- Testing volumes"); // Find all of the partitions on the machine and verify that the sizes - // returned by File::getXSpace are equivalent to those from getSpace0 or getCDDriveSpace + // returned by File::getXSpace are equivalent to those from getSpace or getCDDriveSpace ArrayList l; try { l = paths(); @@ -412,6 +412,19 @@ public class GetXSpace { private static native boolean isCDDrive(String root); + private static boolean getSpace(String root, long[] space) { + try { + return getSpace0(root, space); + } catch (RuntimeException e) { + File f = new File(root); + boolean exists = f.exists(); + boolean readable = f.canRead(); + System.err.printf("getSpace0 failed for %s (%s, %s)%n", + root, exists, readable); + throw e; + } + } + private static void getCDDriveSpace(String root, long[] sizes) throws IOException { String[] cmd = new String[] {"df", "-k", "-P", root}; diff --git a/test/jdk/java/lang/ProcessBuilder/Basic.java b/test/jdk/java/lang/ProcessBuilder/Basic.java index 4377752650d..7034174f85c 100644 --- a/test/jdk/java/lang/ProcessBuilder/Basic.java +++ b/test/jdk/java/lang/ProcessBuilder/Basic.java @@ -85,8 +85,8 @@ public class Basic { static final String libpath = System.getenv("LIBPATH"); /* Used for regex String matching for long error messages */ - static final String PERMISSION_DENIED_ERROR_MSG = "(Permission denied|error=13)"; - static final String NO_SUCH_FILE_ERROR_MSG = "(No such file|error=2)"; + static final String PERMISSION_DENIED_ERROR_MSG = "(Permission denied|error:13)"; + static final String NO_SUCH_FILE_ERROR_MSG = "(No such file|error:2)"; static final String SPAWNHELPER_FAILURE_MSG = "(Possible reasons:)"; /** diff --git a/test/jdk/java/lang/String/UnicodeCaseFoldingTest.java b/test/jdk/java/lang/String/UnicodeCaseFoldingTest.java new file mode 100644 index 00000000000..86b3fba0a27 --- /dev/null +++ b/test/jdk/java/lang/String/UnicodeCaseFoldingTest.java @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary tests unicode case-folding based String comparison and equality + * @bug 4397357 + * @library /lib/testlibrary/java/lang + * @modules java.base/jdk.internal.lang:+open + * @run junit/othervm + * UnicodeCaseFoldingTest + */ + +import java.nio.file.Files; +import java.util.stream.Stream; +import java.util.stream.Collectors; +import java.util.ArrayList; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import jdk.internal.lang.CaseFolding; + +public class UnicodeCaseFoldingTest { + + @Test + void testAllCommnFullCodePointsListedInCaseFoldinigTxt() throws Throwable { + var filter = "^.*; [CF]; .*$"; // C=common, F=full, for full case folding + var results = Files.lines(UCDFiles.CASEFOLDING) + .filter(line -> !line.startsWith("#") && line.matches(filter)) + .map(line -> { + var fields = line.split("; "); + var cp = Integer.parseInt(fields[0], 16); + fields = fields[2].trim().split(" "); + var folding = new int[fields.length]; + for (int i = 0; i < folding.length; i++) { + folding[i] = Integer.parseInt(fields[i], 16); + } + var source = new String(Character.toChars(cp)); + var expected = new String(folding, 0, folding.length); + // (1) Verify the folding result matches expected + assertEquals(expected, foldCase(source), "CaseFolding.fold(): "); + + // (2) Verify compareToFoldCase() result + assertEquals(0, source.compareToFoldCase(expected), "source.compareToFoldCase(expected)"); + assertEquals(0, expected.compareToFoldCase(source), "expected.compareToFoldCase(source)"); + + // (3) Verify equalsFoldCase() result + assertEquals(true, source.equalsFoldCase(expected), "source.equalsFoldCase(expected)"); + assertEquals(true, expected.equalsFoldCase(source), "expected.equalsFoldCase(source)"); + return null; + }) + .filter(error -> error != null) + .toArray(); + assertEquals(0, results.length); + } + + @Test + void testAllSimpleCodePointsListedInCaseFoldinigTxt() throws Throwable { + // S=simple, for simple case folding. The simple case folding should still matches + var filter = "^.*; [S]; .*$"; + var results = Files.lines(UCDFiles.CASEFOLDING) + .filter(line -> !line.startsWith("#") && line.matches(filter)) + .map(line -> { + var fields = line.split("; "); + var cp = Integer.parseInt(fields[0], 16); + fields = fields[2].trim().split(" "); + var folding = new int[fields.length]; + for (int i = 0; i < folding.length; i++) { + folding[i] = Integer.parseInt(fields[i], 16); + } + var source = new String(Character.toChars(cp)); + var expected = new String(folding, 0, folding.length); + + // (1) Verify compareToFoldCase() result + assertEquals(0, source.compareToFoldCase(expected), "source.compareToFoldCase(expected)"); + assertEquals(0, expected.compareToFoldCase(source), "expected.compareToFoldCase(source)"); + + // (2) Verify equalsFoldCase() result + assertEquals(true, source.equalsFoldCase(expected), "source.equalsFoldCase(expected)"); + assertEquals(true, expected.equalsFoldCase(source), "expected.equalsFoldCase(source)"); + return null; + }) + .filter(error -> error != null) + .toArray(); + assertEquals(0, results.length); + } + + @Test + public void testAllCodePointsFoldToThemselvesIfNotListed() throws Exception { + // Collect all code points that appear in CaseFolding.txt + var listed = Files.lines(UCDFiles.CASEFOLDING) + .filter(line -> !line.startsWith("#") && line.matches("^.*; [CF]; .*$")) + .map(line -> Integer.parseInt(line.split("; ")[0], 16)) + .collect(Collectors.toSet()); + + var failures = new ArrayList(); + + // Scan BMP + Supplementary Plane 1 (U+0000..U+1FFFF) + for (int cp = Character.MIN_CODE_POINT; cp <= 0x1FFFF; cp++) { + if (!Character.isDefined(cp)) { + continue; // skip undefined + } + if (Character.isSurrogate((char) cp)) { + continue; // skip surrogate code units + } + if (listed.contains(cp)) { + continue; // already tested separately + } + String s = new String(Character.toChars(cp)); + String folded = foldCase(s); + if (!s.equals(folded)) { + failures.add(String.format("Unexpected folding: U+%04X '%s' → '%s'", cp, s, folded)); + } + } + + assertEquals(0, failures.size(), + () -> "Some unlisted code points folded unexpectedly:\n" + + String.join("\n", failures)); + } + + @ParameterizedTest(name = "CaseFold \"{0}\" → \"{1}\"") + @MethodSource("caseFoldTestCases") + void testIndividualCaseFolding(String input, String expected) { + assertEquals(expected, foldCase(input)); + } + + static Stream caseFoldTestCases() { + return Stream.of( + // ASCII simple cases + Arguments.of("ABC", "abc"), + Arguments.of("already", "already"), + Arguments.of("MiXeD123", "mixed123"), + // --- Latin-1 to non-Latin-1 fold --- + Arguments.of("aBc\u00B5Efg", "abc\u03BCefg"), // "µ" → "μ" + Arguments.of("test\u00B5\ud801\udc00X", "test\u03bc\ud801\udc28x"), + // German Eszett + Arguments.of("Stra\u00DFe", "strasse"), // "Straße" + Arguments.of("\u1E9E", "ss"), // "ẞ" capital sharp S + // Turkish dotted I / dotless i + Arguments.of("I", "i"), + Arguments.of("\u0130", "i\u0307"), // capital dotted I → "i + dot above" + Arguments.of("\u0069\u0307", "i\u0307"), // small i + dot above remains + Arguments.of("\u0131", "\u0131"), // "ı" (dotless i stays dotless) + + // Greek special cases --- + Arguments.of("\u039F\u03A3", "\u03BF\u03C3"), // "ΟΣ" → "οσ" final sigma always folds to normal sigma + Arguments.of("\u1F88", "\u1F00\u03B9"), // "ᾈ" → "ἀι" Alpha with psili + ypogegrammeni + Arguments.of("\u039C\u03AC\u03CA\u03BF\u03C2", "\u03BC\u03AC\u03CA\u03BF\u03C3"), // "Μάϊος" → "μάϊοσ" + Arguments.of("\u1F08", "\u1F00"), // Ἀ (Capital Alpha with psili) → ἀ + + // Supplementary Plane characters + Arguments.of("\uD801\uDC00", "\uD801\uDC28"), // Deseret Capital Letter Long I → Small + Arguments.of("\uD801\uDC01", "\uD801\uDC29"), // Deseret Capital Letter Long E → Small + + // Supplementary inside ASCII + Arguments.of("abc\uD801\uDC00def", "abc\uD801\uDC28def"), + // Ligatures and compatibility folds + Arguments.of("\uFB00", "ff"), // ff → ff + Arguments.of("\uFB03", "ffi"), // ffi → ffi + Arguments.of("\u212A", "k"), // Kelvin sign → k + + Arguments.of("abc\uFB00def", "abcffdef"), // ff → ff + Arguments.of("abc\uFB03def", "abcffidef"), // ffi → ffi + Arguments.of("abc\u212Adef", "abckdef"), // Kelvin sign → k + + // --- Fullwidth --- + Arguments.of("\uFF21\uFF22\uFF23", "\uFF41\uFF42\uFF43"), // "ABC" → "abc" + + // --- Armenian --- + Arguments.of("\u0531", "\u0561"), // "Ա" → "ա" + + // --- Cherokee --- + Arguments.of("\u13A0", "\u13A0"), // Capital Cherokee A folds to itself + Arguments.of("\uAB70", "\u13A0") // Small Cherokee A folds Capital Cherokee A + ); + } + + static Stream caseFoldEqualProvider() { + return Stream.of( + Arguments.of("abc", "ABC"), + Arguments.of("aBcDe", "AbCdE"), + Arguments.of("\u00C0\u00E7", "\u00E0\u00C7"), // Àç vs àÇ + Arguments.of("straße", "STRASSE"), // ß → ss + Arguments.of("\uD83C\uDDE6", "\uD83C\uDDE6"), // 🇦 vs 🇦 + Arguments.of("\u1E9E", "ss"), // ẞ (capital sharp S) + Arguments.of("\u03A3", "\u03C3"), // Σ vs σ (Greek Sigma) + Arguments.of("\u03C3", "\u03C2"), // σ vs ς (Greek sigma/final sigma) + Arguments.of("\u212B", "\u00E5"), // Å (Angstrom sign) vs å + Arguments.of("\uFB00", "ff"), // ff (ligature) + Arguments.of("\u01C5", "\u01C5"), // Dž (Latin capital D with small z with caron) + Arguments.of("Caf\u00E9", "CAF\u00C9"), // Café vs CAFÉ + Arguments.of("\u03BA\u03B1\u03BB\u03B7\u03BC\u03AD\u03C1\u03B1", "\u039A\u0391\u039B\u0397\u039C\u0388\u03A1\u0391"), // καλημέρα vs ΚΑΛΗΜΕΡΑ + Arguments.of("\u4E2D\u56FD", "\u4E2D\u56FD"), // 中国 + Arguments.of("\u03B1", "\u0391"), // α vs Α (Greek alpha) + Arguments.of("\u212B", "\u00C5"), // Å vs Å + // from StringCompareToIgnoreCase + Arguments.of("\u0100\u0102\u0104\u0106\u0108", "\u0100\u0102\u0104\u0106\u0109"), // ĀĂĄĆĈ vs ĀĂĄĆĉ + Arguments.of("\u0101\u0103\u0105\u0107\u0109", "\u0100\u0102\u0104\u0106\u0109"), // āăąćĉ vs ĀĂĄĆĉ + Arguments.of("\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc04", + "\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc2c"), // 𐐀𐐁𐐂𐐃𐐄 vs 𐐀𐐁𐐂𐐃𐐬 + Arguments.of("\ud801\udc28\ud801\udc29\ud801\udc2a\ud801\udc2b\ud801\udc2c", + "\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc2c") // 𐐨𐐩𐐪𐐫𐐬 vs 𐐀𐐁𐐂𐐃𐐬 + ); + } + + @ParameterizedTest + @MethodSource("caseFoldEqualProvider") + void testcompareToFoldCaseEquals(String s1, String s2) { + assertEquals(0, s1.compareToFoldCase(s2)); + assertEquals(0, s2.compareToFoldCase(s1)); + assertEquals(true, s1.equalsFoldCase(s2)); + assertEquals(true, s2.equalsFoldCase(s1)); + assertEquals(foldCase(s1), foldCase(s2)); + } + + static Stream caseFoldOrderingProvider() { + return Stream.of( + Arguments.of("asa", "aß", -1), // ß → ss → "asa" < "ass" + Arguments.of("aß", "asa", +1), + Arguments.of("a\u00DF", "ass", 0), // aß vs ass + Arguments.of("\uFB03", "ffi", 0), // ffi (ligature) + Arguments.of("\u00C5", "Z", 1), // Å vs Z + Arguments.of("A", "\u00C0", -1), // A vs À + Arguments.of("\u03A9", "\u03C9", 0), // Ω vs ω + Arguments.of("\u03C2", "\u03C3", 0), // ς vs σ + Arguments.of("\uD835\uDD23", "R", 1), // 𝔯 (fraktur r) vs R + Arguments.of("\uFF26", "E", 1), // F (full-width F) vs E + Arguments.of("\u00C9clair", "Eclair", 1), // Éclair vs Eclair + Arguments.of("\u03bc\u00df", "\u00b5s", 1), + Arguments.of("\u00b5s", "\u03bc\u00df", -1) + ); + } + + @ParameterizedTest + @MethodSource("caseFoldOrderingProvider") + void testcompareToFoldCaseOrdering(String s1, String s2, int expectedSign) { + int cmp = s1.compareToFoldCase(s2); + assertEquals(expectedSign, Integer.signum(cmp)); + } + + static Stream roundTripProvider() { + return Stream.of( + Arguments.of("abc"), + Arguments.of("ABC"), + Arguments.of("straße"), + Arguments.of("Àç"), + Arguments.of("aß"), + Arguments.of("\uFB02uff"), // fluff (ligature in "fluff") + Arguments.of("\u00C9COLE") // ÉCOLE + ); + } + + @ParameterizedTest + @MethodSource("roundTripProvider") + void testCaseFoldRoundTrip(String s) { + String folded = foldCase(s); + assertEquals(0, s.compareToFoldCase(folded)); + assertEquals(0, folded.compareToFoldCase(s)); + assertEquals(true, s.equalsFoldCase(folded)); + assertEquals(true, folded.equalsFoldCase(s)); + } + + // helper to test the integrity of folding mapping + private static int[] longToFolding(long value) { + int len = (int) (value >>> 48); + if (len == 0) { + return new int[]{(int) (value & 0xFFFFF)}; + } else { + var folding = new int[len]; + for (int i = 0; i < len; i++) { + folding[i] = (int) (value & 0xFFFF); + value >>= 16; + } + return folding; + } + } + + private static String foldCase(String s) { + int first; + int len = s.length(); + int cpCnt = 1; + for (first = 0; first < len; first += cpCnt) { + int cp = s.codePointAt(first); + if (CaseFolding.isDefined(cp)) { + break; + } + cpCnt = Character.charCount(cp); + } + if (first == len) { + return s; + } + StringBuilder sb = new StringBuilder(len); + sb.append(s, 0, first); + for (int i = first; i < len; i += cpCnt) { + int cp = s.codePointAt(i); + int[] folded = longToFolding(CaseFolding.fold(cp)); + for (int f : folded) { + sb.appendCodePoint(f); + } + cpCnt = Character.charCount(cp); + } + return sb.toString(); + } +} diff --git a/test/jdk/java/lang/reflect/Modifier/toStringTest.java b/test/jdk/java/lang/reflect/Modifier/toStringTest.java index 85bceb48339..f36d83f1ad8 100644 --- a/test/jdk/java/lang/reflect/Modifier/toStringTest.java +++ b/test/jdk/java/lang/reflect/Modifier/toStringTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,36 +23,71 @@ /** * @test - * @bug 4394937 8051382 + * @bug 4394937 8051382 8373125 * @summary tests the toString method of reflect.Modifier */ import java.lang.reflect.Modifier; +import static java.lang.reflect.Modifier.*; public class toStringTest { static void testString(int test, String expected) { - if(!Modifier.toString(test).equals(expected)) - throw new RuntimeException(test + - " yields incorrect toString result"); + String result = Modifier.toString(test); + if(!expected.equals(result)) { + System.err.println("For input 0x" + Integer.toHexString(test)); + System.err.println("expected:\t" + expected + "\ngot\t\t" + result); + + throw new RuntimeException(); + } } - public static void main(String [] argv) { - int allMods = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | - Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | - Modifier.TRANSIENT | Modifier.VOLATILE | Modifier.SYNCHRONIZED | - Modifier.NATIVE | Modifier.STRICT | Modifier.INTERFACE; + public static void main(String... argv) { + int allMods = PUBLIC | PROTECTED | PRIVATE | + ABSTRACT | STATIC | FINAL | + TRANSIENT | VOLATILE | SYNCHRONIZED | + NATIVE | STRICT | INTERFACE; String allModsString = "public protected private abstract static " + "final transient volatile synchronized native strictfp interface"; - /* zero should have an empty string */ + final int ALL_ONES = ~0; + + // zero should have an empty string testString(0, ""); - /* test to make sure all modifiers print out in the proper order */ + // test to make sure all modifiers print out in the proper order testString(allMods, allModsString); - /* verify no extraneous modifiers are printed */ - testString(~0, allModsString); + // verify no extraneous modifiers are printed + testString(ALL_ONES, allModsString); + + ModifierKindCase[] kindModifiers = { + new ModifierKindCase(classModifiers(), + "public protected private abstract " + + "static final strictfp"), + + new ModifierKindCase(constructorModifiers(),"public protected private"), + + new ModifierKindCase(fieldModifiers(), + "public protected private " + + "static final transient volatile"), + + new ModifierKindCase(interfaceModifiers(), + "public protected private " + + "abstract static strictfp"), + + new ModifierKindCase(methodModifiers(), + "public protected private abstract " + + "static final synchronized native strictfp"), + + new ModifierKindCase(parameterModifiers(), "final"), + }; + + for (var modKindCase : kindModifiers) { + testString(ALL_ONES & modKindCase.mask(), modKindCase.expected()); + } } + + private record ModifierKindCase(int mask, String expected){} } diff --git a/test/jdk/java/net/Socket/AsyncShutdown.java b/test/jdk/java/net/Socket/AsyncShutdown.java index cdc930b360c..159c08075ad 100644 --- a/test/jdk/java/net/Socket/AsyncShutdown.java +++ b/test/jdk/java/net/Socket/AsyncShutdown.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,11 +24,13 @@ /* * @test * @requires (os.family == "linux" | os.family == "mac") - * @run testng AsyncShutdown * @summary Test shutdownInput/shutdownOutput with threads blocked in read/write + * @run junit AsyncShutdown */ import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; @@ -38,54 +40,56 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import static org.junit.jupiter.api.Assertions.*; -@Test -public class AsyncShutdown { +class AsyncShutdown { - public void testShutdownInput1() throws IOException { + @ParameterizedTest + @ValueSource(booleans = { false, true }) + void testShutdownInput(boolean timed) throws IOException { withConnection((s1, s2) -> { + InputStream in = s1.getInputStream(); scheduleShutdownInput(s1, 2000); - int n = s1.getInputStream().read(); - assertTrue(n == -1); + if (timed) { + s1.setSoTimeout(30*1000); + } + assertEquals(-1, in.read()); + assertEquals(0, in.available()); }); } - public void testShutdownInput2() throws IOException { - withConnection((s1, s2) -> { - scheduleShutdownInput(s1, 2000); - s1.setSoTimeout(30*1000); - int n = s1.getInputStream().read(); - assertTrue(n == -1); - }); - } - - public void testShutdownOutput1() throws IOException { + @Test + void testShutdownOutput1() throws IOException { withConnection((s1, s2) -> { + OutputStream out = s1.getOutputStream(); scheduleShutdownOutput(s1, 2000); byte[] data = new byte[128*1024]; try { while (true) { - s1.getOutputStream().write(data); + out.write(data); } } catch (IOException expected) { } }); } - public void testShutdownOutput2() throws IOException { + @Test + void testShutdownOutput2() throws IOException { withConnection((s1, s2) -> { s1.setSoTimeout(100); try { s1.getInputStream().read(); - assertTrue(false); + fail(); } catch (SocketTimeoutException e) { } + OutputStream out = s1.getOutputStream(); scheduleShutdownOutput(s1, 2000); byte[] data = new byte[128*1024]; try { while (true) { - s1.getOutputStream().write(data); + out.write(data); } } catch (IOException expected) { } }); diff --git a/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java b/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java new file mode 100644 index 00000000000..093885a6ba0 --- /dev/null +++ b/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.InputStream; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import static jdk.internal.net.http.HttpClientTimerAccess.assertNoResponseTimerEventRegistrations; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; +import static org.junit.jupiter.api.Assertions.fail; + +/* + * @test id=retriesDisabled + * @bug 8208693 + * @summary Verifies `HttpRequest::timeout` is effective for *response body* + * timeouts when all retry mechanisms are disabled. + * + * @library /test/lib + * /test/jdk/java/net/httpclient/lib + * access + * @build TimeoutResponseTestSupport + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @run junit/othervm + * -Djdk.httpclient.auth.retrylimit=0 + * -Djdk.httpclient.disableRetryConnect + * -Djdk.httpclient.redirects.retrylimit=0 + * -Dtest.requestTimeoutMillis=1000 + * TimeoutResponseBodyTest + */ + +/* + * @test id=retriesEnabledForResponseFailure + * @bug 8208693 + * @summary Verifies `HttpRequest::timeout` is effective for *response body* + * timeouts, where some initial responses are intentionally configured + * to fail to trigger retries. + * + * @library /test/lib + * /test/jdk/java/net/httpclient/lib + * access + * @build TimeoutResponseTestSupport + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @run junit/othervm + * -Djdk.httpclient.auth.retrylimit=0 + * -Djdk.httpclient.disableRetryConnect + * -Djdk.httpclient.redirects.retrylimit=3 + * -Dtest.requestTimeoutMillis=1000 + * -Dtest.responseFailureWaitDurationMillis=600 + * TimeoutResponseBodyTest + */ + +/** + * Verifies {@link HttpRequest#timeout() HttpRequest.timeout()} is effective + * for response body timeouts. + * + * @implNote + * + * Using a response body subscriber (i.e., {@link InputStream}) of type that + * allows gradual consumption of the response body after successfully building + * an {@link HttpResponse} instance to ensure timeouts are propagated even + * after the {@code HttpResponse} construction. + *

+ * Each test is provided a pristine ephemeral client to avoid any unexpected + * effects due to pooling. + */ +class TimeoutResponseBodyTest extends TimeoutResponseTestSupport { + + private static final Logger LOGGER = Utils.getDebugLogger( + TimeoutResponseBodyTest.class.getSimpleName()::toString, Utils.DEBUG); + + /** + * Tests timeouts using + * {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) HttpClient::send} + * against a server blocking without delivering the response body. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendOnMissingBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.BLOCK_BEFORE_BODY_DELIVERY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request"); + var response = client.send(pair.request(), HttpResponse.BodyHandlers.ofInputStream()); + LOGGER.log("Consuming the obtained response"); + verifyResponseBodyDoesNotArrive(response); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + /** + * Tests timeouts using + * {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler) HttpClient::sendAsync} + * against a server blocking without delivering the response body. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendAsyncOnMissingBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.BLOCK_BEFORE_BODY_DELIVERY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request asynchronously"); + var responseFuture = client.sendAsync(pair.request(), HttpResponse.BodyHandlers.ofInputStream()); + LOGGER.log("Obtaining the response"); + var response = responseFuture.get(); + LOGGER.log("Consuming the obtained response"); + verifyResponseBodyDoesNotArrive(response); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + private static void verifyResponseBodyDoesNotArrive(HttpResponse response) { + assertEquals(200, response.statusCode()); + assertThrowsHttpTimeoutException(() -> { + try (var responseBodyStream = response.body()) { + var readByte = responseBodyStream.read(); + fail("Unexpected read byte: " + readByte); + } + }); + } + + /** + * Tests timeouts using + * {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) HttpClient::send} + * against a server delivering the response body very slowly. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendOnSlowBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.DELIVER_BODY_SLOWLY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request"); + var response = client.send(pair.request(), HttpResponse.BodyHandlers.ofInputStream()); + LOGGER.log("Consuming the obtained response"); + verifyResponseBodyArrivesSlow(response); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + /** + * Tests timeouts using + * {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler) HttpClient::sendAsync} + * against a server delivering the response body very slowly. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendAsyncOnSlowBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.DELIVER_BODY_SLOWLY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request asynchronously"); + var responseFuture = client.sendAsync(pair.request(), HttpResponse.BodyHandlers.ofInputStream()); + LOGGER.log("Obtaining the response"); + var response = responseFuture.get(); + LOGGER.log("Consuming the obtained response"); + verifyResponseBodyArrivesSlow(response); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + private static void verifyResponseBodyArrivesSlow(HttpResponse response) { + assertEquals(200, response.statusCode()); + assertThrowsHttpTimeoutException(() -> { + try (var responseBodyStream = response.body()) { + int i = 0; + int l = ServerRequestPair.CONTENT_LENGTH; + for (; i < l; i++) { + LOGGER.log("Reading byte %s/%s", i, l); + var readByte = responseBodyStream.read(); + if (readByte < 0) { + break; + } + assertEquals(i, readByte); + } + fail("Should not have reached here! (i=%s)".formatted(i)); + } + }); + } + + /** + * Tests timeouts using + * {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) HttpClient::send} + * against a server delivering 204, i.e., no content, which is handled + * through a specialized path served by {@code MultiExchange::handleNoBody}. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendOnNoBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.DELIVER_NO_BODY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request"); + client.send(pair.request(), HttpResponse.BodyHandlers.discarding()); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + /** + * Tests timeouts using + * {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler) HttpClient::sendAsync} + * against a server delivering 204, i.e., no content, which is handled + * through a specialized path served by {@code MultiExchange::handleNoBody}. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendAsyncOnNoBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.DELIVER_NO_BODY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request asynchronously"); + client.sendAsync(pair.request(), HttpResponse.BodyHandlers.discarding()).get(); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + +} diff --git a/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java b/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java new file mode 100644 index 00000000000..ab562f8eab8 --- /dev/null +++ b/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import static jdk.internal.net.http.HttpClientTimerAccess.assertNoResponseTimerEventRegistrations; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; + +/* + * @test id=retriesDisabled + * @bug 8208693 + * @summary Verifies `HttpRequest::timeout` is effective for *response header* + * timeouts when all retry mechanisms are disabled. + * + * @library /test/jdk/java/net/httpclient/lib + * /test/lib + * access + * @build TimeoutResponseTestSupport + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @run junit/othervm + * -Djdk.httpclient.auth.retrylimit=0 + * -Djdk.httpclient.disableRetryConnect + * -Djdk.httpclient.redirects.retrylimit=0 + * -Dtest.requestTimeoutMillis=1000 + * TimeoutResponseHeaderTest + */ + +/* + * @test id=retriesEnabledForResponseFailure + * @bug 8208693 + * @summary Verifies `HttpRequest::timeout` is effective for *response header* + * timeouts, where some initial responses are intentionally configured + * to fail to trigger retries. + * + * @library /test/jdk/java/net/httpclient/lib + * /test/lib + * access + * @build TimeoutResponseTestSupport + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @run junit/othervm + * -Djdk.httpclient.auth.retrylimit=0 + * -Djdk.httpclient.disableRetryConnect + * -Djdk.httpclient.redirects.retrylimit=3 + * -Dtest.requestTimeoutMillis=1000 + * -Dtest.responseFailureWaitDurationMillis=600 + * TimeoutResponseHeaderTest + */ + +/** + * Verifies {@link HttpRequest#timeout() HttpRequest.timeout()} is effective + * for response header timeouts. + */ +class TimeoutResponseHeaderTest extends TimeoutResponseTestSupport { + + private static final Logger LOGGER = Utils.getDebugLogger( + TimeoutResponseHeaderTest.class.getSimpleName()::toString, Utils.DEBUG); + + static { + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.BLOCK_BEFORE_HEADER_DELIVERY; + } + + /** + * Tests timeouts using + * {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) HttpClient::send} + * against a server blocking without delivering any response headers. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSend(ServerRequestPair pair) throws Exception { + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively( + REQUEST_TIMEOUT.multipliedBy(2), + () -> assertThrowsHttpTimeoutException(() -> { + LOGGER.log("Sending the request"); + client.send(pair.request(), HttpResponse.BodyHandlers.discarding()); + })); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + } + + /** + * Tests timeouts using + * {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler) HttpClient::sendAsync} + * against a server blocking without delivering any response headers. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendAsync(ServerRequestPair pair) throws Exception { + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request asynchronously"); + var responseFuture = client.sendAsync(pair.request(), HttpResponse.BodyHandlers.discarding()); + assertThrowsHttpTimeoutException(() -> { + LOGGER.log("Obtaining the response"); + responseFuture.get(); + }); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + } + +} diff --git a/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java b/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java new file mode 100644 index 00000000000..4da63a2dff9 --- /dev/null +++ b/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestExchange; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestHandler; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; +import jdk.internal.net.http.frame.ErrorFrame; +import jdk.internal.net.http.http3.Http3Error; +import jdk.test.lib.net.SimpleSSLContext; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.function.Executable; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpClient.Version; +import java.net.http.HttpOption; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpTimeoutException; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; +import static jdk.httpclient.test.lib.common.HttpServerAdapters.createClientBuilderFor; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Utilities for {@code TimeoutResponse*Test}s. + * + * @see TimeoutResponseBodyTest Server response body timeout tests + * @see TimeoutResponseHeaderTest Server response header timeout tests + * @see TimeoutBasic Server connection timeout tests + */ +public class TimeoutResponseTestSupport { + + private static final String CLASS_NAME = TimeoutResponseTestSupport.class.getSimpleName(); + + private static final Logger LOGGER = Utils.getDebugLogger(CLASS_NAME::toString, Utils.DEBUG); + + private static final SSLContext SSL_CONTEXT = createSslContext(); + + protected static final Duration REQUEST_TIMEOUT = + Duration.ofMillis(Long.parseLong(System.getProperty("test.requestTimeoutMillis"))); + + static { + assertTrue( + REQUEST_TIMEOUT.isPositive(), + "was expecting `test.requestTimeoutMillis > 0`, found: " + REQUEST_TIMEOUT); + } + + protected static final int RETRY_LIMIT = + Integer.parseInt(System.getProperty("jdk.httpclient.redirects.retrylimit", "0")); + + private static final long RESPONSE_FAILURE_WAIT_DURATION_MILLIS = + Long.parseLong(System.getProperty("test.responseFailureWaitDurationMillis", "0")); + + static { + if (RETRY_LIMIT > 0) { + + // Verify that response failure wait duration is provided + if (RESPONSE_FAILURE_WAIT_DURATION_MILLIS <= 0) { + var message = String.format( + "`jdk.httpclient.redirects.retrylimit` (%s) is greater than zero. " + + "`test.responseFailureWaitDurationMillis` (%s) must be greater than zero too.", + RETRY_LIMIT, RESPONSE_FAILURE_WAIT_DURATION_MILLIS); + throw new AssertionError(message); + } + + // Verify that the total response failure waits exceed the request timeout + var totalResponseFailureWaitDuration = Duration + .ofMillis(RESPONSE_FAILURE_WAIT_DURATION_MILLIS) + .multipliedBy(RETRY_LIMIT); + if (totalResponseFailureWaitDuration.compareTo(REQUEST_TIMEOUT) <= 0) { + var message = ("`test.responseFailureWaitDurationMillis * jdk.httpclient.redirects.retrylimit` (%s * %s = %s) " + + "must be greater than `test.requestTimeoutMillis` (%s)") + .formatted( + RESPONSE_FAILURE_WAIT_DURATION_MILLIS, + RETRY_LIMIT, + totalResponseFailureWaitDuration, + REQUEST_TIMEOUT); + throw new AssertionError(message); + } + + } + } + + protected static final ServerRequestPair + HTTP1 = ServerRequestPair.of(Version.HTTP_1_1, false), + HTTPS1 = ServerRequestPair.of(Version.HTTP_1_1, true), + HTTP2 = ServerRequestPair.of(Version.HTTP_2, false), + HTTPS2 = ServerRequestPair.of(Version.HTTP_2, true), + HTTP3 = ServerRequestPair.of(Version.HTTP_3, true); + + private static SSLContext createSslContext() { + try { + return new SimpleSSLContext().get(); + } catch (IOException exception) { + throw new UncheckedIOException(exception); + } + } + + protected record ServerRequestPair(HttpTestServer server, HttpRequest request, boolean secure) { + + private static final ExecutorService EXECUTOR = Executors.newVirtualThreadPerTaskExecutor(); + + private static final CountDownLatch SHUT_DOWN_LATCH = new CountDownLatch(1); + + private static final AtomicInteger SERVER_COUNTER = new AtomicInteger(); + + /** + * An arbitrary content length to cause the client wait for it. + * It just needs to be greater than zero, and big enough to trigger a timeout when delivered slowly. + */ + public static final int CONTENT_LENGTH = 1234; + + public enum ServerHandlerBehaviour { + BLOCK_BEFORE_HEADER_DELIVERY, + BLOCK_BEFORE_BODY_DELIVERY, + DELIVER_BODY_SLOWLY, + DELIVER_NO_BODY + } + + public static volatile ServerHandlerBehaviour SERVER_HANDLER_BEHAVIOUR; + + public static volatile int SERVER_HANDLER_PENDING_FAILURE_COUNT = 0; + + private static ServerRequestPair of(Version version, boolean secure) { + + // Create the server and the request URI + var sslContext = secure ? SSL_CONTEXT : null; + var serverId = "" + SERVER_COUNTER.getAndIncrement(); + var server = createServer(version, sslContext); + server.getVersion(); + var handlerPath = "/%s/".formatted(CLASS_NAME); + var requestUriScheme = secure ? "https" : "http"; + var requestUri = URI.create("%s://%s%s-".formatted(requestUriScheme, server.serverAuthority(), handlerPath)); + + // Register the request handler + server.addHandler(createServerHandler(serverId), handlerPath); + + // Create the request + var request = createRequestBuilder(requestUri, version).timeout(REQUEST_TIMEOUT).build(); + + // Create the pair + var pair = new ServerRequestPair(server, request, secure); + pair.server.start(); + LOGGER.log("Server[%s] is started at `%s`", serverId, server.serverAuthority()); + return pair; + + } + + private static HttpTestServer createServer(Version version, SSLContext sslContext) { + try { + return switch (version) { + case HTTP_1_1, HTTP_2 -> HttpTestServer.create(version, sslContext, EXECUTOR); + case HTTP_3 -> HttpTestServer.create(HTTP_3_URI_ONLY, sslContext, EXECUTOR); + }; + } catch (IOException exception) { + throw new UncheckedIOException(exception); + } + } + + private static HttpTestHandler createServerHandler(String serverId) { + return (exchange) -> { + var connectionKey = exchange.getConnectionKey(); + LOGGER.log( + "Server[%s] has received request %s", + serverId, Map.of("connectionKey", connectionKey)); + try (exchange) { + + // Short-circuit on `HEAD` requests. + // They are used for admitting established connections to the pool. + if ("HEAD".equals(exchange.getRequestMethod())) { + LOGGER.log( + "Server[%s] is responding to the `HEAD` request %s", + serverId, Map.of("connectionKey", connectionKey)); + exchange.sendResponseHeaders(200, 0); + return; + } + + // Short-circuit if instructed to fail + synchronized (ServerRequestPair.class) { + if (SERVER_HANDLER_PENDING_FAILURE_COUNT > 0) { + LOGGER.log( + "Server[%s] is prematurely failing as instructed %s", + serverId, + Map.of( + "connectionKey", connectionKey, + "SERVER_HANDLER_PENDING_FAILURE_COUNT", SERVER_HANDLER_PENDING_FAILURE_COUNT)); + // Closing the exchange will trigger an `END_STREAM` without a headers frame. + // This is a protocol violation, hence we must reset the stream first. + // We are doing so using by rejecting the stream, which is known to make the client retry. + if (Version.HTTP_2.equals(exchange.getExchangeVersion())) { + exchange.resetStream(ErrorFrame.REFUSED_STREAM); + } else if (Version.HTTP_3.equals(exchange.getExchangeVersion())) { + exchange.resetStream(Http3Error.H3_REQUEST_REJECTED.code()); + } + SERVER_HANDLER_PENDING_FAILURE_COUNT--; + return; + } + } + + switch (SERVER_HANDLER_BEHAVIOUR) { + + case BLOCK_BEFORE_HEADER_DELIVERY -> sleepIndefinitely(serverId, connectionKey); + + case BLOCK_BEFORE_BODY_DELIVERY -> { + sendResponseHeaders(serverId, exchange, connectionKey); + sleepIndefinitely(serverId, connectionKey); + } + + case DELIVER_BODY_SLOWLY -> { + sendResponseHeaders(serverId, exchange, connectionKey); + sendResponseBodySlowly(serverId, exchange, connectionKey); + } + + case DELIVER_NO_BODY -> sendResponseHeaders(serverId, exchange, connectionKey, 204, 0); + + } + + } catch (Exception exception) { + var message = String.format( + "Server[%s] has failed! %s", + serverId, Map.of("connectionKey", connectionKey)); + LOGGER.log(System.Logger.Level.ERROR, message, exception); + if (exception instanceof InterruptedException) { + // Restore the interrupt + Thread.currentThread().interrupt(); + } + throw new RuntimeException(message, exception); + } + }; + } + + private static void sleepIndefinitely(String serverId, String connectionKey) throws InterruptedException { + LOGGER.log("Server[%s] is sleeping %s", serverId, Map.of("connectionKey", connectionKey)); + SHUT_DOWN_LATCH.await(); + } + + private static void sendResponseHeaders(String serverId, HttpTestExchange exchange, String connectionKey) + throws IOException { + sendResponseHeaders(serverId, exchange, connectionKey, 200, CONTENT_LENGTH); + } + + private static void sendResponseHeaders( + String serverId, + HttpTestExchange exchange, + String connectionKey, + int statusCode, + long contentLength) + throws IOException { + LOGGER.log("Server[%s] is sending headers %s", serverId, Map.of("connectionKey", connectionKey)); + exchange.sendResponseHeaders(statusCode, contentLength); + // Force the headers to be flushed + exchange.getResponseBody().flush(); + } + + private static void sendResponseBodySlowly(String serverId, HttpTestExchange exchange, String connectionKey) + throws Exception { + var perBytePauseDuration = Duration.ofMillis(100); + assertTrue( + perBytePauseDuration.multipliedBy(CONTENT_LENGTH).compareTo(REQUEST_TIMEOUT) > 0, + "Per-byte pause duration (%s) must be long enough to exceed the timeout (%s) when delivering the content (%s bytes)".formatted( + perBytePauseDuration, REQUEST_TIMEOUT, CONTENT_LENGTH)); + try (var responseBody = exchange.getResponseBody()) { + for (int i = 0; i < CONTENT_LENGTH; i++) { + LOGGER.log( + "Server[%s] is sending the body %s/%s %s", + serverId, i, CONTENT_LENGTH, Map.of("connectionKey", connectionKey)); + responseBody.write(i); + responseBody.flush(); + Thread.sleep(perBytePauseDuration); + } + throw new AssertionError("Delivery should never have succeeded due to timeout!"); + } catch (IOException _) { + // Client's timeout mechanism is expected to short-circuit and cut the stream. + // Hence, discard I/O failures. + } + } + + public HttpClient createClientWithEstablishedConnection() throws IOException, InterruptedException { + var version = server.getVersion(); + var client = createClientBuilderFor(version) + .version(version) + .sslContext(SSL_CONTEXT) + .proxy(NO_PROXY) + .build(); + // Ensure an established connection is admitted to the pool. This + // helps to cross out any possibilities of a timeout before a + // request makes it to the server handler. For instance, consider + // HTTP/1.1 to HTTP/2 upgrades, or long-running TLS handshakes. + var headRequest = createRequestBuilder(request.uri(), version).HEAD().build(); + client.send(headRequest, HttpResponse.BodyHandlers.discarding()); + return client; + } + + private static HttpRequest.Builder createRequestBuilder(URI uri, Version version) { + var requestBuilder = HttpRequest.newBuilder(uri).version(version); + if (Version.HTTP_3.equals(version)) { + requestBuilder.setOption(HttpOption.H3_DISCOVERY, HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY); + } + return requestBuilder; + } + + @Override + public String toString() { + var version = server.getVersion(); + var versionString = version.toString(); + return switch (version) { + case HTTP_1_1, HTTP_2 -> secure ? versionString.replaceFirst("_", "S_") : versionString; + case HTTP_3 -> versionString; + }; + } + + } + + @AfterAll + static void closeServers() { + + // Terminate all handlers before shutting down the server, which would block otherwise. + ServerRequestPair.SHUT_DOWN_LATCH.countDown(); + ServerRequestPair.EXECUTOR.shutdown(); + + // Shut down servers + Exception[] exceptionRef = {null}; + serverRequestPairs() + .forEach(pair -> { + try { + pair.server.stop(); + } catch (Exception exception) { + if (exceptionRef[0] == null) { + exceptionRef[0] = exception; + } else { + exceptionRef[0].addSuppressed(exception); + } + } + }); + if (exceptionRef[0] != null) { + throw new RuntimeException("failed closing one or more server resources", exceptionRef[0]); + } + + } + + /** + * Configures how many times the handler should fail. + */ + @BeforeEach + void resetServerHandlerFailureIndex() { + ServerRequestPair.SERVER_HANDLER_PENDING_FAILURE_COUNT = Math.max(0, RETRY_LIMIT - 1); + } + + /** + * Ensures that the handler has failed as many times as instructed. + */ + @AfterEach + void verifyServerHandlerFailureIndex() { + assertEquals(0, ServerRequestPair.SERVER_HANDLER_PENDING_FAILURE_COUNT); + } + + protected static Stream serverRequestPairs() { + return Stream.of(HTTP1, HTTPS1, HTTP2, HTTPS2, HTTP3); + } + + protected static void assertThrowsHttpTimeoutException(Executable executable) { + var rootException = assertThrows(Exception.class, executable); + // Due to intricacies involved in the way exceptions are generated and + // nested, there is no bullet-proof way to determine at which level of + // the causal chain an `HttpTimeoutException` will show up. Hence, we + // scan through the entire causal chain. + Throwable exception = rootException; + while (exception != null) { + if (exception instanceof HttpTimeoutException) { + return; + } + exception = exception.getCause(); + } + throw new AssertionError("was expecting an `HttpTimeoutException` in the causal chain", rootException); + } + +} diff --git a/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientTimerAccess.java b/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientTimerAccess.java new file mode 100644 index 00000000000..8bc1fac7b60 --- /dev/null +++ b/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientTimerAccess.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.net.http; + +import java.net.http.HttpClient; + +public enum HttpClientTimerAccess {; + + public static void assertNoResponseTimerEventRegistrations(HttpClient client) { + assertTimerEventRegistrationCount(client, ResponseTimerEvent.class, 0); + } + + private static void assertTimerEventRegistrationCount( + HttpClient client, + Class clazz, + long expectedCount) { + var facade = assertType(HttpClientFacade.class, client); + var actualCount = facade.impl.timers().stream().filter(clazz::isInstance).count(); + if (actualCount != 0) { + throw new AssertionError( + "Found %s occurrences of `%s` timer event registrations while expecting %s.".formatted( + actualCount, clazz.getCanonicalName(), expectedCount)); + } + } + + private static T assertType(Class expectedType, Object instance) { + if (!expectedType.isInstance(instance)) { + var expectedTypeName = expectedType.getCanonicalName(); + var actualTypeName = instance != null ? instance.getClass().getCanonicalName() : null; + throw new AssertionError( + "Was expecting an instance of type `%s`, found: `%s`".formatted( + expectedTypeName, actualTypeName)); + } + @SuppressWarnings("unchecked") + T typedInstance = (T) instance; + return typedInstance; + } + +} diff --git a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java index 862ccf22ddc..2e4047cf5ea 100644 --- a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java +++ b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java @@ -37,7 +37,7 @@ * -Djdk.internal.httpclient.quic.poller.usePlatformThreads=false * -Djdk.httpclient.quic.maxEndpoints=-1 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 - * -Djdk.httpclient.quic.maxBidiStreams=2 + * -Djdk.internal.httpclient.quic.maxBidiStreams=2 * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:retransmit * -Dsimpleget.requests=100 @@ -61,7 +61,7 @@ * -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations * -Djdk.httpclient.quic.maxEndpoints=-1 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 - * -Djdk.httpclient.quic.maxBidiStreams=2 + * -Djdk.internal.httpclient.quic.maxBidiStreams=2 * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:retransmit * -Dsimpleget.requests=100 @@ -85,7 +85,7 @@ * -Djdk.internal.httpclient.quic.useNioSelector=true * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 * -Djdk.httpclient.quic.maxEndpoints=1 - * -Djdk.httpclient.quic.maxBidiStreams=2 + * -Djdk.internal.httpclient.quic.maxBidiStreams=2 * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:hs:retransmit * -Dsimpleget.requests=100 @@ -109,7 +109,7 @@ * -Djdk.httpclient.quic.maxPtoBackoff=9 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 * -Djdk.httpclient.quic.maxEndpoints=1 - * -Djdk.httpclient.quic.maxBidiStreams=2 + * -Djdk.internal.httpclient.quic.maxBidiStreams=2 * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:hs:retransmit * -Dsimpleget.requests=100 @@ -239,7 +239,7 @@ public class H3MultipleConnectionsToSameHost implements HttpServerAdapters { long done = System.nanoTime(); System.out.println("Initialization and warmup took "+ TimeUnit.NANOSECONDS.toMillis(done-prestart)+" millis"); // Thread.sleep(30000); - int maxBidiStreams = Utils.getIntegerNetProperty("jdk.httpclient.quic.maxBidiStreams", 100); + int maxBidiStreams = Utils.getIntegerNetProperty("jdk.internal.httpclient.quic.maxBidiStreams", 100); long timeout = MAX_STREAM_LIMIT_WAIT_TIMEOUT; Set connections = new ConcurrentSkipListSet<>(); diff --git a/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java b/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java index 916a6a5221d..0de80c6d587 100644 --- a/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java +++ b/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java @@ -23,6 +23,24 @@ /* * @test id=with-default-wait + * @summary this test verifies that the correct connection is + * used when a request is retried on a new connection + * due to stream limit reached. + * The maxBidiStreams limit is artificially set to 1. + * This configuration uses the default wait for a stream + * to become available before retrying. + * Different configurations are tested if possible, + * with both HTTP/3 only and HTTP/2 HTTP/3 with altsvc. + * In one case the HTTP/3 only server will be listening + * on the same port as the HTTP/2 server, with the + * HTTP/2 server advertising an AltService on a different + * port. In another case the AltService will be on the + * same port as the HTTP/2 server and the HTTP/3 server + * will be on a different port. In all case, the test + * verifies that the right connection is picked up + * for the retry. + * @bug 8372951 + * @comment this test also tests bug 8372951 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer * jdk.test.lib.Asserts @@ -30,12 +48,30 @@ * jdk.test.lib.net.SimpleSSLContext * @run testng/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors,http3,quic:control * -Djdk.internal.httpclient.debug=false - * -Djdk.httpclient.quic.maxBidiStreams=1 + * -Djdk.internal.httpclient.quic.maxBidiStreams=1 * H3StreamLimitReachedTest */ /* * @test id=with-no-wait + * @summary this test verifies that the correct connection is + * used when a request is retried on a new connection + * due to stream limit reached. + * The maxBidiStreams limit is artificially set to 1. + * This configuration retries immediately on a new + * connection when no stream is available. + * Different configurations are tested if possible, + * with both HTTP/3 only and HTTP/2 HTTP/3 with altsvc. + * In one case the HTTP/3 only server will be listening + * on the same port as the HTTP/2 server, with the + * HTTP/2 server advertising an AltService on a different + * port. In another case the AltService will be on the + * same port as the HTTP/2 server and the HTTP/3 server + * will be on a different port. In all case, the test + * verifies that the right connection is picked up + * for the retry. + * @bug 8372951 + * @comment this test also tests bug 8372951 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer * jdk.test.lib.Asserts @@ -43,7 +79,7 @@ * jdk.test.lib.net.SimpleSSLContext * @run testng/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors,http3,quic:control * -Djdk.internal.httpclient.debug=false - * -Djdk.httpclient.quic.maxBidiStreams=1 + * -Djdk.internal.httpclient.quic.maxBidiStreams=1 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 * -Djdk.httpclient.retryOnStreamlimit=9 * H3StreamLimitReachedTest @@ -93,7 +129,7 @@ import static org.testng.Assert.assertFalse; public class H3StreamLimitReachedTest implements HttpServerAdapters { - private static final String CLASS_NAME = H3ConnectionPoolTest.class.getSimpleName(); + private static final String CLASS_NAME = H3StreamLimitReachedTest.class.getSimpleName(); static int altsvcPort, https2Port, http3Port; static Http3TestServer http3OnlyServer; diff --git a/test/jdk/java/net/httpclient/http3/StreamLimitTest.java b/test/jdk/java/net/httpclient/http3/StreamLimitTest.java index d8a920c8544..105417950a1 100644 --- a/test/jdk/java/net/httpclient/http3/StreamLimitTest.java +++ b/test/jdk/java/net/httpclient/http3/StreamLimitTest.java @@ -56,7 +56,10 @@ import static java.net.http.HttpOption.H3_DISCOVERY; /* * @test * @summary verifies that when the Quic stream limit is reached - * then HTTP3 requests are retried on newer connection + * then HTTP3 requests are retried on newer connection. + * This test uses an HTTP/3 only test server, which is + * configured to allow the test to control when a new + * MAX_STREAMS frames is sent to the client. * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.common.HttpServerAdapters diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java index 83f8b6eab27..43bcb054b7d 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,10 @@ /* * @test - * @bug 8217429 + * @bug 8217429 8208693 + * @library ../access * @build DummyWebSocketServer + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess * @run testng/othervm * WebSocketTest */ @@ -40,6 +42,7 @@ import java.net.http.WebSocket; import java.net.http.WebSocketHandshakeException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -48,6 +51,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionStage; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; @@ -58,6 +62,7 @@ import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.net.http.HttpClient.newBuilder; import static java.net.http.WebSocket.NORMAL_CLOSURE; import static java.nio.charset.StandardCharsets.UTF_8; +import static jdk.internal.net.http.HttpClientTimerAccess.assertNoResponseTimerEventRegistrations; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; import static org.testng.Assert.fail; @@ -143,6 +148,45 @@ public class WebSocketTest { } } + /** + * Verifies that the internally issued request to establish the WebSocket + * connection does not leave any response timers registered at the client + * after the WebSocket handshake. + */ + @Test + public void responseTimerCleanUp() throws Exception { + try (var server = new DummyWebSocketServer()) { + server.open(); + try (var client = newBuilder().proxy(NO_PROXY).build()) { + var connectionEstablished = new CountDownLatch(1); + var webSocketListener = new WebSocket.Listener() { + + @Override + public void onOpen(WebSocket webSocket) { + connectionEstablished.countDown(); + } + + }; + var webSocket = client + .newWebSocketBuilder() + // Explicitly configure a timeout to get a response + // timer event get registered at the client. The query + // should succeed without timing out. + .connectTimeout(Duration.ofMinutes(2)) + .buildAsync(server.getURI(), webSocketListener) + .join(); + try { + connectionEstablished.await(); + // We expect the response timer event to get evicted once + // the WebSocket handshake headers are received. + assertNoResponseTimerEventRegistrations(client); + } finally { + webSocket.abort(); + } + } + } + } + @Test public void partialBinaryThenText() throws IOException { try (var server = new DummyWebSocketServer()) { diff --git a/test/jdk/java/net/vthread/BlockingSocketOps.java b/test/jdk/java/net/vthread/BlockingSocketOps.java index 3c6b9cd5276..ef58e06b915 100644 --- a/test/jdk/java/net/vthread/BlockingSocketOps.java +++ b/test/jdk/java/net/vthread/BlockingSocketOps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,15 +21,15 @@ * questions. */ -/** +/* * @test id=default - * @bug 8284161 + * @bug 8284161 8372958 * @summary Test virtual threads doing blocking I/O on java.net Sockets * @library /test/lib * @run junit BlockingSocketOps */ -/** +/* * @test id=poller-modes * @requires (os.family == "linux") | (os.family == "mac") * @library /test/lib @@ -37,7 +37,7 @@ * @run junit/othervm -Djdk.pollerMode=2 BlockingSocketOps */ -/** +/* * @test id=no-vmcontinuations * @requires vm.continuations * @library /test/lib @@ -60,6 +60,8 @@ import java.net.SocketTimeoutException; import jdk.test.lib.thread.VThreadRunner; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.*; class BlockingSocketOps { @@ -90,19 +92,8 @@ class BlockingSocketOps { /** * Virtual thread blocks in read. */ - @Test - void testSocketRead1() throws Exception { - testSocketRead(0); - } - - /** - * Virtual thread blocks in timed read. - */ - @Test - void testSocketRead2() throws Exception { - testSocketRead(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testSocketRead(int timeout) throws Exception { VThreadRunner.run(() -> { try (var connection = new Connection()) { @@ -202,19 +193,8 @@ class BlockingSocketOps { /** * Socket close while virtual thread blocked in read. */ - @Test - void testSocketReadAsyncClose1() throws Exception { - testSocketReadAsyncClose(0); - } - - /** - * Socket close while virtual thread blocked in timed read. - */ - @Test - void testSocketReadAsyncClose2() throws Exception { - testSocketReadAsyncClose(0); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testSocketReadAsyncClose(int timeout) throws Exception { VThreadRunner.run(() -> { try (var connection = new Connection()) { @@ -230,7 +210,34 @@ class BlockingSocketOps { try { int n = s.getInputStream().read(); fail("read " + n); - } catch (SocketException expected) { } + } catch (SocketException expected) { + log(expected); + } + } + }); + } + + /** + * Socket shutdownInput while virtual thread blocked in read. + */ + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testSocketReadAsyncShutdownInput(int timeout) throws Exception { + VThreadRunner.run(() -> { + try (var connection = new Connection()) { + Socket s = connection.socket1(); + + // delayed shutdown of input stream + InputStream in = s.getInputStream(); + runAfterParkedAsync(s::shutdownInput); + + // read should return -1 + if (timeout > 0) { + s.setSoTimeout(timeout); + } + assertEquals(-1, in.read()); + assertEquals(0, in.available()); + assertFalse(s.isClosed()); } }); } @@ -238,19 +245,8 @@ class BlockingSocketOps { /** * Virtual thread interrupted while blocked in Socket read. */ - @Test - void testSocketReadInterrupt1() throws Exception { - testSocketReadInterrupt(0); - } - - /** - * Virtual thread interrupted while blocked in Socket read with timeout - */ - @Test - void testSocketReadInterrupt2() throws Exception { - testSocketReadInterrupt(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testSocketReadInterrupt(int timeout) throws Exception { VThreadRunner.run(() -> { try (var connection = new Connection()) { @@ -269,6 +265,7 @@ class BlockingSocketOps { int n = s.getInputStream().read(); fail("read " + n); } catch (SocketException expected) { + log(expected); assertTrue(Thread.interrupted()); assertTrue(s.isClosed()); } @@ -285,7 +282,7 @@ class BlockingSocketOps { try (var connection = new Connection()) { Socket s = connection.socket1(); - // delayedclose of s + // delayed close of s runAfterParkedAsync(s::close); // write to s should block, then throw @@ -295,7 +292,36 @@ class BlockingSocketOps { for (;;) { out.write(ba); } - } catch (SocketException expected) { } + } catch (SocketException expected) { + log(expected); + } + } + }); + } + + /** + * Socket shutdownOutput while virtual thread blocked in write. + */ + @Test + void testSocketWriteAsyncShutdownOutput() throws Exception { + VThreadRunner.run(() -> { + try (var connection = new Connection()) { + Socket s = connection.socket1(); + + // delayed shutdown of output stream + OutputStream out = s.getOutputStream(); + runAfterParkedAsync(s::shutdownOutput); + + // write to s should block, then throw + try { + byte[] ba = new byte[100*1024]; + for (;;) { + out.write(ba); + } + } catch (SocketException expected) { + log(expected); + } + assertFalse(s.isClosed()); } }); } @@ -321,6 +347,7 @@ class BlockingSocketOps { out.write(ba); } } catch (SocketException expected) { + log(expected); assertTrue(Thread.interrupted()); assertTrue(s.isClosed()); } @@ -355,7 +382,9 @@ class BlockingSocketOps { try { s1.getInputStream().read(ba); fail(); - } catch (SocketTimeoutException expected) { } + } catch (SocketTimeoutException expected) { + log(expected); + } } }); } @@ -384,19 +413,8 @@ class BlockingSocketOps { /** * Virtual thread blocks in accept. */ - @Test - void testServerSocketAccept2() throws Exception { - testServerSocketAccept(0); - } - - /** - * Virtual thread blocks in timed accept. - */ - @Test - void testServerSocketAccept3() throws Exception { - testServerSocketAccept(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testServerSocketAccept(int timeout) throws Exception { VThreadRunner.run(() -> { try (var listener = new ServerSocket()) { @@ -422,19 +440,8 @@ class BlockingSocketOps { /** * ServerSocket close while virtual thread blocked in accept. */ - @Test - void testServerSocketAcceptAsyncClose1() throws Exception { - testServerSocketAcceptAsyncClose(0); - } - - /** - * ServerSocket close while virtual thread blocked in timed accept. - */ - @Test - void testServerSocketAcceptAsyncClose2() throws Exception { - testServerSocketAcceptAsyncClose(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testServerSocketAcceptAsyncClose(int timeout) throws Exception { VThreadRunner.run(() -> { try (var listener = new ServerSocket()) { @@ -451,7 +458,9 @@ class BlockingSocketOps { try { listener.accept().close(); fail("connection accepted???"); - } catch (SocketException expected) { } + } catch (SocketException expected) { + log(expected); + } } }); } @@ -459,19 +468,8 @@ class BlockingSocketOps { /** * Virtual thread interrupted while blocked in ServerSocket accept. */ - @Test - void testServerSocketAcceptInterrupt1() throws Exception { - testServerSocketAcceptInterrupt(0); - } - - /** - * Virtual thread interrupted while blocked in ServerSocket accept with timeout. - */ - @Test - void testServerSocketAcceptInterrupt2() throws Exception { - testServerSocketAcceptInterrupt(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testServerSocketAcceptInterrupt(int timeout) throws Exception { VThreadRunner.run(() -> { try (var listener = new ServerSocket()) { @@ -490,6 +488,7 @@ class BlockingSocketOps { listener.accept().close(); fail("connection accepted???"); } catch (SocketException expected) { + log(expected); assertTrue(Thread.interrupted()); assertTrue(listener.isClosed()); } @@ -529,20 +528,9 @@ class BlockingSocketOps { /** * Virtual thread blocks in DatagramSocket receive. */ - @Test - void testDatagramSocketSendReceive2() throws Exception { - testDatagramSocketSendReceive(0); - } - - /** - * Virtual thread blocks in DatagramSocket receive with timeout. - */ - @Test - void testDatagramSocketSendReceive3() throws Exception { - testDatagramSocketSendReceive(60_000); - } - - private void testDatagramSocketSendReceive(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketSendReceive(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramSocket s1 = new DatagramSocket(null); DatagramSocket s2 = new DatagramSocket(null)) { @@ -585,7 +573,9 @@ class BlockingSocketOps { try { s.receive(p); fail(); - } catch (SocketTimeoutException expected) { } + } catch (SocketTimeoutException expected) { + log(expected); + } } }); } @@ -593,20 +583,9 @@ class BlockingSocketOps { /** * DatagramSocket close while virtual thread blocked in receive. */ - @Test - void testDatagramSocketReceiveAsyncClose1() throws Exception { - testDatagramSocketReceiveAsyncClose(0); - } - - /** - * DatagramSocket close while virtual thread blocked with timeout. - */ - @Test - void testDatagramSocketReceiveAsyncClose2() throws Exception { - testDatagramSocketReceiveAsyncClose(60_000); - } - - private void testDatagramSocketReceiveAsyncClose(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketReceiveAsyncClose(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramSocket s = new DatagramSocket(null)) { InetAddress lh = InetAddress.getLoopbackAddress(); @@ -624,7 +603,9 @@ class BlockingSocketOps { DatagramPacket p = new DatagramPacket(ba, ba.length); s.receive(p); fail(); - } catch (SocketException expected) { } + } catch (SocketException expected) { + log(expected); + } } }); } @@ -632,20 +613,9 @@ class BlockingSocketOps { /** * Virtual thread interrupted while blocked in DatagramSocket receive. */ - @Test - void testDatagramSocketReceiveInterrupt1() throws Exception { - testDatagramSocketReceiveInterrupt(0); - } - - /** - * Virtual thread interrupted while blocked in DatagramSocket receive with timeout. - */ - @Test - void testDatagramSocketReceiveInterrupt2() throws Exception { - testDatagramSocketReceiveInterrupt(60_000); - } - - private void testDatagramSocketReceiveInterrupt(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketReceiveInterrupt(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramSocket s = new DatagramSocket(null)) { InetAddress lh = InetAddress.getLoopbackAddress(); @@ -665,6 +635,7 @@ class BlockingSocketOps { s.receive(p); fail(); } catch (SocketException expected) { + log(expected); assertTrue(Thread.interrupted()); assertTrue(s.isClosed()); } @@ -737,4 +708,11 @@ class BlockingSocketOps { } }); } + + /** + * Log to System.err to inline with the JUnit messages. + */ + static void log(Throwable e) { + System.err.println(e); + } } diff --git a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java index f04bece07b6..eb2229d927a 100644 --- a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java +++ b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java @@ -66,6 +66,8 @@ import java.util.concurrent.locks.LockSupport; import jdk.test.lib.thread.VThreadRunner; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.*; class BlockingChannelOps { @@ -301,20 +303,9 @@ class BlockingChannelOps { /** * Virtual thread blocks in SocketChannel adaptor read. */ - @Test - void testSocketAdaptorRead1() throws Exception { - testSocketAdaptorRead(0); - } - - /** - * Virtual thread blocks in SocketChannel adaptor read with timeout. - */ - @Test - void testSocketAdaptorRead2() throws Exception { - testSocketAdaptorRead(60_000); - } - - private void testSocketAdaptorRead(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testSocketAdaptorRead(int timeout) throws Exception { VThreadRunner.run(() -> { try (var connection = new Connection()) { SocketChannel sc1 = connection.channel1(); @@ -420,20 +411,9 @@ class BlockingChannelOps { /** * Virtual thread blocks in ServerSocketChannel adaptor accept. */ - @Test - void testSocketChannelAdaptorAccept1() throws Exception { - testSocketChannelAdaptorAccept(0); - } - - /** - * Virtual thread blocks in ServerSocketChannel adaptor accept with timeout. - */ - @Test - void testSocketChannelAdaptorAccept2() throws Exception { - testSocketChannelAdaptorAccept(60_000); - } - - private void testSocketChannelAdaptorAccept(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testSocketChannelAdaptorAccept(int timeout) throws Exception { VThreadRunner.run(() -> { try (var ssc = ServerSocketChannel.open()) { ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); @@ -546,20 +526,9 @@ class BlockingChannelOps { /** * Virtual thread blocks in DatagramSocket adaptor receive. */ - @Test - void testDatagramSocketAdaptorReceive1() throws Exception { - testDatagramSocketAdaptorReceive(0); - } - - /** - * Virtual thread blocks in DatagramSocket adaptor receive with timeout. - */ - @Test - void testDatagramSocketAdaptorReceive2() throws Exception { - testDatagramSocketAdaptorReceive(60_000); - } - - private void testDatagramSocketAdaptorReceive(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketAdaptorReceive(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramChannel dc1 = DatagramChannel.open(); DatagramChannel dc2 = DatagramChannel.open()) { @@ -585,21 +554,9 @@ class BlockingChannelOps { /** * DatagramChannel close while virtual thread blocked in adaptor receive. */ - @Test - void testDatagramSocketAdaptorReceiveAsyncClose1() throws Exception { - testDatagramSocketAdaptorReceiveAsyncClose(0); - } - - /** - * DatagramChannel close while virtual thread blocked in adaptor receive - * with timeout. - */ - @Test - void testDatagramSocketAdaptorReceiveAsyncClose2() throws Exception { - testDatagramSocketAdaptorReceiveAsyncClose(60_1000); - } - - private void testDatagramSocketAdaptorReceiveAsyncClose(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketAdaptorReceiveAsyncClose(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramChannel dc = DatagramChannel.open()) { InetAddress lh = InetAddress.getLoopbackAddress(); @@ -621,21 +578,9 @@ class BlockingChannelOps { /** * Virtual thread interrupted while blocked in DatagramSocket adaptor receive. */ - @Test - void testDatagramSocketAdaptorReceiveInterrupt1() throws Exception { - testDatagramSocketAdaptorReceiveInterrupt(0); - } - - /** - * Virtual thread interrupted while blocked in DatagramSocket adaptor receive - * with timeout. - */ - @Test - void testDatagramSocketAdaptorReceiveInterrupt2() throws Exception { - testDatagramSocketAdaptorReceiveInterrupt(60_1000); - } - - private void testDatagramSocketAdaptorReceiveInterrupt(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketAdaptorReceiveInterrupt(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramChannel dc = DatagramChannel.open()) { InetAddress lh = InetAddress.getLoopbackAddress(); diff --git a/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java b/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java index 34e343b6193..86ac5b0313b 100644 --- a/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java +++ b/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ /* @test * @bug 4111507 * @summary retryServerSocket should not retry on BindException - * @author Ann Wollrath * * @run main/othervm AddrInUse */ @@ -33,75 +32,54 @@ import java.net.ServerSocket; import java.rmi.registry.LocateRegistry; import java.rmi.server.ExportException; -public class AddrInUse implements Runnable { +public class AddrInUse { - private static int port = -1; - private static final long TIMEOUT = 10000; - - private boolean exportSucceeded = false; - private Throwable exportException = null; - - public void run() { - - /* - * Attempt to create (i.e. export) a registry on the port that - * has already been bound, and record the result. - */ - try { - LocateRegistry.createRegistry(port); - synchronized (this) { - exportSucceeded = true; - notifyAll(); - } - } catch (Throwable t) { - synchronized (this) { - exportException = t; - notifyAll(); - } - } - } + private static volatile Throwable registryExportFailure = null; public static void main(String[] args) throws Exception { - System.err.println("\nRegression test for bug 4111507\n"); - /* * Bind a server socket to a port. */ - ServerSocket server = new ServerSocket(0); - port = server.getLocalPort(); - System.err.println("Created a ServerSocket on port " + port + "..."); - - /* - * Start a thread that creates a registry on the same port, - * and analyze the result. - */ - System.err.println("create a registry on the same port..."); - System.err.println("(should cause an ExportException)"); - AddrInUse obj = new AddrInUse(); - synchronized (obj) { - (new Thread(obj, "AddrInUse")).start(); + try (ServerSocket server = new ServerSocket(0)) { + int port = server.getLocalPort(); + System.err.println("Created a ServerSocket on port " + port + "..."); /* - * Don't wait forever (original bug is that the export - * hangs). + * Start a thread that creates a registry on the same port, + * and analyze the result. */ - obj.wait(TIMEOUT); + System.err.println("create a registry on the same port..."); + System.err.println("(should cause an ExportException)"); - if (obj.exportSucceeded) { - throw new RuntimeException( - "TEST FAILED: export on already-bound port succeeded"); - } else if (obj.exportException != null) { - obj.exportException.printStackTrace(); - if (obj.exportException instanceof ExportException) { - System.err.println("TEST PASSED"); - } else { - throw new RuntimeException( - "TEST FAILED: unexpected exception occurred", - obj.exportException); + Thread exportRegistryThread = new Thread(() -> { + /* + * Attempt to create (i.e. export) a registry on the port that + * has already been bound, and record the result. + */ + try { + LocateRegistry.createRegistry(port); + } catch (Throwable t) { + registryExportFailure = t; } - } else { - throw new RuntimeException("TEST FAILED: export timed out"); + }, "ExportRegistry-Thread"); + + exportRegistryThread.start(); + + /* + * Wait for the LocateRegistry.createRegistry() call to complete or + * if it blocks forever (due to the original bug), then let jtreg fail + * the test with a timeout + */ + exportRegistryThread.join(); + if (registryExportFailure == null) { + throw new RuntimeException( + "TEST FAILED: export on already-bound port succeeded"); } + if (!(registryExportFailure instanceof ExportException)) { + throw new RuntimeException( + "TEST FAILED: unexpected exception occurred", registryExportFailure); + } + System.err.println("TEST PASSED, received expected exception: " + registryExportFailure); } } } diff --git a/test/jdk/java/text/Format/DateFormat/Bug4407042.java b/test/jdk/java/text/Format/DateFormat/Bug4407042.java index 1960cb2b151..85825ff8b21 100644 --- a/test/jdk/java/text/Format/DateFormat/Bug4407042.java +++ b/test/jdk/java/text/Format/DateFormat/Bug4407042.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,29 +27,31 @@ * @summary Make sure that cloned SimpleDateFormat objects work * independently in multiple threads. * @library /java/text/testlib - * @run main Bug4407042 10 + * @run junit Bug4407042 */ +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; + import java.io.*; import java.text.*; import java.util.*; -// Usage: java Bug4407042 [duration] public class Bug4407042 { static final String TIME_STRING = "2000/11/18 00:01:00"; static final long UTC_LONG = 974534460000L; static SimpleDateFormat masterFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); static boolean runrun = true; - static int duration = 100; + static int duration = 10; + @Test void test() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale) - || !TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); masterFormat.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); DateParseThread d1 = new DateParseThread(); @@ -124,11 +126,4 @@ public class Bug4407042 { } } } - - public static void main (String[] args) { - if (args.length == 1) { - duration = Math.max(10, Integer.parseInt(args[0])); - } - new Bug4407042().test(); - } } diff --git a/test/jdk/java/text/Format/DateFormat/Bug4845901.java b/test/jdk/java/text/Format/DateFormat/Bug4845901.java index 363a3518bf0..754197dbe0d 100644 --- a/test/jdk/java/text/Format/DateFormat/Bug4845901.java +++ b/test/jdk/java/text/Format/DateFormat/Bug4845901.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,19 +28,22 @@ * the same time zone abbreviation for standard and daylight saving * time. * @library /java/text/testlib - * @run main Bug4845901 + * @run junit/othervm Bug4845901 */ +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; + import java.util.*; import java.text.SimpleDateFormat; public class Bug4845901 { - public static void main (String args[]) { + + @Test + void test() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); TimeZone savedTZ = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("Australia/Sydney")); diff --git a/test/jdk/java/text/Format/DateFormat/Bug6530336.java b/test/jdk/java/text/Format/DateFormat/Bug6530336.java index 552343cb1ba..880e8b3ae2b 100644 --- a/test/jdk/java/text/Format/DateFormat/Bug6530336.java +++ b/test/jdk/java/text/Format/DateFormat/Bug6530336.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,93 +25,73 @@ * @test * @bug 6530336 6537997 8008577 8174269 8333582 * @library /java/text/testlib - * @run main Bug6530336 + * @run junit/othervm Bug6530336 */ +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.FieldSource; + import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Locale; import java.util.TimeZone; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class Bug6530336 { - public static void main(String[] args) throws Exception { - Locale defaultLocale = Locale.getDefault(); - TimeZone defaultTimeZone = TimeZone.getDefault(); + private static final Locale[] locales = Locale.getAvailableLocales(); + private static final TimeZone[] timezones = { + TimeZone.getTimeZone("America/New_York"), + TimeZone.getTimeZone("America/Denver"), + }; + private static final TimeZone timezone_LA = TimeZone.getTimeZone("America/Los_Angeles"); + private static final String[] expected = { + "Sun Jul 15 12:00:00 PDT 2007", + "Sun Jul 15 14:00:00 PDT 2007", + }; + private static final Date[] dates = new Date[2]; - boolean err = false; - - try { - Locale locales[] = Locale.getAvailableLocales(); - TimeZone timezone_LA = TimeZone.getTimeZone("America/Los_Angeles"); - TimeZone.setDefault(timezone_LA); - - TimeZone timezones[] = { - TimeZone.getTimeZone("America/New_York"), - TimeZone.getTimeZone("America/Denver"), - }; - - String[] expected = { - "Sun Jul 15 12:00:00 PDT 2007", - "Sun Jul 15 14:00:00 PDT 2007", - }; - - Date[] dates = new Date[2]; - - for (int i = 0; i < locales.length; i++) { - Locale locale = locales[i]; - if (!TestUtils.usesGregorianCalendar(locale)) { - continue; - } - - Locale.setDefault(locale); - - for (int j = 0; j < timezones.length; j++) { - Calendar cal = Calendar.getInstance(timezones[j]); - cal.set(2007, 6, 15, 15, 0, 0); - dates[j] = cal.getTime(); - } - - SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy"); - - for (int j = 0; j < timezones.length; j++) { - sdf.setTimeZone(timezones[j]); - String date = sdf.format(dates[j]); - // CLDR localizes GMT format into for some locales. Ignore those cases - if (date.matches(".*GMT[\\s+-]\\D.*") || - date.contains("UTC") || - date.contains("TMG") || // Interlingue - date.contains("\u07dc\u07ed\u07d5\u07d6") || // N’Ko - date.contains("\ua2e7\ua0c5\ua395\ua3e6\ua12e\ua209") || // Sichuan Yi, Nuosu - date.contains("\u06af\u0631\u06cc\u0646\u06cc\u0686")) { // Central Kurdish - continue; - } - sdf.setTimeZone(timezone_LA); - String date_LA = sdf.parse(date).toString(); - - if (!expected[j].equals(date_LA)) { - System.err.println("Got wrong Pacific time (" + - date_LA + ") for (" + date + ") in " + locale + - " in " + timezones[j] + - ".\nExpected=" + expected[j]); - err = true; - } - } - } - } - catch (Exception e) { - e.printStackTrace(); - err = true; - } - finally { - Locale.setDefault(defaultLocale); - TimeZone.setDefault(defaultTimeZone); - - if (err) { - throw new RuntimeException("Failed."); - } - } + @BeforeAll + static void setup() { + TimeZone.setDefault(timezone_LA); } + @ParameterizedTest + @FieldSource("locales") + void test(Locale locale) { + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); + Locale.setDefault(locale); + + for (int j = 0; j < timezones.length; j++) { + Calendar cal = Calendar.getInstance(timezones[j]); + cal.set(2007, 6, 15, 15, 0, 0); + dates[j] = cal.getTime(); + } + + SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy"); + + for (int j = 0; j < timezones.length; j++) { + sdf.setTimeZone(timezones[j]); + String date = sdf.format(dates[j]); + // CLDR localizes GMT format into for some locales. Ignore those cases + if (date.matches(".*GMT[\\s+-]\\D.*") || + date.contains("UTC") || + date.contains("TMG") || // Interlingue + date.contains("ߜ߭ߕߖ") || // N’Ko + date.contains("ꋧꃅꎕꏦꄮꈉ") || // Sichuan Yi, Nuosu + date.contains("گرینیچ")) { // Central Kurdish + continue; + } + sdf.setTimeZone(timezone_LA); + String date_LA = assertDoesNotThrow(() -> sdf.parse(date).toString()); + assertEquals(expected[j], date_LA, + "Got wrong Pacific time (%s) for (%s) in %s in %s.".formatted(date_LA, date, locale, timezones[j])); + } + } } diff --git a/test/jdk/java/text/Format/DateFormat/DateFormatRegression.java b/test/jdk/java/text/Format/DateFormat/DateFormatRegression.java index dbd12e66f60..2e3fed17ce5 100644 --- a/test/jdk/java/text/Format/DateFormat/DateFormatRegression.java +++ b/test/jdk/java/text/Format/DateFormat/DateFormatRegression.java @@ -25,6 +25,7 @@ import java.text.*; import java.util.*; import java.io.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -170,10 +171,8 @@ public class DateFormatRegression { @Test public void Test4059917() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); SimpleDateFormat fmt; String myDate; diff --git a/test/jdk/java/text/Format/MessageFormat/MessageRegression.java b/test/jdk/java/text/Format/MessageFormat/MessageRegression.java index e10e4899202..31aa5189ba2 100644 --- a/test/jdk/java/text/Format/MessageFormat/MessageRegression.java +++ b/test/jdk/java/text/Format/MessageFormat/MessageRegression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,7 @@ import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.Serializable; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -126,10 +127,8 @@ public class MessageRegression { @Test public void Test4031438() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); String pattern1 = "Impossible {1} has occurred -- status code is {0} and message is {2}."; String pattern2 = "Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'."; diff --git a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java index a0a096e6782..90f60151197 100644 --- a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java +++ b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java @@ -58,6 +58,7 @@ import java.math.BigDecimal; import java.io.*; import java.math.BigInteger; +import org.junit.jupiter.api.Assumptions; import sun.util.resources.LocaleData; import org.junit.jupiter.api.Test; @@ -109,10 +110,8 @@ public class NumberRegression { @Test public void Test4088161 (){ Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); DecimalFormat df = new DecimalFormat(); double d = 100; diff --git a/test/jdk/java/util/Calendar/CalendarLimitTest.java b/test/jdk/java/util/Calendar/CalendarLimitTest.java index e8a92f180ec..552aa5f9866 100644 --- a/test/jdk/java/util/Calendar/CalendarLimitTest.java +++ b/test/jdk/java/util/Calendar/CalendarLimitTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.util.*; import java.text.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -130,10 +131,8 @@ public class CalendarLimitTest public void TestCalendarLimit() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); ORIGIN = julianDayToMillis(JAN_1_1_JULIAN_DAY); Calendar cal = Calendar.getInstance(); diff --git a/test/jdk/java/util/Calendar/CalendarRegression.java b/test/jdk/java/util/Calendar/CalendarRegression.java index 7b0f2025005..6e5148c0c20 100644 --- a/test/jdk/java/util/Calendar/CalendarRegression.java +++ b/test/jdk/java/util/Calendar/CalendarRegression.java @@ -55,6 +55,7 @@ import java.util.function.Predicate; import static java.util.Calendar.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -575,10 +576,8 @@ public class CalendarRegression { @Test public void Test4100311() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance(); cal.set(YEAR, 1997); @@ -593,10 +592,8 @@ public class CalendarRegression { @Test public void Test4103271() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); SimpleDateFormat sdf = new SimpleDateFormat(); int numYears = 40, startYear = 1997, numDays = 15; @@ -833,10 +830,8 @@ public class CalendarRegression { @Test public void Test4114578() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); int ONE_HOUR = 60 * 60 * 1000; TimeZone saveZone = TimeZone.getDefault(); @@ -921,10 +916,8 @@ public class CalendarRegression { @Test public void Test4125881() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance(); DateFormat fmt = new SimpleDateFormat("MMMM d, yyyy G"); @@ -947,10 +940,8 @@ public class CalendarRegression { @Test public void Test4125892() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance(); DateFormat fmt = new SimpleDateFormat("MMMM d, yyyy G"); @@ -1373,10 +1364,8 @@ public class CalendarRegression { @Test public void Test4173516() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); int[][] fieldsList = { {1997, FEBRUARY, 1, 10, 45, 15, 900}, @@ -1852,11 +1841,10 @@ public class CalendarRegression { @Test public void Test4685354() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale) - || !TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); Calendar calendar = Calendar.getInstance(Locale.US); DateFormat df = new SimpleDateFormat("yyyy/MM/dd", Locale.US); @@ -1961,10 +1949,8 @@ public class CalendarRegression { @Test public void Test4655637() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); Calendar cal = Calendar.getInstance(); cal.setTime(new Date(1029814211523L)); diff --git a/test/jdk/java/util/Calendar/CalendarTest.java b/test/jdk/java/util/Calendar/CalendarTest.java index 5092c6adec0..0b50b07179d 100644 --- a/test/jdk/java/util/Calendar/CalendarTest.java +++ b/test/jdk/java/util/Calendar/CalendarTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ import java.util.TimeZone; import static java.util.Calendar.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -223,10 +224,8 @@ public class CalendarTest { @Test public void TestGenericAPI() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); String str; Date when = new Date(90, APRIL, 15); @@ -625,10 +624,8 @@ public class CalendarTest { @Test public void TestGMTvsLocal4064654() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); // Sample output 1: // % /usr/local/java/jdk1.1.3/solaris/bin/java test 1997 1 1 12 0 0 diff --git a/test/jdk/java/util/Calendar/bug4409072.java b/test/jdk/java/util/Calendar/bug4409072.java index 617550fe1aa..132934daa98 100644 --- a/test/jdk/java/util/Calendar/bug4409072.java +++ b/test/jdk/java/util/Calendar/bug4409072.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.util.*; import static java.util.Calendar.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -44,10 +45,8 @@ public class bug4409072 { @Test public void Test4409072() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); Locale savedLocale = Locale.getDefault(); TimeZone savedTZ = TimeZone.getDefault(); diff --git a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java index 12f5a96d3fb..07cc7a412b6 100644 --- a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java +++ b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java @@ -25,9 +25,9 @@ * @test * @bug 8025703 8040211 8191404 8203872 8222980 8225435 8241082 8242010 8247432 * 8258795 8267038 8287180 8302512 8304761 8306031 8308021 8313702 8318322 - * 8327631 8332424 8334418 8344589 8348328 + * 8327631 8332424 8334418 8344589 8348328 8362428 * @summary Checks the IANA language subtag registry data update - * (LSR Revision: 2025-05-15) with Locale and Locale.LanguageRange + * (LSR Revision: 2025-08-25) with Locale and Locale.LanguageRange * class methods. * @run main LanguageSubtagRegistryTest */ diff --git a/test/jdk/java/util/Locale/LocaleCategory.java b/test/jdk/java/util/Locale/LocaleCategory.java index ed63203916a..ec4277d43c0 100644 --- a/test/jdk/java/util/Locale/LocaleCategory.java +++ b/test/jdk/java/util/Locale/LocaleCategory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,14 +29,17 @@ * @library /java/text/testlib * @build TestUtils LocaleCategory * @comment test user.xxx.display user.xxx.format properties - * @run main/othervm -Duser.language.display=ja + * @run junit/othervm -Duser.language.display=ja * -Duser.language.format=zh LocaleCategory * @comment test user.xxx properties overriding user.xxx.display/format - * @run main/othervm -Duser.language=en + * @run junit/othervm -Duser.language=en * -Duser.language.display=ja * -Duser.language.format=zh LocaleCategory */ +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; + import java.util.Locale; public class LocaleCategory { @@ -44,12 +47,11 @@ public class LocaleCategory { private static Locale disp = null; private static Locale fmt = null; - public static void main(String[] args) { + @Test + void test() { Locale reservedLocale = Locale.getDefault(); - if (TestUtils.hasSpecialVariant(reservedLocale)) { - System.out.println("Skipping this test because locale is " + reservedLocale); - return; - } + Assumptions.assumeFalse(TestUtils.hasSpecialVariant(reservedLocale), + reservedLocale + " has special variant"); try { Locale.Builder builder = new Locale.Builder(); diff --git a/test/jdk/java/util/TimeZone/TimeZoneRegression.java b/test/jdk/java/util/TimeZone/TimeZoneRegression.java index 241afd3f7cf..c1b1b98369e 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneRegression.java +++ b/test/jdk/java/util/TimeZone/TimeZoneRegression.java @@ -34,6 +34,7 @@ import java.util.*; import java.io.*; import java.text.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -164,10 +165,8 @@ public class TimeZoneRegression { @Test public void Test4109314() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); // test both SimpleTimeZone and ZoneInfo objects. // @since 1.4 @@ -292,10 +291,8 @@ public class TimeZoneRegression { @Test public void Test4126678() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); // Note: this test depends on the PST time zone. TimeZone initialZone = TimeZone.getDefault(); diff --git a/test/jdk/javax/swing/JList/JListTest.java b/test/jdk/javax/swing/JList/JListTest.java new file mode 100644 index 00000000000..fbc9bda69e3 --- /dev/null +++ b/test/jdk/javax/swing/JList/JListTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8364146 + * @key headful + * @summary Verifies JList getScrollableUnitIncrement return non-negative number + * @run main JListTest + */ + +import java.awt.Dimension; +import java.awt.Rectangle; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +public class JListTest { + + private static JFrame f; + + public static void main(String[] argv) throws Exception { + + SwingUtilities.invokeAndWait(() -> { + try { + f = new JFrame(); + String[] data = {"One", "Two", "Three", "Four", "Five", "Six ", + "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelv"}; + JList list = new JList<>(data); + list.setLayoutOrientation(JList.HORIZONTAL_WRAP); + + JScrollPane sp = new JScrollPane(list); + sp.setPreferredSize(new Dimension(200, 200)); + f.add(sp); + f.pack(); + f.setVisible(true); + + Rectangle cell = list.getCellBounds(1, data.length); + System.out.println(cell); + cell.y = list.getHeight() + 10; + int unit = list.getScrollableUnitIncrement( + cell, + SwingConstants.VERTICAL, + -1); + System.out.println("Scrollable unit increment: " + unit); + + if (unit < 0) { + throw new RuntimeException("JList scrollable unit increment should be greater than 0."); + } + unit = list.getScrollableUnitIncrement( + cell, + SwingConstants.VERTICAL, + 1); + System.out.println("Scrollable unit increment: " + unit); + if (unit < 0) { + throw new RuntimeException("JList scrollable unit increment should be greater than 0."); + } + } finally { + if (f != null) { + f.dispose(); + } + } + }); + } +} diff --git a/test/jdk/javax/swing/JTree/JTreeUpdateTest.java b/test/jdk/javax/swing/JTree/JTreeUpdateTest.java new file mode 100644 index 00000000000..6b0a4f03c29 --- /dev/null +++ b/test/jdk/javax/swing/JTree/JTreeUpdateTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8042054 + * @summary JTree.updateUI should use updated item size information + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual JTreeUpdateTest + */ + +import java.awt.BorderLayout; +import java.awt.Dimension; +import javax.swing.BorderFactory; +import javax.swing.JFrame; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.UIManager; + +public class JTreeUpdateTest { + + static final String INSTRUCTIONS = """ + A frame with two identical JTrees is shown. + If the left JTree's text is abbreviated and JTree items + are cramped with little space between rows then press Fail. + If the left JTree is identical with right JTree, press Pass. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JTreeUpdateTest Test instructions") + .instructions(INSTRUCTIONS) + .columns(30) + .testUI(JTreeUpdateTest::createUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + setLaf("javax.swing.plaf.metal.MetalLookAndFeel"); + + final JFrame frame = new JFrame("JTreeUpdateTest"); + + final JTree tree = new JTree(); + tree.setPreferredSize(new Dimension(200, 200)); + tree.setCellRenderer(new DefaultTreeCellRenderer()); + tree.setBorder(BorderFactory.createTitledBorder("updateUI() called once")); + frame.add(tree); + + final JTree tree2 = new JTree(); + tree2.setPreferredSize(new Dimension(200, 200)); + tree2.setCellRenderer(new DefaultTreeCellRenderer()); + tree2.setBorder(BorderFactory.createTitledBorder("updateUI() called twice")); + frame.add(tree2, BorderLayout.EAST); + + frame.pack(); + frame.setLocationRelativeTo(null); + + SwingUtilities.invokeLater(() -> { + setLaf("javax.swing.plaf.nimbus.NimbusLookAndFeel"); + SwingUtilities.updateComponentTreeUI(frame); + SwingUtilities.updateComponentTreeUI(tree2); + }); + return frame; + } + + private static void setLaf(String className) { + try { + UIManager.setLookAndFeel(className); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java b/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java index 9a531d692ed..bfc628a25fc 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022, Red Hat, Inc. - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @run main/timeout=360 TestDockerBasic */ @@ -42,10 +43,8 @@ public class TestDockerBasic { private static final String imageName = Common.imageName("javaDockerBasic"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java b/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java index ff039913b8f..042996a353b 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,9 +46,8 @@ public class TestDockerCpuMetrics { private static final String imageName = Common.imageName("metrics-cpu"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); // These tests create a docker image and run this image with // varying docker cpu options. The arguments passed to the docker diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java index 2afb5ed93b1..818c2c04a1d 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java @@ -45,9 +45,8 @@ public class TestDockerMemoryMetrics { private static final String imageName = Common.imageName("metrics-memory"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); // These tests create a docker image and run this image with // varying docker memory options. The arguments passed to the docker diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java index f9dd405891c..7d5dbca6f7c 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java @@ -58,10 +58,7 @@ public class TestDockerMemoryMetricsSubgroup { System.out.println("Cgroup not configured."); return; } - if (!DockerTestUtils.canTestDocker()) { - System.out.println("Unable to run docker tests."); - return; - } + DockerTestUtils.checkCanTestDocker(); ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); diff --git a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java index dc70fe32b16..1e5160330de 100644 --- a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java @@ -29,9 +29,11 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build GetFreeSwapSpaceSize * @run driver/timeout=480 TestGetFreeSwapSpaceSize */ + import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; @@ -41,10 +43,8 @@ public class TestGetFreeSwapSpaceSize { private static final String imageName = Common.imageName("osbeanSwapSpace"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java index e4decb7f903..a3df580fed1 100644 --- a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java +++ b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java @@ -55,10 +55,8 @@ public class TestLimitsUpdating { private static final String imageName = Common.imageName("limitsUpdatingJDK"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java index 033562b3951..87ecae7ee62 100644 --- a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java +++ b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java @@ -30,6 +30,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build TestPidsLimit * @run driver/timeout=480 TestPidsLimit */ @@ -49,10 +50,8 @@ public class TestPidsLimit { private static final int UNLIMITED_PIDS_DOCKER = -1; public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java index 49ec5663478..e6e78bd5cd8 100644 --- a/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java @@ -42,10 +42,7 @@ public class TestSystemMetrics { private static final String imageName = Common.imageName("metrics"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java b/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java index d8d300401a0..e77783f395b 100644 --- a/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java +++ b/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java @@ -42,10 +42,7 @@ public class TestUseContainerSupport { private static final String imageName = Common.imageName("useContainerSupport"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/jfr/api/recording/dump/TestDumpOverwrite.java b/test/jdk/jdk/jfr/api/recording/dump/TestDumpOverwrite.java new file mode 100644 index 00000000000..050b68eb538 --- /dev/null +++ b/test/jdk/jdk/jfr/api/recording/dump/TestDumpOverwrite.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.api.recording.dump; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingFile; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.SimpleEventHelper; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Test that multiple dumps to the same file by ongoing recordings do not mangle data. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.api.recording.dump.TestDumpOverwrite + */ +public class TestDumpOverwrite { + private static Path DUMP_PATH = Paths.get(".", "rec_TestDumpOverwrite.jfr"); + public static void main(String[] args) throws Exception { + Recording recording1 = new Recording(); + Recording recording2 = new Recording(); + SimpleEventHelper.enable(recording1, true); + SimpleEventHelper.enable(recording2, true); + recording1.setDestination(DUMP_PATH); + recording2.setDestination(DUMP_PATH); + + int actualId = 0; + recording1.start(); + SimpleEventHelper.createEvent(actualId++); + recording2.start(); + SimpleEventHelper.createEvent(actualId++); + // This is results in the initial write to the dump destination + recording2.stop(); + SimpleEventHelper.createEvent(actualId++); + recording2.close(); + SimpleEventHelper.createEvent(actualId++); + // This should first wipe the data previously written by recording2. + recording1.stop(); + recording1.close(); + + Asserts.assertTrue(Files.exists(DUMP_PATH), "Recording file does not exist: " + DUMP_PATH); + + // Verify events are read in order without duplicates (otherwise chunks may be out of order). + // If the dump file is not being overwritten correctly, we will see event ids: 1, 0, 1, 2, 3. + int expectedId = 0; + for (RecordedEvent event : RecordingFile.readAllEvents(DUMP_PATH)) { + Events.assertField(event, "id").equal(expectedId++); + } + Asserts.assertTrue(expectedId == actualId, "incorrect number of events found"); + } +} diff --git a/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java b/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java index b0522741a1e..74fb8e71e87 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java @@ -70,6 +70,8 @@ public final class TestClassDefineEvent { "Expected type " + cl.getClass().getName() + ", got type " + definingClassLoaderType.getName()); Asserts.assertEquals(cl.getName(), definingClassLoader.getName(), "Defining Class Loader should have the same name as the original class loader"); + Asserts.assertTrue(event.getString("source").startsWith("file:/"), "Invalid source location"); + Asserts.assertTrue(event.getString("source").endsWith(TEST_CLASS_NAME.substring(TEST_CLASS_NAME.lastIndexOf('.') + 1) + ".class"), "Invalid source location"); foundTestClasses = true; } } diff --git a/test/jdk/jdk/modules/etc/JmodExcludedFiles.java b/test/jdk/jdk/modules/etc/JmodExcludedFiles.java index 90ca6840d52..3929419a080 100644 --- a/test/jdk/jdk/modules/etc/JmodExcludedFiles.java +++ b/test/jdk/jdk/modules/etc/JmodExcludedFiles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,12 @@ * @test * @bug 8159927 * @modules java.base/jdk.internal.util + * @library /test/lib * @requires jlink.packagedModules - * @run main JmodExcludedFiles - * @summary Test that JDK JMOD files do not include native debug symbols + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JmodExcludedFiles + * @summary Test that JDK JMOD files do not include native debug symbols when it is not configured */ import java.nio.file.DirectoryStream; @@ -37,9 +40,11 @@ import java.nio.file.Paths; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import jdk.internal.util.OperatingSystem; +import jdk.test.whitebox.WhiteBox; public class JmodExcludedFiles { private static String javaHome = System.getProperty("java.home"); + private static final boolean expectSymbols = WhiteBox.getWhiteBox().shipsDebugInfo(); public static void main(String[] args) throws Exception { Path jmods = Path.of(javaHome, "jmods"); @@ -76,24 +81,19 @@ public class JmodExcludedFiles { if (i != -1) { if (n.substring(0, i).endsWith(".dSYM")) { System.err.println("Found symbols in " + jmod + ": " + name); - return true; + return expectSymbols ? false: true; } } } if (OperatingSystem.isWindows() && name.endsWith(".pdb")) { - // on Windows we check if we should have public symbols through --with-external-symbols-in-bundles=public (JDK-8237192) - String strippedpdb = javaHome + "/bin/" + name.substring(index + 1, name.length() - 4) + ".stripped.pdb"; - if (!Files.exists(Paths.get(strippedpdb))) { - System.err.println("Found symbols in " + jmod + ": " + name + - ". No stripped pdb file " + strippedpdb + " exists."); - return true; - } + System.err.println("Found symbols in " + jmod + ": " + name); + return expectSymbols ? false: true; } if (name.endsWith(".diz") || name.endsWith(".debuginfo") || name.endsWith(".map")) { System.err.println("Found symbols in " + jmod + ": " + name); - return true; + return expectSymbols ? false: true; } } return false; diff --git a/test/jdk/sun/security/pkcs11/Signature/InitAgainPSS.java b/test/jdk/sun/security/pkcs11/Signature/InitAgainPSS.java index a2fa7294977..1acf6c250ef 100644 --- a/test/jdk/sun/security/pkcs11/Signature/InitAgainPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/InitAgainPSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,8 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import java.security.*; -import java.security.spec.*; +import jtreg.SkippedException; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Signature; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; /** * @test @@ -46,9 +53,7 @@ public class InitAgainPSS extends PKCS11Test { try { s1 = Signature.getInstance(sigAlg, p); } catch (NoSuchAlgorithmException e) { - System.out.println("Skip testing " + sigAlg + - " due to no support"); - return; + throw new SkippedException("No support " + sigAlg); } byte[] msg = "hello".getBytes(); diff --git a/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java b/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java index adf7a08908e..45e26ec3930 100644 --- a/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,9 +20,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import java.security.*; -import java.security.interfaces.*; -import java.security.spec.*; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; +import java.util.ArrayList; +import java.util.List; import jtreg.SkippedException; @@ -43,7 +52,7 @@ public class KeyAndParamCheckForPSS extends PKCS11Test { main(new KeyAndParamCheckForPSS(), args); } - private static boolean skipTest = true; + private static final List skippedAlgs = new ArrayList<>(); @Override public void main(Provider p) throws Exception { @@ -73,8 +82,8 @@ public class KeyAndParamCheckForPSS extends PKCS11Test { runTest(p, 1040, "SHA3-512", "SHA3-384"); runTest(p, 1040, "SHA3-512", "SHA3-512"); - if (skipTest) { - throw new SkippedException("Test Skipped"); + if (!skippedAlgs.isEmpty()) { + throw new SkippedException("Tests Skipped: " + skippedAlgs); } } @@ -84,7 +93,17 @@ public class KeyAndParamCheckForPSS extends PKCS11Test { System.out.println("Testing " + hashAlg + " and MGF1" + mgfHashAlg); PSSUtil.AlgoSupport s = PSSUtil.isHashSupported(p, hashAlg, mgfHashAlg); if (s == PSSUtil.AlgoSupport.NO) { - System.out.println("=> Skip; no support"); + System.out.printf("=> Skip; no support keysize: %d, hash alg: %s, mgf Hash Alg: %s%n", + keySize, + hashAlg, + mgfHashAlg); + skippedAlgs.add( + String.format( + "[keysize: %s, hash alg: %s, mgf Hash Alg: %s]", + keySize, + hashAlg, + mgfHashAlg) + ); return; } @@ -108,7 +127,6 @@ public class KeyAndParamCheckForPSS extends PKCS11Test { sig.setParameter(paramsGood); sig.initSign(priv); // algorithm support confirmed - skipTest = false; } catch (Exception ex) { if (s == PSSUtil.AlgoSupport.MAYBE) { // confirmed to be unsupported; skip the rest of the test diff --git a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java index d5b22400bff..c9efa8fdf76 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,9 +21,15 @@ * questions. */ -import java.security.*; -import java.security.spec.*; -import java.security.interfaces.*; +import jtreg.SkippedException; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Signature; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; /* * @test @@ -53,9 +59,7 @@ public class SigInteropPSS extends PKCS11Test { try { sigPkcs11 = Signature.getInstance("RSASSA-PSS", p); } catch (NoSuchAlgorithmException e) { - System.out.println("Skip testing RSASSA-PSS" + - " due to no support"); - return; + throw new SkippedException("No support for RSASSA-PSS"); } Signature sigSunRsaSign = diff --git a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java index dfe56167848..ca0368841c5 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,9 +21,16 @@ * questions. */ -import java.security.*; -import java.security.spec.*; -import java.security.interfaces.*; +import jtreg.SkippedException; + +import java.security.AlgorithmParameters; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.security.Signature; +import java.security.spec.PSSParameterSpec; /* * @test @@ -67,9 +74,7 @@ public class SigInteropPSS2 extends PKCS11Test { try { sigPkcs11 = Signature.getInstance(digest + "withRSASSA-PSS", p); } catch (NoSuchAlgorithmException e) { - System.out.println("Skip testing " + digest + "withRSASSA-PSS" + - " due to no support"); - continue; + throw new SkippedException("No support for " + digest + "withRSASSA-PSS"); } runTest(sigPkcs11, sigSunRsaSign, kp); diff --git a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java index c87554a51b1..778a7758562 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,29 +20,55 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import java.security.*; -import java.security.interfaces.*; -import java.security.spec.*; -import java.util.stream.IntStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; +import java.util.ArrayList; +import java.util.List; + import jtreg.SkippedException; /** - * @test + * @test id=sha * @bug 8080462 8226651 8242332 * @summary Generate a RSASSA-PSS signature and verify it using PKCS11 provider * @library /test/lib .. * @modules jdk.crypto.cryptoki * @run main SignatureTestPSS */ + +/** + * @test id=sha3 + * @bug 8080462 8226651 8242332 + * @summary Generate a RSASSA-PSS signature and verify it using PKCS11 provider + * @library /test/lib .. + * @modules jdk.crypto.cryptoki + * @run main SignatureTestPSS sha3 + */ public class SignatureTestPSS extends PKCS11Test { private static final String SIGALG = "RSASSA-PSS"; private static final int[] KEYSIZES = { 2048, 3072 }; - private static final String[] DIGESTS = { + + private static String[] DIGESTS = null; + + private static final String[] SHA_DIGESTS = { "SHA-224", "SHA-256", "SHA-384" , "SHA-512", - "SHA3-224", "SHA3-256", "SHA3-384" , "SHA3-512", }; + private static final String[] SHA3_DIGESTS = { + "SHA3-224", "SHA3-256", "SHA3-384" , "SHA3-512" + }; + private static final byte[] DATA = generateData(100); /** @@ -55,9 +81,12 @@ public class SignatureTestPSS extends PKCS11Test { */ private static final int UPDATE_TIMES_HUNDRED = 100; - private static boolean skipTest = true; + private static final List skippedAlgs = new ArrayList<>(); public static void main(String[] args) throws Exception { + DIGESTS = (args.length > 0 && "sha3".equals(args[0])) ? + SHA3_DIGESTS : SHA_DIGESTS; + main(new SignatureTestPSS(), args); } @@ -80,6 +109,8 @@ public class SignatureTestPSS extends PKCS11Test { PSSUtil.isHashSupported(p, hash, mgfHash); if (s == PSSUtil.AlgoSupport.NO) { System.out.println(" => Skip; no support"); + skippedAlgs.add("[Hash = " + hash + + ", MGF1 Hash = " + mgfHash + "]"); continue; } checkSignature(p, DATA, pubKey, privKey, hash, mgfHash, s); @@ -87,17 +118,15 @@ public class SignatureTestPSS extends PKCS11Test { }; } - // start testing below - if (skipTest) { - throw new SkippedException("Test Skipped"); + if (!skippedAlgs.isEmpty()) { + throw new SkippedException("Test Skipped :" + skippedAlgs); } } private static void checkSignature(Provider p, byte[] data, PublicKey pub, PrivateKey priv, String hash, String mgfHash, PSSUtil.AlgoSupport s) throws NoSuchAlgorithmException, InvalidKeyException, - SignatureException, NoSuchProviderException, - InvalidAlgorithmParameterException { + SignatureException { // only test RSASSA-PSS signature against the supplied hash/mgfHash // if they are supported; otherwise PKCS11 library will throw @@ -112,14 +141,27 @@ public class SignatureTestPSS extends PKCS11Test { } catch (InvalidAlgorithmParameterException iape) { if (s == PSSUtil.AlgoSupport.MAYBE) { // confirmed to be unsupported; skip the rest of the test - System.out.println(" => Skip; no PSS support"); + System.out.printf(" => Skip; no PSS support public key: %s, private key: %s, " + + "hash: %s, mgf hash: %s, Algo Support: %s%n", + pub, + priv, + hash, + mgfHash, + s); + skippedAlgs.add(String.format( + "[public key: %s, private key: %s, " + + "hash: %s, mgf hash: %s, Algo Support: %s]", + pub, + priv, + hash, + mgfHash, + s) + ); return; } else { throw new RuntimeException("Unexpected Exception", iape); } } - // start testing below - skipTest = false; for (int i = 0; i < UPDATE_TIMES_HUNDRED; i++) { sig.update(data); diff --git a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS2.java b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS2.java index 516b17972e5..ac6c13523a2 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS2.java +++ b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,13 +20,23 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import java.security.*; -import java.security.interfaces.*; -import java.security.spec.*; +import jtreg.SkippedException; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; import java.util.stream.IntStream; /** - * @test + * @test id=sha * @bug 8244154 8242332 * @summary Generate a withRSASSA-PSS signature and verify it using * PKCS11 provider @@ -34,13 +44,28 @@ import java.util.stream.IntStream; * @modules jdk.crypto.cryptoki * @run main SignatureTestPSS2 */ + +/** + * @test id=sha3 + * @bug 8244154 8242332 + * @summary Generate a withRSASSA-PSS signature and verify it using + * PKCS11 provider + * @library /test/lib .. + * @modules jdk.crypto.cryptoki + * @run main SignatureTestPSS2 sha3 + */ public class SignatureTestPSS2 extends PKCS11Test { // PKCS11 does not support RSASSA-PSS keys yet private static final String KEYALG = "RSA"; - private static final String[] SIGALGS = { + + private static String[] SIGALGS = null; + + private static final String[] SHA_SIGALGS = { "SHA224withRSASSA-PSS", "SHA256withRSASSA-PSS", - "SHA384withRSASSA-PSS", "SHA512withRSASSA-PSS", + "SHA384withRSASSA-PSS", "SHA512withRSASSA-PSS" + }; + private static final String[] SHA3_SIGALGS = { "SHA3-224withRSASSA-PSS", "SHA3-256withRSASSA-PSS", "SHA3-384withRSASSA-PSS", "SHA3-512withRSASSA-PSS" }; @@ -53,6 +78,8 @@ public class SignatureTestPSS2 extends PKCS11Test { private static final int UPDATE_TIMES = 2; public static void main(String[] args) throws Exception { + SIGALGS = (args.length > 0 && "sha3".equals(args[0])) ? SHA3_SIGALGS : SHA_SIGALGS; + main(new SignatureTestPSS2(), args); } @@ -63,9 +90,7 @@ public class SignatureTestPSS2 extends PKCS11Test { try { sig = Signature.getInstance(sa, p); } catch (NoSuchAlgorithmException e) { - System.out.println("Skip testing " + sa + - " due to no support"); - return; + throw new SkippedException("No support for " + sa); } for (int i : KEYSIZES) { runTest(sig, i); @@ -94,7 +119,7 @@ public class SignatureTestPSS2 extends PKCS11Test { SignatureException | NoSuchProviderException ex) { throw new RuntimeException(ex); } catch (InvalidAlgorithmParameterException ex2) { - System.out.println("Skip test due to " + ex2); + throw new SkippedException(ex2.toString()); } } diff --git a/test/jdk/sun/security/pkcs11/Signature/TestDSA.java b/test/jdk/sun/security/pkcs11/Signature/TestDSA.java index e7b937d6190..0a086bd2ed0 100644 --- a/test/jdk/sun/security/pkcs11/Signature/TestDSA.java +++ b/test/jdk/sun/security/pkcs11/Signature/TestDSA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ * @run main/othervm TestDSA */ +import jtreg.SkippedException; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; @@ -122,8 +124,7 @@ public class TestDSA extends PKCS11Test { System.out.println("Testing provider " + provider + "..."); if (provider.getService("Signature", "SHA1withDSA") == null) { - System.out.println("DSA not supported, skipping"); - return; + throw new SkippedException("DSA not supported"); } KeyFactory kf = KeyFactory.getInstance("DSA", provider); diff --git a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java index ea04b3c7eec..1e9faf7fb74 100644 --- a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java +++ b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java @@ -28,13 +28,6 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; import java.util.HexFormat; -/* - * @test - * @library /test/lib - * @key randomness - * @modules java.base/sun.security.provider:+open - * @run main/othervm ML_DSA_Intrinsic_Test -XX:+UnlockDiagnosticVMOptions -XX:-UseDilithiumIntrinsics - */ /* * @test * @requires os.simpleArch == "x64" @@ -45,6 +38,8 @@ import java.util.HexFormat; */ /* * @test + * @comment This test should be reenabled on aarch64 + * @requires os.simpleArch == "x64" * @library /test/lib * @key randomness * @modules java.base/sun.security.provider:+open @@ -55,7 +50,7 @@ import java.util.HexFormat; // -XX:+UnlockDiagnosticVMOptions -XX:+UseDilithiumIntrinsics test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java public class ML_DSA_Intrinsic_Test { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); Class kClazz = sun.security.provider.ML_DSA.class; @@ -114,33 +109,29 @@ public class ML_DSA_Intrinsic_Test { long seed = rnd.nextLong(); rnd.setSeed(seed); //Note: it might be useful to increase this number during development of new intrinsics - final int repeat = 10000000; + final int repeat = 10000; int[] coeffs1 = new int[ML_DSA_N]; int[] coeffs2 = new int[ML_DSA_N]; int[] prod1 = new int[ML_DSA_N]; int[] prod2 = new int[ML_DSA_N]; int[] prod3 = new int[ML_DSA_N]; int[] prod4 = new int[ML_DSA_N]; - try { - for (int i = 0; i < repeat; i++) { - // Hint: if test fails, you can hardcode the seed to make the test more reproducible: - // rnd.setSeed(seed); - testMult(prod1, prod2, coeffs1, coeffs2, mult, multJava, rnd, seed, i); - testMultConst(prod1, prod2, multConst, multConstJava, rnd, seed, i); - testDecompose(prod1, prod2, prod3, prod4, coeffs1, coeffs2, decompose, decomposeJava, rnd, seed, i); - testAlmostNtt(coeffs1, coeffs2, almostNtt, almostNttJava, rnd, seed, i); - testInverseNtt(coeffs1, coeffs2, inverseNtt, inverseNttJava, rnd, seed, i); - } - System.out.println("Fuzz Success"); - } catch (Throwable e) { - System.out.println("Fuzz Failed: " + e); + for (int i = 0; i < repeat; i++) { + // Hint: if test fails, you can hardcode the seed to make the test more reproducible: + // rnd.setSeed(seed); + testMult(prod1, prod2, coeffs1, coeffs2, mult, multJava, rnd, seed, i); + testMultConst(prod1, prod2, multConst, multConstJava, rnd, seed, i); + testDecompose(prod1, prod2, prod3, prod4, coeffs1, coeffs2, decompose, decomposeJava, rnd, seed, i); + testAlmostNtt(coeffs1, coeffs2, almostNtt, almostNttJava, rnd, seed, i); + testInverseNtt(coeffs1, coeffs2, inverseNtt, inverseNttJava, rnd, seed, i); } + System.out.println("Fuzz Success"); } private static final int ML_DSA_N = 256; public static void testMult(int[] prod1, int[] prod2, int[] coeffs1, int[] coeffs2, MethodHandle mult, MethodHandle multJava, Random rnd, - long seed, int i) throws Exception, Throwable { + long seed, int i) throws Throwable { for (int j = 0; j { + try { + runServer(disabledInClient); + } catch (Exception exc) { + System.out.println("Server Exception:"); + exc.printStackTrace(System.out); + serverException = exc; + throw new RuntimeException(exc); + } + }); + + if (!waitForServer.await(WAIT_FOR_SERVER_SECS, TimeUnit.SECONDS)) { + throw new Exception("Server did not start within " + + WAIT_FOR_SERVER_SECS + " seconds."); + } + + System.out.printf("Server listening on port %d.%nStarting client process...", + serverPort); + + OutputAnalyzer oa = ProcessTools.executeProcess( + ProcessTools.createTestJavaProcessBuilder("DisabledCipherSuitesNotNegotiated", + "" + disabledInClient, "" + serverPort)); + oa.shouldHaveExitValue(0); + System.out.println("Client output:"); + System.out.println(oa.getOutput()); + if (serverException != null) { + throw new Exception ("Server-side threw an unexpected exception: " + + serverException); + } + } + + } else if (args.length == 2) { + // run client-side + boolean disabledInClient = Boolean.parseBoolean(args[0]); + if (disabledInClient) { + SecurityUtils.addToDisabledTlsAlgs(DISABLED_CIPHER_WILDCARD); + } + runClient(Boolean.parseBoolean(args[0]), Integer.parseInt(args[1])); + + } else { + throw new Exception( + "DisabledCipherSuitesNotNegotiated called with invalid arguments"); + } + } + +} diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java index 65311e97701..5a704ef4d1f 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java @@ -60,7 +60,6 @@ import java.util.Arrays; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.Utils; public class SSLEngineKeyLimit extends SSLContextTemplate { @@ -119,9 +118,7 @@ public class SSLEngineKeyLimit extends SSLContextTemplate { System.getProperty("test.java.opts")); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("SSLEngineKeyLimit", "p", args[1], - args[2])); - + "SSLEngineKeyLimit", "p", args[1], args[2]); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { output.shouldContain(String.format( diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java index d6cdbf2e015..1c9c259c38d 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java @@ -37,7 +37,6 @@ * @run main/othervm MultiNSTClient -Djdk.tls.client.protocols=TLSv1.2 -Djdk.tls.server.enableSessionTicketExtension=true -Djdk.tls.client.enableSessionTicketExtension=true */ -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -77,8 +76,7 @@ public class MultiNSTClient { System.out.println("test.java.opts: " + System.getProperty("test.java.opts")); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("MultiNSTClient", "p")); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("MultiNSTClient", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); boolean pass = true; diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java index 41f6ec0ada4..a851a5d72bb 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java @@ -31,7 +31,6 @@ * @run main/othervm MultiNSTNoSessionCreation -Djdk.tls.client.protocols=TLSv1.2 -Djdk.tls.server.newSessionTicketCount=0 */ -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -61,7 +60,7 @@ public class MultiNSTNoSessionCreation { System.getProperty("test.java.opts")); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("MultiNSTNoSessionCreation", "p")); + "MultiNSTNoSessionCreation", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java index 32ee7db7b4b..a2609130e0b 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java @@ -30,7 +30,6 @@ * @run main/othervm MultiNSTParallel 10 -Djdk.tls.client.protocols=TLSv1.3 */ -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -116,8 +115,7 @@ public class MultiNSTParallel { System.out.println("test.java.opts: " + System.getProperty("test.java.opts")); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("MultiNSTParallel", "p")); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("MultiNSTParallel", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java index 125b006055b..b63ebc5ec1e 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java @@ -30,7 +30,6 @@ * @run main/othervm MultiNSTSequence -Djdk.tls.server.newSessionTicketCount=2 */ -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -69,8 +68,7 @@ public class MultiNSTSequence { System.out.println("test.java.opts: " + System.getProperty("test.java.opts")); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("MultiNSTSequence", "p")); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("MultiNSTSequence", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); boolean pass = true; diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java index 87db7eed296..2784875d426 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java @@ -45,7 +45,6 @@ import javax.net.ssl.SSLSocketFactory; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.Utils; public class ResumptionUpdateBoundValues extends SSLContextTemplate { @@ -188,7 +187,7 @@ public class ResumptionUpdateBoundValues extends SSLContextTemplate { System.getProperty("test.java.opts")); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("ResumptionUpdateBoundValues", "p")); + "ResumptionUpdateBoundValues", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java index fc26b60e4d4..7ce4d97a7a2 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java @@ -68,7 +68,6 @@ import java.util.Arrays; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.Utils; import jdk.test.lib.hexdump.HexPrinter; public class SSLSocketKeyLimit { @@ -135,8 +134,7 @@ public class SSLSocketKeyLimit { System.getProperty("test.java.opts")); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("SSLSocketKeyLimit", "p", args[1], - args[2])); + "SSLSocketKeyLimit", "p", args[1], args[2]); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { diff --git a/test/jdk/tools/jar/ReproducibleJar.java b/test/jdk/tools/jar/ReproducibleJar.java index ed5e2ed2ae3..5f59d1cbe41 100644 --- a/test/jdk/tools/jar/ReproducibleJar.java +++ b/test/jdk/tools/jar/ReproducibleJar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,7 +66,9 @@ public class ReproducibleJar { private static final TimeZone TZ = TimeZone.getDefault(); private static final boolean DST = TZ.inDaylightTime(new Date()); private static final String UNIX_2038_ROLLOVER_TIME = "2038-01-19T03:14:07Z"; + private static final String UNIX_EPOCH_TIME = "1970-01-01T00:00:00Z"; private static final Instant UNIX_2038_ROLLOVER = Instant.parse(UNIX_2038_ROLLOVER_TIME); + private static final Instant UNIX_EPOCH = Instant.parse(UNIX_EPOCH_TIME); private static final File DIR_OUTER = new File("outer"); private static final File DIR_INNER = new File(DIR_OUTER, "inner"); private static final File FILE_INNER = new File(DIR_INNER, "foo.txt"); @@ -231,12 +233,15 @@ public class ReproducibleJar { if (Math.abs(now - original) > PRECISION) { // If original time is after UNIX 2038 32bit rollover - // and the now time is exactly the rollover time, then assume + // and the now time is exactly the rollover time or UNIX epoch time, then assume // running on a file system that only supports to 2038 (e.g.XFS) and pass test - if (FileTime.fromMillis(original).toInstant().isAfter(UNIX_2038_ROLLOVER) && - FileTime.fromMillis(now).toInstant().equals(UNIX_2038_ROLLOVER)) { - System.out.println("Checking file time after Unix 2038 rollover," + - " and extracted file time is " + UNIX_2038_ROLLOVER_TIME + ", " + + Instant originalInstant = FileTime.fromMillis(original).toInstant(); + Instant nowInstant = FileTime.fromMillis(now).toInstant(); + if (originalInstant.isAfter(UNIX_2038_ROLLOVER) && + (nowInstant.equals(UNIX_2038_ROLLOVER) || + nowInstant.equals(UNIX_EPOCH))) { + System.out.println("Checking file time after Unix 2038 rollover," + + " and extracted file time is " + nowInstant + ", " + " Assuming restricted file system, pass file time check."); } else { throw new AssertionError("checkFileTime failed," + diff --git a/test/jdk/tools/jlink/JLinkTest.java b/test/jdk/tools/jlink/JLinkTest.java index bc4d2a08800..1d84caaa147 100644 --- a/test/jdk/tools/jlink/JLinkTest.java +++ b/test/jdk/tools/jlink/JLinkTest.java @@ -42,10 +42,7 @@ import tests.JImageGenerator; /* * @test * @summary Test image creation - * @bug 8189777 - * @bug 8194922 - * @bug 8206962 - * @bug 8240349 + * @bug 8189777 8194922 8206962 8240349 8163382 8165735 8166810 8173717 8321139 * @author Jean-Francois Denise * @requires (vm.compMode != "Xcomp" & os.maxMemory >= 2g) * @library ../lib @@ -358,6 +355,39 @@ public class JLinkTest { helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level invalid"); } + // short command without argument + { + String[] userOptions = {"-c"}; + String moduleName = "invalidCompressLevelEmpty"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: no value given for -c"); + } + + // invalid short command + { + String[] userOptions = {"-c", "3", "--output", "image"}; + String moduleName = "invalidCompressLevel3"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level 3"); + } + + + // invalid argument value + { + String[] userOptions = {"--compress", "42", "--output", "image"}; + String moduleName = "invalidCompressLevel42"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level 42"); + } + + // invalid argument value + { + String[] userOptions = {"--compress", "zip-", "--output", "image"}; + String moduleName = "invalidCompressLevelZip"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level zip-"); + } + // orphan argument - JDK-8166810 { String[] userOptions = {"--compress", "2", "foo" }; diff --git a/test/jdk/tools/jlink/TaskHelperTest.java b/test/jdk/tools/jlink/TaskHelperTest.java index 51dea8de24a..26ac376a6ec 100644 --- a/test/jdk/tools/jlink/TaskHelperTest.java +++ b/test/jdk/tools/jlink/TaskHelperTest.java @@ -48,7 +48,7 @@ import jdk.tools.jlink.internal.TaskHelper.BadArgs; /* * @test * @summary Test TaskHelper option parsing - * @bug 8303884 + * @bug 8303884 8321139 * @modules jdk.jlink/jdk.tools.jlink.internal * jdk.jlink/jdk.tools.jlink.plugin * @run junit TaskHelperTest @@ -59,19 +59,22 @@ public class TaskHelperTest { private static final List> OPTIONS = List.of( new Option<>(true, (task, opt, arg) -> { - System.out.println(arg); mainArgValue = arg; }, true, "--main-expecting"), new Option<>(false, (task, opt, arg) -> { mainFlag = true; - }, true, "--main-no-arg") + }, true, "--main-no-arg"), + new Option<>(true, (task, opt, arg) -> { + compressArgValue = (arg != null && !arg.isEmpty()) ? arg : "zip-6"; + }, "--compress", "-c") ); private static String argValue; private static String mainArgValue; private static boolean mainFlag = false; + private static String compressArgValue; - public record ArgTestCase(String cmdLine, String[] tokens, String pluginArgValue, String mainArgValue, boolean mainFlagSet) {}; + public record ArgTestCase(String cmdLine, String[] tokens, String pluginArgValue, String mainArgValue, boolean mainFlagSet) {} public static class TestPluginWithRawOption implements Plugin { @Override @@ -118,6 +121,7 @@ public class TaskHelperTest { argValue = null; mainArgValue = null; mainFlag = false; + compressArgValue= null; } public static Stream gnuStyleUsages() { @@ -217,4 +221,41 @@ public class TaskHelperTest { var remaining = optionsHelper.handleOptions(this, args); assertEquals(2, remaining.size()); } -} \ No newline at end of file + + record CompressTestCase(String[] tokens, String expectedCompressValue) {} + + public static Stream compressUsages() { + return Stream.of( + + new CompressTestCase(new String[] {"-c", "0"}, "0"), + new CompressTestCase(new String[] {"--compress=zip-0"}, "zip-0"), + + new CompressTestCase(new String[] {"-c", "1"}, "1"), + new CompressTestCase(new String[] {"--compress=zip-1"}, "zip-1"), + + new CompressTestCase(new String[] {"-c", "2"}, "2"), + new CompressTestCase(new String[] {"--compress=zip-2"}, "zip-2"), + + new CompressTestCase(new String[] {"--compress=zip-3"}, "zip-3"), + new CompressTestCase(new String[] {"--compress=zip-4"}, "zip-4"), + new CompressTestCase(new String[] {"--compress=zip-5"}, "zip-5"), + new CompressTestCase(new String[] {"--compress=zip-6"}, "zip-6"), + new CompressTestCase(new String[] {"--compress=zip-7"}, "zip-7"), + new CompressTestCase(new String[] {"--compress=zip-8"}, "zip-8"), + new CompressTestCase(new String[] {"--compress=zip-9"}, "zip-9") + ); + } + + @ParameterizedTest + @MethodSource("compressUsages") + public void testCompressOptionArg(CompressTestCase testCase) throws TaskHelper.BadArgs, IOException { + var remaining = optionsHelper.handleOptions(this, testCase.tokens); + + // trigger Plugin::configure + taskHelper.getPluginsConfig(null, null, null); + + assertTrue(remaining.isEmpty()); + assertEquals(testCase.expectedCompressValue, compressArgValue); + } +} + diff --git a/test/langtools/jdk/javadoc/tool/testLocaleOption/TestSupportedLocales.java b/test/langtools/jdk/javadoc/tool/testLocaleOption/TestSupportedLocales.java new file mode 100644 index 00000000000..6d4e24f0c3a --- /dev/null +++ b/test/langtools/jdk/javadoc/tool/testLocaleOption/TestSupportedLocales.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8372708 + * @summary Javadoc ignores "-locale" and uses default locale for all messages and texts + * @library /tools/lib ../../lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestSupportedLocales + */ + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Locale; + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +public class TestSupportedLocales extends JavadocTester { + + public static void main(String... args) throws Exception { + var tester = new TestSupportedLocales(); + tester.runTests(); + } + + private final ToolBox tb = new ToolBox(); + + // A locale with an associated output message + record LocalizedOutput(Locale locale, String message) {} + + // Console messages are determined by the system default locale + private final LocalizedOutput[] consoleOutput = new LocalizedOutput[] { + new LocalizedOutput(Locale.CHINA, "\u6b63\u5728\u6784\u9020 Javadoc \u4fe1\u606f..."), + new LocalizedOutput(Locale.GERMANY, "Javadoc-Informationen werden erstellt..."), + new LocalizedOutput(Locale.JAPAN, "Javadoc\u60c5\u5831\u3092\u69cb\u7bc9\u3057\u3066\u3044\u307e\u3059..."), + new LocalizedOutput(Locale.US, "Constructing Javadoc information..."), + }; + + // Documentation messages are determined by the -locale option + private final LocalizedOutput[] documentationOutput = new LocalizedOutput[] { + new LocalizedOutput(Locale.CHINA, "\u7c7b\u548c\u63a5\u53e3"), + new LocalizedOutput(Locale.GERMANY, "Klassen und Schnittstellen"), + new LocalizedOutput(Locale.JAPAN, "\u30af\u30e9\u30b9\u3068\u30a4\u30f3\u30bf\u30d5\u30a7\u30fc\u30b9"), + new LocalizedOutput(Locale.US, "Classes and Interfaces"), + }; + + // Test all combinations of system and documentation locales + @Test + public void testSupportedLocales(Path base) throws Exception { + var src = base.resolve("src"); + initSource(src); + for (var console : consoleOutput) { + for (var documentation : documentationOutput) { + test(base, console, documentation); + } + } + } + + void test(Path base, LocalizedOutput console, LocalizedOutput documentation) throws Exception { + var src = base.resolve("src"); + var out = base.resolve(console.locale + "-" + documentation.locale); + Locale.setDefault(console.locale); + javadoc("-d", out.toString(), + "-locale", documentation.locale.toString(), + "--source-path", src.toString(), + "p"); + checkExit(Exit.OK); + checkOutput(Output.OUT, true, console.message); + checkOutput("p/package-summary.html", true, documentation.message); + } + + private void initSource(Path src) throws IOException { + tb.writeJavaFiles(src, """ + package p; + /** + * A class. + */ + public class C { + private C() { } + }"""); + } +} diff --git a/test/langtools/tools/javac/api/TestGetSourceVersions.java b/test/langtools/tools/javac/api/TestGetSourceVersions.java index 4df60355aad..61147bc458d 100644 --- a/test/langtools/tools/javac/api/TestGetSourceVersions.java +++ b/test/langtools/tools/javac/api/TestGetSourceVersions.java @@ -24,7 +24,7 @@ /* * @test * @bug 6395981 6458819 7025784 8028543 8028544 8193291 8193292 8193292 8205393 8245585 8245585 8245585 8286034 - * 8296150 8306585 8319414 8330183 8342982 8355748 + * 8296150 8306585 8319414 8330183 8342982 8355748 8370893 * @summary JavaCompilerTool and Tool must specify version of JLS and JVMS * @author Peter von der Ahé * @modules java.compiler @@ -37,7 +37,7 @@ * RELEASE_8 RELEASE_9 RELEASE_10 RELEASE_11 RELEASE_12 * RELEASE_13 RELEASE_14 RELEASE_15 RELEASE_16 RELEASE_17 * RELEASE_18 RELEASE_19 RELEASE_20 RELEASE_21 RELEASE_22 - * RELEASE_23 RELEASE_24 RELEASE_25 RELEASE_26 + * RELEASE_23 RELEASE_24 RELEASE_25 RELEASE_26 RELEASE_27 */ import java.util.EnumSet; diff --git a/test/langtools/tools/javac/classfiles/ClassVersionChecker.java b/test/langtools/tools/javac/classfiles/ClassVersionChecker.java index 6afa7ad9e30..8cf30373e29 100644 --- a/test/langtools/tools/javac/classfiles/ClassVersionChecker.java +++ b/test/langtools/tools/javac/classfiles/ClassVersionChecker.java @@ -24,7 +24,7 @@ /* * @test * @bug 7157626 8001112 8188870 8173382 8193290 8205619 8245586 8257453 8306586 8330184 - * 8342983 8355751 + * 8342983 8355751 8370894 * @summary Test major version for all legal combinations for -source and -target * @author sgoel * @@ -62,6 +62,7 @@ public class ClassVersionChecker { TWENTY_FOUR("24", 68), TWENTY_FIVE("25", 69), TWENTY_SIX("26", 70), + TWENTY_SEVEN("27", 71), ; // Reduce code churn when appending new constants private Version(String release, int classFileVer) { diff --git a/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java b/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java index e181ef8bf63..70a1e028839 100644 --- a/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java +++ b/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java @@ -113,7 +113,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { * corresponding platform visitor type. */ - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static abstract class AbstractAnnotationValueVisitor extends AbstractAnnotationValueVisitorPreview { @@ -125,7 +125,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static abstract class AbstractElementVisitor extends AbstractElementVisitorPreview { /** @@ -136,7 +136,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static abstract class AbstractTypeVisitor extends AbstractTypeVisitorPreview { /** @@ -147,7 +147,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class ElementKindVisitor extends ElementKindVisitorPreview { /** @@ -169,7 +169,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class ElementScanner extends ElementScannerPreview { /** @@ -189,7 +189,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class SimpleAnnotationValueVisitor extends SimpleAnnotationValueVisitorPreview { /** @@ -211,7 +211,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class SimpleElementVisitor extends SimpleElementVisitorPreview { /** @@ -233,7 +233,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class SimpleTypeVisitor extends SimpleTypeVisitorPreview { /** @@ -255,7 +255,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class TypeKindVisitor extends TypeKindVisitorPreview { /** diff --git a/test/langtools/tools/javac/options/HelpOutputColumnWidthTest.java b/test/langtools/tools/javac/options/HelpOutputColumnWidthTest.java index 4cef7e1916b..f46ef0219b5 100644 --- a/test/langtools/tools/javac/options/HelpOutputColumnWidthTest.java +++ b/test/langtools/tools/javac/options/HelpOutputColumnWidthTest.java @@ -47,7 +47,7 @@ import toolbox.Task; public class HelpOutputColumnWidthTest extends TestRunner { - public static final int MAX_COLUMNS = 84; + public static final int MAX_COLUMNS = 80; protected ToolBox tb; diff --git a/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out b/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out index 8c455009ae5..f46b53f80db 100644 --- a/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out +++ b/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out @@ -1,2 +1,2 @@ -- compiler.err.preview.feature.disabled.classfile: Bar.class, 26 +- compiler.err.preview.feature.disabled.classfile: Bar.class, 27 1 error diff --git a/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out b/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out index 26ff05b085a..7ae297ee2fb 100644 --- a/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out +++ b/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out @@ -1,4 +1,4 @@ -- compiler.warn.preview.feature.use.classfile: Bar.class, 26 +- compiler.warn.preview.feature.use.classfile: Bar.class, 27 - compiler.err.warnings.and.werror 1 error 1 warning diff --git a/test/langtools/tools/javac/versions/Versions.java b/test/langtools/tools/javac/versions/Versions.java index 43fcb0353d0..e83f7b8c308 100644 --- a/test/langtools/tools/javac/versions/Versions.java +++ b/test/langtools/tools/javac/versions/Versions.java @@ -26,7 +26,7 @@ * @bug 4981566 5028634 5094412 6304984 7025786 7025789 8001112 8028545 * 8000961 8030610 8028546 8188870 8173382 8173382 8193290 8205619 8028563 * 8245147 8245586 8257453 8286035 8306586 8320806 8306586 8319414 8330183 - * 8342982 8355748 8356108 + * 8342982 8355748 8356108 8370893 * @summary Check interpretation of -target and -source options * @modules java.compiler * jdk.compiler @@ -73,9 +73,9 @@ public class Versions { public static final Set VALID_SOURCES = Set.of("1.8", "1.9", "1.10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", - "23", "24", "25", "26"); + "23", "24", "25", "26", "27"); - public static final String LATEST_MAJOR_VERSION = "70.0"; + public static final String LATEST_MAJOR_VERSION = "71.0"; static enum SourceTarget { EIGHT(true, "52.0", "8"), @@ -97,6 +97,7 @@ public class Versions { TWENTY_FOUR(false,"68.0", "24"), TWENTY_FIVE(false,"69.0", "25"), TWENTY_SIX(false, "70.0", "26"), + TWENTY_SEVEN(false, "71.0", "27"), ; // Reduce code churn when appending new constants private final boolean dotOne; diff --git a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java index 422671d65b7..ec3e6d773b1 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.List; +import jdk.internal.platform.Metrics; import jdk.test.lib.Container; import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; @@ -47,6 +48,7 @@ import jtreg.SkippedException; public class DockerTestUtils { private static boolean isDockerEngineAvailable = false; private static boolean wasDockerEngineChecked = false; + private static final Metrics metrics = Metrics.systemMetrics(); // Specifies how many lines to copy from child STDOUT to main test output. // Having too many lines in the main test output will result @@ -93,16 +95,12 @@ public class DockerTestUtils { } /** - * Convenience method, will check if docker engine is available and usable; - * will print the appropriate message when not available. + * Checks if the docker engine is available and usable, throws an exception if not. * - * @return true if docker engine is available * @throws Exception */ - public static boolean canTestDocker() throws Exception { - if (isDockerEngineAvailable()) { - return true; - } else { + public static void checkCanTestDocker() throws Exception { + if (!isDockerEngineAvailable()) { throw new SkippedException("Docker engine is not available on this system"); } } @@ -133,6 +131,17 @@ public class DockerTestUtils { return execute(Container.ENGINE_COMMAND, "info", "-f", format).getStdout(); } + /** + * Checks if the engine can use resource limits, throws an exception if not. + * + * @throws Exception + */ + public static void checkCanUseResourceLimits() throws Exception { + if (isRootless() && "cgroupv1".equals(metrics.getProvider())) { + throw new SkippedException("Resource limits are not available on this system"); + } + } + /** * Determine if the engine is running in root-less mode. * diff --git a/test/lib/jdk/test/lib/thread/TestThreadFactory.java b/test/lib/jdk/test/lib/thread/TestThreadFactory.java index ac5a6b74909..043c96cf284 100644 --- a/test/lib/jdk/test/lib/thread/TestThreadFactory.java +++ b/test/lib/jdk/test/lib/thread/TestThreadFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,8 +32,27 @@ import java.util.concurrent.ThreadFactory; public class TestThreadFactory { - private static ThreadFactory threadFactory = "Virtual".equals(System.getProperty("test.thread.factory")) - ? virtualThreadFactory() : platformThreadFactory(); + public enum TestThreadFactoryType { + NONE, VIRTUAL + } + + private final static TestThreadFactoryType testThreadFactoryType = + "Virtual".equals(System.getProperty("test.thread.factory")) + ? TestThreadFactoryType.VIRTUAL + : TestThreadFactoryType.NONE; + + private final static ThreadFactory threadFactory = + testThreadFactoryType == TestThreadFactoryType.VIRTUAL + ? virtualThreadFactory() + : platformThreadFactory(); + + public static TestThreadFactoryType testThreadFactoryType() { + return testThreadFactoryType; + } + + public static boolean isTestThreadFactorySet() { + return !testThreadFactoryType.equals(TestThreadFactoryType.NONE); + } public static Thread newThread(Runnable task) { return threadFactory.newThread(task); diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 5741745e064..8e30c089bcb 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -66,7 +66,7 @@ public class WhiteBox { // Memory private native long getObjectAddress0(Object o); - public long getObjectAddress(Object o) { + public long getObjectAddress(Object o) { Objects.requireNonNull(o); return getObjectAddress0(o); } @@ -78,7 +78,12 @@ public class WhiteBox { public native long getHeapSpaceAlignment(); public native long getHeapAlignment(); - public native boolean hasExternalSymbolsStripped(); + public native boolean shipsFullDebugInfo(); + public native boolean shipsPublicDebugInfo(); + + public boolean shipsDebugInfo() { + return shipsFullDebugInfo() || shipsPublicDebugInfo(); + } private native boolean isObjectInOldGen0(Object o); public boolean isObjectInOldGen(Object o) { diff --git a/test/micro/org/openjdk/bench/java/lang/StringCompareToFoldCase.java b/test/micro/org/openjdk/bench/java/lang/StringCompareToFoldCase.java new file mode 100644 index 00000000000..dff4d874705 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/StringCompareToFoldCase.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.*; +import java.util.concurrent.TimeUnit; + +/* + * This benchmark naively explores String::compareToFoldCase performance + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +public class StringCompareToFoldCase { + + private String asciiUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + private String asciiUpperLower = "ABCDEFGHIJKLMNOpqrstuvwxyz"; + private String asciiLower = "abcdefghijklmnopqrstuvwxyz"; + + private String asciiWithDF = "abcdßßßßßßßßßßßßßßßßWXYZ"; + private String asciiWithDFSS = "abcdssssssssssssssssßßßßßßßßWXYZ"; + + private String asciiLatine1 = "ABCDEFGHIJKLMNOpqrstuvwxyz0"; + private String asciiLatin1UTF16 = "abcdefghijklmnopqrstuvwxyz\u0391"; + + private String greekUpper = "\u0391\u0392\u0393\u0394\u0395\u0391\u0392\u0393\u0394\u0395"; // ΑΒΓΔΕ + private String greekUpperLower = "\u0391\u0392\u0393\u0394\u0395\u0391\u0392\u0393\u0394\u03B5"; // ΑΒΓΔε + private String greekLower = "\u03B1\u03B2\u03B3\u03B4\u03B5\u03B1\u03B2\u03B3\u03B4\u03B5"; // αβγδε + + public String supUpper = "\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc04"; + public String supUpperLower = "\ud801\udc00\ud801\udc01\ud801\udc02\ud801\udc03\ud801\udc2c"; + public String supLower = "\ud801\udc28\ud801\udc29\ud801\udc2a\ud801\udc2b\ud801\udc2c"; + + @Benchmark + public int asciiUpperLower() { + return asciiUpper.compareToIgnoreCase(asciiUpperLower); + } + + @Benchmark + public int asciiLower() { + return asciiUpper.compareToIgnoreCase(asciiLower); + } + + @Benchmark + public int greekUpperLower() { + return greekUpper.compareToIgnoreCase(greekUpperLower); + } + + @Benchmark + public int greekLower() { + return greekUpper.compareToIgnoreCase(greekLower); + } + + @Benchmark + public int latin1UTF16() { + return asciiLatine1.compareToIgnoreCase(asciiLatin1UTF16); + } + + @Benchmark + public int supUpperLower() { + return supUpper.compareToIgnoreCase(supUpperLower); + } + + @Benchmark + public int supLower() { + return supUpper.compareToIgnoreCase(supLower); + } + + @Benchmark + public int asciiUpperLowerFC() { + return asciiUpper.compareToFoldCase(asciiUpperLower); + } + + @Benchmark + public int asciiLowerFC() { + return asciiUpper.compareToFoldCase(asciiLower); + } + + @Benchmark + public int asciiWithDFFC() { + return asciiWithDF.compareToFoldCase(asciiWithDFSS); + } + + @Benchmark + public int greekUpperLowerFC() { + return greekUpper.compareToFoldCase(greekUpperLower); + } + + @Benchmark + public int greekLowerFC() { + return greekUpper.compareToFoldCase(greekLower); + } + + @Benchmark + public int latin1UTF16FC() { + return asciiLatine1.compareToFoldCase(asciiLatin1UTF16); } + + @Benchmark + public int supUpperLowerFC() { + return supUpper.compareToFoldCase(supUpperLower); + } + + @Benchmark + public int supLowerFC() { + return supUpper.compareToFoldCase(supLower); + } + + @Benchmark + public boolean asciiUpperLowerEQ() { + return asciiUpper.equalsIgnoreCase(asciiUpperLower); + } + + @Benchmark + public boolean asciiLowerEQ() { + return asciiUpper.equalsIgnoreCase(asciiLower); + } + + @Benchmark + public boolean greekUpperLowerEQ() { + return greekUpper.equalsIgnoreCase(greekUpperLower); + } + + @Benchmark + public boolean greekLowerEQ() { + return greekUpper.equalsIgnoreCase(greekLower); + } + + @Benchmark + public boolean latin1UTF16EQ() { + return asciiLatine1.equalsIgnoreCase(asciiLatin1UTF16); + } + + @Benchmark + public boolean supUpperLowerEQ() { + return supUpper.equalsIgnoreCase(supUpperLower); + } + + @Benchmark + public boolean supLowerEQ() { + return supUpper.equalsIgnoreCase(supLower); + } + + @Benchmark + public boolean asciiUpperLowerEQFC() { + return asciiUpper.equalsFoldCase(asciiUpperLower); + } + + @Benchmark + public boolean asciiLowerEQFC() { + return asciiUpper.equalsFoldCase(asciiLower); + } + + @Benchmark + public boolean greekUpperLowerEQFC() { + return greekUpper.equalsFoldCase(greekUpperLower); + } + + @Benchmark + public boolean greekLowerEQFC() { + return greekUpper.equalsFoldCase(greekLower); + } + + @Benchmark + public boolean latin1UTF16EQFC() { + return asciiLatine1.equalsFoldCase(asciiLatin1UTF16); + } + + @Benchmark + public boolean supUpperLowerEQFC() { + return supUpper.equalsFoldCase(supUpperLower); + } + + @Benchmark + public boolean supLowerEQFC() { + return supUpper.equalsFoldCase(supLower); + } + } diff --git a/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java b/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java new file mode 100644 index 00000000000..f041eb89f5a --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.vm.runtime; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +@State(Scope.Benchmark) +@Warmup(iterations = 2, time = 5) +@Measurement(iterations = 5, time = 5) +@BenchmarkMode(Mode.SampleTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Threads(1) +@Fork(value = 10) +public class ThreadMXBeanBench { + static final ThreadMXBean mxThreadBean = ManagementFactory.getThreadMXBean(); + static long user; // To avoid dead-code elimination + + @Benchmark + public void getCurrentThreadUserTime() throws Throwable { + user = mxThreadBean.getCurrentThreadUserTime(); + } +} diff --git a/test/setup_aot/TestSetupAOT.java b/test/setup_aot/TestSetupAOT.java index a46bd6e66c7..0ab17d6ca99 100644 --- a/test/setup_aot/TestSetupAOT.java +++ b/test/setup_aot/TestSetupAOT.java @@ -137,7 +137,7 @@ public class TestSetupAOT { String jlinkOutput = tmpDir + File.separator + "jlinkOutput"; execTool("jlink", "--help") - .shouldContain("Compression to use in compressing resources"); + .shouldContain("Compress all resources in the output image"); execTool("jlink", "--list-plugins") .shouldContain("List of available plugins", "--generate-cds-archive ");