diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0d8663fab1a..4d1e8a8be3d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -327,8 +327,8 @@ jobs: uses: ./.github/workflows/build-macos.yml with: platform: macos-x64 - runs-on: 'macos-13' - xcode-toolset-version: '14.3.1' + runs-on: 'macos-15-intel' + xcode-toolset-version: '16.4' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} @@ -340,8 +340,8 @@ jobs: uses: ./.github/workflows/build-macos.yml with: platform: macos-aarch64 - runs-on: 'macos-14' - xcode-toolset-version: '15.4' + runs-on: 'macos-15' + xcode-toolset-version: '16.4' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} @@ -432,9 +432,9 @@ jobs: with: platform: macos-aarch64 bootjdk-platform: macos-aarch64 - runs-on: macos-14 + runs-on: macos-15 dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} - xcode-toolset-version: '15.4' + xcode-toolset-version: '16.4' debug-suffix: -debug test-windows-x64: diff --git a/make/autoconf/boot-jdk.m4 b/make/autoconf/boot-jdk.m4 index 1dd768b2ae1..adc9afc349d 100644 --- a/make/autoconf/boot-jdk.m4 +++ b/make/autoconf/boot-jdk.m4 @@ -444,6 +444,9 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS], # Force en-US environment UTIL_ADD_JVM_ARG_IF_OK([-Duser.language=en -Duser.country=US],boot_jdk_jvmargs,[$JAVA]) + UTIL_ADD_JVM_ARG_IF_OK([-Xlog:all=off:stdout],boot_jdk_jvmargs,[$JAVA]) + UTIL_ADD_JVM_ARG_IF_OK([-Xlog:all=warning:stderr],boot_jdk_jvmargs,[$JAVA]) + if test "x$BOOTJDK_USE_LOCAL_CDS" = xtrue; then # Use our own CDS archive UTIL_ADD_JVM_ARG_IF_OK([$boot_jdk_cds_args -Xshare:auto],boot_jdk_jvmargs,[$JAVA]) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index 651be3a1913..66f8904db89 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -79,7 +79,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], fi if test "x$OPENJDK_TARGET_OS" = xaix; then BASIC_LDFLAGS="-Wl,-b64 -Wl,-brtl -Wl,-bnorwexec -Wl,-blibpath:/usr/lib:lib -Wl,-bnoexpall \ - -Wl,-bernotok -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k" + -Wl,-bernotok -Wl,-bcdtors:mbr::s -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k" BASIC_LDFLAGS_JVM_ONLY="$BASIC_LDFLAGS_JVM_ONLY -Wl,-lC_r -Wl,-bbigtoc" fi diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index d4299078abf..bb188778001 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -565,9 +565,14 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER], # with an additional define LLVM_SYMBOLIZER, which we set here. # To calculate the correct llvm_symbolizer path we can use the location of the compiler, because # their relation is fixed. + # In the ubsan case we have to link every binary with the C++-compiler as linker, because inherently + # the C-Compiler and the C++-compiler used as linker provide a different set of ubsan exports. + # Linking an executable with the C-compiler and one of its shared libraries with the C++-compiler + # leeds to unresolved symbols. if test "x$TOOLCHAIN_TYPE" = "xclang" && test "x$OPENJDK_TARGET_OS" = "xaix"; then - UBSAN_CFLAGS="$UBSAN_CFLAGS -fno-sanitize=function,vptr -DLLVM_SYMBOLIZER=$(dirname $(dirname $CC))/tools/ibm-llvm-symbolizer" - UBSAN_LDFLAGS="$UBSAN_LDFLAGS -fno-sanitize=function,vptr -Wl,-bbigtoc" + UBSAN_CFLAGS="$UBSAN_CFLAGS -DLLVM_SYMBOLIZER=$(dirname $(dirname $CC))/tools/ibm-llvm-symbolizer" + UBSAN_LDFLAGS="$UBSAN_LDFLAGS -Wl,-bbigtoc" + LD="$LDCXX" fi UTIL_ARG_ENABLE(NAME: ubsan, DEFAULT: false, RESULT: UBSAN_ENABLED, DESC: [enable UndefinedBehaviorSanitizer], diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4 index bf697928f1b..8dc3d55ed0c 100644 --- a/make/autoconf/libraries.m4 +++ b/make/autoconf/libraries.m4 @@ -136,12 +136,8 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES], BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBPTHREAD" fi - # librt for legacy clock_gettime + # librt - for timers (timer_* functions) if test "x$OPENJDK_TARGET_OS" = xlinux; then - # Hotspot needs to link librt to get the clock_* functions. - # But once our supported minimum build and runtime platform - # has glibc 2.17, this can be removed as the functions are - # in libc. BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lrt" fi diff --git a/make/common/Execute.gmk b/make/common/Execute.gmk index 0311c4ecba1..c195510151f 100644 --- a/make/common/Execute.gmk +++ b/make/common/Execute.gmk @@ -149,7 +149,7 @@ define SetupExecuteBody endif $1_VARDEPS := $$($1_COMMAND) $$($1_PRE_COMMAND) $$($1_POST_COMMAND) - $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS) + $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_BASE)_exec.vardeps) ifneq ($$($1_PRE_COMMAND), ) diff --git a/make/data/charsetmapping/IBM930.c2b b/make/data/charsetmapping/IBM930.c2b index 88754763fe3..72107424104 100644 --- a/make/data/charsetmapping/IBM930.c2b +++ b/make/data/charsetmapping/IBM930.c2b @@ -32,11 +32,6 @@ 547d 92ca 53da 9b7e 446e f86f -# -# we should use this one instead of the 4260<-ff0d -#4260 2212 -4260 ff0d -# 426A 00A6 43A1 301C 444A 2014 diff --git a/make/data/charsetmapping/IBM930.map b/make/data/charsetmapping/IBM930.map index 4b9dad9526b..7939e795bdf 100644 --- a/make/data/charsetmapping/IBM930.map +++ b/make/data/charsetmapping/IBM930.map @@ -25,13 +25,6 @@ # 4260 <--> 2212 # 426A <--> 00A6 # -# Warning: -# "our old" implementation seems agree with above "new" mappings -# except the entries 4260 <-> 2212. To keep the "compatbility" -# with the "old" implementation, I changed the entries "temporarily" -# 4260 <-> 2212 -# 4260 <- ff0d -# 00 0000 01 0001 02 0002 @@ -407,8 +400,7 @@ FF 009F 425D FF09 425E FF1B 425F FFE2 -#4260 FF0D -4260 2212 +4260 FF0D 4261 FF0F 426A FFE4 426B FF0C diff --git a/make/devkit/Makefile b/make/devkit/Makefile index d2167bf33fa..30e0dce0839 100644 --- a/make/devkit/Makefile +++ b/make/devkit/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -57,61 +57,61 @@ COMMA := , -os := $(shell uname -o) -cpu := $(shell uname -p) +OS := $(shell uname -o) +CPU := $(shell uname -m) # Figure out what platform this is building on. -me := $(cpu)-$(if $(findstring Linux,$(os)),linux-gnu) +ME := $(CPU)-$(if $(findstring Linux,$(OS)),linux-gnu) -$(info Building on platform $(me)) +$(info Building on platform $(ME)) # # By default just build for the current platform, which is assumed to be Linux # ifeq ($(TARGETS), ) - platforms := $(me) - host_platforms := $(platforms) + PLATFORMS := $(ME) + HOST_PLATFORMS := $(PLATFORMS) else - platforms := $(subst $(COMMA), , $(TARGETS)) - host_platforms := $(me) + PLATFORMS := $(subst $(COMMA), , $(TARGETS)) + HOST_PLATFORMS := $(ME) endif -target_platforms := $(platforms) -$(info host_platforms $(host_platforms)) -$(info target_platforms $(target_platforms)) +TARGET_PLATFORMS := $(PLATFORMS) +$(info HOST_PLATFORMS $(HOST_PLATFORMS)) +$(info TARGET_PLATFORMS $(TARGET_PLATFORMS)) -all compile : $(platforms) +all compile : $(PLATFORMS) ifeq ($(SKIP_ME), ) - $(foreach p,$(filter-out $(me),$(platforms)),$(eval $(p) : $$(me))) + $(foreach p,$(filter-out $(ME),$(PLATFORMS)),$(eval $(p) : $$(ME))) endif OUTPUT_ROOT = $(abspath ../../build/devkit) RESULT = $(OUTPUT_ROOT)/result -submakevars = HOST=$@ BUILD=$(me) RESULT=$(RESULT) OUTPUT_ROOT=$(OUTPUT_ROOT) +SUBMAKEVARS = HOST=$@ BUILD=$(ME) RESULT=$(RESULT) OUTPUT_ROOT=$(OUTPUT_ROOT) -$(host_platforms) : +$(HOST_PLATFORMS) : @echo 'Building compilers for $@' - @echo 'Targets: $(target_platforms)' - for p in $(filter $@, $(target_platforms)) $(filter-out $@, $(target_platforms)); do \ - $(MAKE) -f Tools.gmk download-rpms $(submakevars) \ + @echo 'Targets: $(TARGET_PLATFORMS)' + for p in $(filter $@, $(TARGET_PLATFORMS)) $(filter-out $@, $(TARGET_PLATFORMS)); do \ + $(MAKE) -f Tools.gmk download-rpms $(SUBMAKEVARS) \ TARGET=$$p PREFIX=$(RESULT)/$@-to-$$p && \ - $(MAKE) -f Tools.gmk all $(submakevars) \ + $(MAKE) -f Tools.gmk all $(SUBMAKEVARS) \ TARGET=$$p PREFIX=$(RESULT)/$@-to-$$p && \ - $(MAKE) -f Tools.gmk ccache $(submakevars) \ + $(MAKE) -f Tools.gmk ccache $(SUBMAKEVARS) \ TARGET=$@ PREFIX=$(RESULT)/$@-to-$$p || exit 1 ; \ done @echo 'All done"' -today := $(shell date +%Y%m%d) +TODAY := $(shell date +%Y%m%d) define Mktar - $(1)-to-$(2)_tar = $$(RESULT)/sdk-$(1)-to-$(2)-$$(today).tar.gz + $(1)-to-$(2)_tar = $$(RESULT)/sdk-$(1)-to-$(2)-$$(TODAY).tar.gz $$($(1)-to-$(2)_tar) : PLATFORM = $(1)-to-$(2) TARFILES += $$($(1)-to-$(2)_tar) endef -$(foreach p,$(host_platforms),$(foreach t,$(target_platforms),$(eval $(call Mktar,$(p),$(t))))) +$(foreach p,$(HOST_PLATFORMS),$(foreach t,$(TARGET_PLATFORMS),$(eval $(call Mktar,$(p),$(t))))) tars : all $(TARFILES) onlytars : $(TARFILES) @@ -119,9 +119,9 @@ onlytars : $(TARFILES) $(MAKE) -r -f Tars.gmk SRC_DIR=$(RESULT)/$(PLATFORM) TAR_FILE=$@ clean : - rm -rf $(addprefix ../../build/devkit/, result $(host_platforms)) + rm -rf $(addprefix ../../build/devkit/, result $(HOST_PLATFORMS)) dist-clean: clean rm -rf $(addprefix ../../build/devkit/, src download) FORCE : -.PHONY : all compile tars $(configs) $(host_platforms) clean dist-clean +.PHONY : all compile tars $(HOST_PLATFORMS) clean dist-clean diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index f27d47b822c..77a201d0c38 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -39,7 +39,7 @@ # Fix this... # -uppercase = $(shell echo $1 | tr a-z A-Z) +lowercase = $(shell echo $1 | tr A-Z a-z) $(info TARGET=$(TARGET)) $(info HOST=$(HOST)) @@ -104,26 +104,26 @@ endif ################################################################################ # Define external dependencies -gcc_ver_only := 14.2.0 -binutils_ver_only := 2.43 -ccache_ver_only := 4.10.2 +GCC_VER_ONLY := 14.2.0 +BINUTILS_VER_ONLY := 2.43 +CCACHE_VER_ONLY := 4.10.2 CCACHE_CMAKE_BASED := 1 -mpfr_ver_only := 4.2.1 -gmp_ver_only := 6.3.0 -mpc_ver_only := 1.3.1 -gdb_ver_only := 15.2 +MPFR_VER_ONLY := 4.2.1 +GMP_VER_ONLY := 6.3.0 +MPC_VER_ONLY := 1.3.1 +GDB_VER_ONLY := 15.2 -dependencies := gcc binutils ccache mpfr gmp mpc gdb +DEPENDENCIES := GCC BINUTILS CCACHE MPFR GMP MPC GDB -$(foreach dep,$(dependencies),$(eval $(dep)_ver := $(dep)-$($(dep)_ver_only))) +$(foreach dep,$(DEPENDENCIES),$(eval $(dep)_VER := $(call lowercase,$(dep)-$($(dep)_VER_ONLY)))) -GCC := http://ftp.gnu.org/pub/gnu/gcc/$(gcc_ver)/$(gcc_ver).tar.xz -BINUTILS := http://ftp.gnu.org/pub/gnu/binutils/$(binutils_ver).tar.gz -CCACHE := https://github.com/ccache/ccache/releases/download/v$(ccache_ver_only)/$(ccache_ver).tar.xz -MPFR := https://www.mpfr.org/$(mpfr_ver)/$(mpfr_ver).tar.bz2 -GMP := http://ftp.gnu.org/pub/gnu/gmp/$(gmp_ver).tar.bz2 -MPC := http://ftp.gnu.org/pub/gnu/mpc/$(mpc_ver).tar.gz -GDB := http://ftp.gnu.org/gnu/gdb/$(gdb_ver).tar.xz +GCC_URL := https://ftp.gnu.org/pub/gnu/gcc/$(GCC_VER)/$(GCC_VER).tar.xz +BINUTILS_URL := https://ftp.gnu.org/pub/gnu/binutils/$(BINUTILS_VER).tar.gz +CCACHE_URL := https://github.com/ccache/ccache/releases/download/v$(CCACHE_VER_ONLY)/$(CCACHE_VER).tar.xz +MPFR_URL := https://www.mpfr.org/$(MPFR_VER)/$(MPFR_VER).tar.bz2 +GMP_URL := https://ftp.gnu.org/pub/gnu/gmp/$(GMP_VER).tar.bz2 +MPC_URL := https://ftp.gnu.org/pub/gnu/mpc/$(MPC_VER).tar.gz +GDB_URL := https://ftp.gnu.org/gnu/gdb/$(GDB_VER).tar.xz REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 ifneq ($(REQUIRED_MIN_MAKE_MAJOR_VERSION),) @@ -180,10 +180,10 @@ DOWNLOAD_RPMS := $(DOWNLOAD)/rpms/$(TARGET)-$(LINUX_VERSION) SRCDIR := $(OUTPUT_ROOT)/src # Marker file for unpacking rpms -rpms := $(SYSROOT)/rpms_unpacked +RPMS := $(SYSROOT)/rpms_unpacked # Need to patch libs that are linker scripts to use non-absolute paths -libs := $(SYSROOT)/libs_patched +LIBS := $(SYSROOT)/libs_patched ################################################################################ # Download RPMs @@ -201,7 +201,7 @@ download-rpms: # Generate downloading + unpacking of sources. define Download # Allow override - $(1)_DIRNAME ?= $(basename $(basename $(notdir $($(1))))) + $(1)_DIRNAME ?= $(basename $(basename $(notdir $($(1)_URL)))) $(1)_DIR = $(abspath $(SRCDIR)/$$($(1)_DIRNAME)) ifeq ($$($(1)_CMAKE_BASED),) $(1)_CFG = $$($(1)_DIR)/configure @@ -212,7 +212,7 @@ define Download $(1)_SRC_MARKER = $$($(1)_DIR)/CMakeLists.txt $(1)_CONFIG = $$(CMAKE_CONFIG) $$($(1)_DIR) endif - $(1)_FILE = $(DOWNLOAD)/$(notdir $($(1))) + $(1)_FILE = $(DOWNLOAD)/$(notdir $($(1)_URL)) $$($(1)_SRC_MARKER) : $$($(1)_FILE) mkdir -p $$(SRCDIR) @@ -224,11 +224,11 @@ define Download touch $$@ $$($(1)_FILE) : - wget -P $(DOWNLOAD) $$($(1)) + wget -P $(DOWNLOAD) $$($(1)_URL) endef # Download and unpack all source packages -$(foreach dep,$(dependencies),$(eval $(call Download,$(call uppercase,$(dep))))) +$(foreach dep,$(DEPENDENCIES),$(eval $(call Download,$(dep)))) ################################################################################ # Unpack RPMS @@ -250,7 +250,7 @@ RPM_FILE_LIST := $(sort $(foreach a, $(RPM_ARCHS), \ # Note. For building linux you should install rpm2cpio. define unrpm $(SYSROOT)/$(notdir $(1)).unpacked : $(1) - $$(rpms) : $(SYSROOT)/$(notdir $(1)).unpacked + $$(RPMS) : $(SYSROOT)/$(notdir $(1)).unpacked endef %.unpacked : @@ -277,7 +277,7 @@ $(foreach p,$(RPM_FILE_LIST),$(eval $(call unrpm,$(p)))) # have it anyway, but just to make sure... # Patch libc.so and libpthread.so to force linking against libraries in sysroot # and not the ones installed on the build machine. -$(libs) : $(rpms) +$(LIBS) : $(RPMS) @echo Patching libc and pthreads @(for f in `find $(SYSROOT) -name libc.so -o -name libpthread.so`; do \ (cat $$f | sed -e 's|/usr/lib64/||g' \ @@ -293,10 +293,10 @@ $(libs) : $(rpms) # Create links for ffi header files so that they become visible by default when using the # devkit. ifeq ($(ARCH), x86_64) - $(SYSROOT)/usr/include/ffi.h: $(rpms) + $(SYSROOT)/usr/include/ffi.h: $(RPMS) cd $(@D) && rm -f $(@F) && ln -s ../lib/libffi-*/include/$(@F) . - $(SYSROOT)/usr/include/ffitarget.h: $(rpms) + $(SYSROOT)/usr/include/ffitarget.h: $(RPMS) cd $(@D) && rm -f $(@F) && ln -s ../lib/libffi-*/include/$(@F) . SYSROOT_LINKS += $(SYSROOT)/usr/include/ffi.h $(SYSROOT)/usr/include/ffitarget.h @@ -305,7 +305,7 @@ endif ################################################################################ # Define marker files for each source package to be compiled -$(foreach dep,$(dependencies),$(eval $(dep) = $(TARGETDIR)/$($(dep)_ver).done)) +$(foreach dep,$(DEPENDENCIES),$(eval $(dep) = $(TARGETDIR)/$($(dep)_VER).done)) ################################################################################ @@ -345,48 +345,48 @@ TOOLS ?= $(call declare_tools,_FOR_TARGET,$(TARGET)-) # CFLAG_ to most likely -m32. define mk_bfd $$(info Libs for $(1)) - $$(BUILDDIR)/$$(binutils_ver)-$(subst /,-,$(1))/Makefile \ + $$(BUILDDIR)/$$(BINUTILS_VER)-$(subst /,-,$(1))/Makefile \ : CFLAGS += $$(CFLAGS_$(1)) - $$(BUILDDIR)/$$(binutils_ver)-$(subst /,-,$(1))/Makefile \ + $$(BUILDDIR)/$$(BINUTILS_VER)-$(subst /,-,$(1))/Makefile \ : LIBDIRS = --libdir=$(TARGETDIR)/$(1) - bfdlib += $$(TARGETDIR)/$$(binutils_ver)-$(subst /,-,$(1)).done - bfdmakes += $$(BUILDDIR)/$$(binutils_ver)-$(subst /,-,$(1))/Makefile + BFDLIB += $$(TARGETDIR)/$$(BINUTILS_VER)-$(subst /,-,$(1)).done + BFDMAKES += $$(BUILDDIR)/$$(BINUTILS_VER)-$(subst /,-,$(1))/Makefile endef # Create one set of bfds etc for each multilib arch $(foreach l,$(LIBDIRS),$(eval $(call mk_bfd,$(l)))) # Only build these two libs. -$(bfdlib) : MAKECMD = all-libiberty all-bfd -$(bfdlib) : INSTALLCMD = install-libiberty install-bfd +$(BFDLIB) : MAKECMD = all-libiberty all-bfd +$(BFDLIB) : INSTALLCMD = install-libiberty install-bfd # Building targets libbfd + libiberty. HOST==TARGET, i.e not # for a cross env. -$(bfdmakes) : CONFIG = --target=$(TARGET) \ +$(BFDMAKES) : CONFIG = --target=$(TARGET) \ --host=$(TARGET) --build=$(BUILD) \ --prefix=$(TARGETDIR) \ --with-sysroot=$(SYSROOT) \ $(LIBDIRS) -$(bfdmakes) : TOOLS = $(call declare_tools,_FOR_TARGET,$(TARGET)-) $(call declare_tools,,$(TARGET)-) +$(BFDMAKES) : TOOLS = $(call declare_tools,_FOR_TARGET,$(TARGET)-) $(call declare_tools,,$(TARGET)-) ################################################################################ -$(gcc) \ - $(binutils) \ - $(gmp) \ - $(mpfr) \ - $(mpc) \ - $(bfdmakes) \ - $(ccache) : ENVS += $(TOOLS) +$(GCC) \ + $(BINUTILS) \ + $(GMP) \ + $(MPFR) \ + $(MPC) \ + $(BFDMAKES) \ + $(CCACHE) : ENVS += $(TOOLS) # libdir to work around hateful bfd stuff installing into wrong dirs... # ensure we have 64 bit bfd support in the HOST library. I.e our # compiler on i686 will know 64 bit symbols, BUT later # we build just the libs again for TARGET, then with whatever the arch # wants. -$(BUILDDIR)/$(binutils_ver)/Makefile : CONFIG += --enable-64-bit-bfd --libdir=$(PREFIX)/$(word 1,$(LIBDIRS)) +$(BUILDDIR)/$(BINUTILS_VER)/Makefile : CONFIG += --enable-64-bit-bfd --libdir=$(PREFIX)/$(word 1,$(LIBDIRS)) ifeq ($(filter $(ARCH), s390x riscv64 ppc64le), ) # gold compiles but cannot link properly on s390x @ gcc 13.2 and Fedore 41 @@ -397,8 +397,8 @@ endif # Makefile creation. Simply run configure in build dir. # Setting CFLAGS to -O2 generates a much faster ld. -$(bfdmakes) \ -$(BUILDDIR)/$(binutils_ver)/Makefile \ +$(BFDMAKES) \ +$(BUILDDIR)/$(BINUTILS_VER)/Makefile \ : $(BINUTILS_CFG) $(info Configuring $@. Log in $(@D)/log.config) @mkdir -p $(@D) @@ -417,7 +417,7 @@ $(BUILDDIR)/$(binutils_ver)/Makefile \ ) > $(@D)/log.config 2>&1 @echo 'done' -$(BUILDDIR)/$(mpfr_ver)/Makefile \ +$(BUILDDIR)/$(MPFR_VER)/Makefile \ : $(MPFR_CFG) $(info Configuring $@. Log in $(@D)/log.config) @mkdir -p $(@D) @@ -432,7 +432,7 @@ $(BUILDDIR)/$(mpfr_ver)/Makefile \ ) > $(@D)/log.config 2>&1 @echo 'done' -$(BUILDDIR)/$(gmp_ver)/Makefile \ +$(BUILDDIR)/$(GMP_VER)/Makefile \ : $(GMP_CFG) $(info Configuring $@. Log in $(@D)/log.config) @mkdir -p $(@D) @@ -449,7 +449,7 @@ $(BUILDDIR)/$(gmp_ver)/Makefile \ ) > $(@D)/log.config 2>&1 @echo 'done' -$(BUILDDIR)/$(mpc_ver)/Makefile \ +$(BUILDDIR)/$(MPC_VER)/Makefile \ : $(MPC_CFG) $(info Configuring $@. Log in $(@D)/log.config) @mkdir -p $(@D) @@ -468,11 +468,11 @@ $(BUILDDIR)/$(mpc_ver)/Makefile \ # Only valid if glibc target -> linux # proper destructor handling for c++ ifneq (,$(findstring linux,$(TARGET))) - $(BUILDDIR)/$(gcc_ver)/Makefile : CONFIG += --enable-__cxa_atexit + $(BUILDDIR)/$(GCC_VER)/Makefile : CONFIG += --enable-__cxa_atexit endif ifeq ($(ARCH), armhfp) - $(BUILDDIR)/$(gcc_ver)/Makefile : CONFIG += --with-float=hard + $(BUILDDIR)/$(GCC_VER)/Makefile : CONFIG += --with-float=hard endif ifneq ($(filter riscv64 ppc64le s390x, $(ARCH)), ) @@ -487,7 +487,7 @@ endif # skip native language. # and link and assemble with the binutils we created # earlier, so --with-gnu* -$(BUILDDIR)/$(gcc_ver)/Makefile \ +$(BUILDDIR)/$(GCC_VER)/Makefile \ : $(GCC_CFG) $(info Configuring $@. Log in $(@D)/log.config) mkdir -p $(@D) @@ -509,17 +509,17 @@ $(BUILDDIR)/$(gcc_ver)/Makefile \ @echo 'done' # need binutils for gcc -$(gcc) : $(binutils) +$(GCC) : $(BINUTILS) # as of 4.3 or so need these for doing config -$(BUILDDIR)/$(gcc_ver)/Makefile : $(gmp) $(mpfr) $(mpc) -$(mpfr) : $(gmp) -$(mpc) : $(gmp) $(mpfr) +$(BUILDDIR)/$(GCC_VER)/Makefile : $(GMP) $(MPFR) $(MPC) +$(MPFR) : $(GMP) +$(MPC) : $(GMP) $(MPFR) ################################################################################ # Build gdb but only where host and target match ifeq ($(HOST), $(TARGET)) - $(BUILDDIR)/$(gdb_ver)/Makefile: $(GDB_CFG) + $(BUILDDIR)/$(GDB_VER)/Makefile: $(GDB_CFG) $(info Configuring $@. Log in $(@D)/log.config) mkdir -p $(@D) ( \ @@ -532,9 +532,9 @@ ifeq ($(HOST), $(TARGET)) ) > $(@D)/log.config 2>&1 @echo 'done' - $(gdb): $(gcc) + $(GDB): $(GCC) else - $(BUILDDIR)/$(gdb_ver)/Makefile: + $(BUILDDIR)/$(GDB_VER)/Makefile: $(info Faking $@, not used when cross-compiling) mkdir -p $(@D) echo "install:" > $@ @@ -543,7 +543,7 @@ endif ################################################################################ # very straightforward. just build a ccache. it is only for host. -$(BUILDDIR)/$(ccache_ver)/Makefile \ +$(BUILDDIR)/$(CCACHE_VER)/Makefile \ : $(CCACHE_SRC_MARKER) $(info Configuring $@. Log in $(@D)/log.config) @mkdir -p $(@D) @@ -554,12 +554,12 @@ $(BUILDDIR)/$(ccache_ver)/Makefile \ ) > $(@D)/log.config 2>&1 @echo 'done' -gccpatch = $(TARGETDIR)/gcc-patched +GCC_PATCHED = $(TARGETDIR)/gcc-patched ################################################################################ # For some reason cpp is not created as a target-compiler ifeq ($(HOST),$(TARGET)) - $(gccpatch) : $(gcc) link_libs + $(GCC_PATCHED) : $(GCC) link_libs @echo -n 'Creating compiler symlinks...' @for f in cpp; do \ if [ ! -e $(PREFIX)/bin/$(TARGET)-$$f ]; \ @@ -587,7 +587,7 @@ ifeq ($(HOST),$(TARGET)) done;) @echo 'done' else - $(gccpatch) : + $(GCC_PATCHED) : @echo 'done' endif @@ -615,7 +615,7 @@ $(PREFIX)/devkit.info: echo '# This file describes to configure how to interpret the contents of this' >> $@ echo '# devkit' >> $@ echo '' >> $@ - echo 'DEVKIT_NAME="$(gcc_ver) - $(LINUX_VERSION)"' >> $@ + echo 'DEVKIT_NAME="$(GCC_VER) - $(LINUX_VERSION)"' >> $@ echo 'DEVKIT_TOOLCHAIN_PATH="$$DEVKIT_ROOT/bin"' >> $@ echo 'DEVKIT_SYSROOT="$$DEVKIT_ROOT/$(TARGET)/sysroot"' >> $@ echo 'DEVKIT_EXTRA_PATH="$$DEVKIT_ROOT/bin"' >> $@ @@ -651,32 +651,32 @@ ifeq ($(TARGET), $(HOST)) @echo 'Creating missing $* soft link' ln -s $(TARGET)-$* $@ - missing-links := $(addprefix $(PREFIX)/bin/, \ - addr2line ar as c++ c++filt dwp elfedit g++ gcc gcc-$(gcc_ver_only) gprof ld ld.bfd \ + MISSING_LINKS := $(addprefix $(PREFIX)/bin/, \ + addr2line ar as c++ c++filt dwp elfedit g++ gcc gcc-$(GCC_VER_ONLY) gprof ld ld.bfd \ ld.gold nm objcopy objdump ranlib readelf size strings strip) endif # Add link to work around "plugin needed to handle lto object" (JDK-8344272) -$(PREFIX)/lib/bfd-plugins/liblto_plugin.so: $(PREFIX)/libexec/gcc/$(TARGET)/$(gcc_ver_only)/liblto_plugin.so +$(PREFIX)/lib/bfd-plugins/liblto_plugin.so: $(PREFIX)/libexec/gcc/$(TARGET)/$(GCC_VER_ONLY)/liblto_plugin.so @echo 'Creating missing $(@F) soft link' @mkdir -p $(@D) ln -s $$(realpath -s --relative-to=$(@D) $<) $@ -missing-links += $(PREFIX)/lib/bfd-plugins/liblto_plugin.so +MISSING_LINKS += $(PREFIX)/lib/bfd-plugins/liblto_plugin.so ################################################################################ -bfdlib : $(bfdlib) -binutils : $(binutils) -rpms : $(rpms) -libs : $(libs) +bfdlib : $(BFDLIB) +binutils : $(BINUTILS) +rpms : $(RPMS) +libs : $(LIBS) sysroot : rpms libs -gcc : sysroot $(gcc) $(gccpatch) -gdb : $(gdb) -all : binutils gcc bfdlib $(PREFIX)/devkit.info $(missing-links) $(SYSROOT_LINKS) \ +gcc : sysroot $(GCC) $(GCC_PATCHED) +gdb : $(GDB) +all : binutils gcc bfdlib $(PREFIX)/devkit.info $(MISSING_LINKS) $(SYSROOT_LINKS) \ $(THESE_MAKEFILES) gdb # this is only built for host. so separate. -ccache : $(ccache) +ccache : $(CCACHE) .PHONY : gcc all binutils bfdlib link_libs rpms libs sysroot diff --git a/make/devkit/createAutoconfBundle.sh b/make/devkit/createAutoconfBundle.sh index ebe9c427f76..4697e4eb1e3 100644 --- a/make/devkit/createAutoconfBundle.sh +++ b/make/devkit/createAutoconfBundle.sh @@ -93,7 +93,7 @@ elif test "x$TARGET_PLATFORM" = xlinux_x64; then rpm2cpio $OUTPUT_ROOT/m4-$M4_VERSION.el6.x86_64.rpm | cpio -d -i elif test "x$TARGET_PLATFORM" = xlinux_x86; then M4_VERSION=1.4.13-5 - wget http://yum.oracle.com/repo/OracleLinux/OL6/latest/i386/getPackage/m4-$M4_VERSION.el6.i686.rpm + wget https://yum.oracle.com/repo/OracleLinux/OL6/latest/i386/getPackage/m4-$M4_VERSION.el6.i686.rpm cd $IMAGE_DIR rpm2cpio $OUTPUT_ROOT/m4-$M4_VERSION.el6.i686.rpm | cpio -d -i else diff --git a/make/ide/vscode/hotspot/template-workspace.jsonc b/make/ide/vscode/hotspot/template-workspace.jsonc index c582c48047d..8a349b232ce 100644 --- a/make/ide/vscode/hotspot/template-workspace.jsonc +++ b/make/ide/vscode/hotspot/template-workspace.jsonc @@ -22,6 +22,7 @@ // Java extension "jdk.project.jdkhome": "{{OUTPUTDIR}}/jdk", "jdk.java.onSave.organizeImports": false, // prevents unnecessary changes + "jdk.serverVmOptions": ["-Xmx2G"], // prevent out of memory // Additional conventions "files.associations": { diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index e0459716122..51cdf8c71df 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2568,10 +2568,6 @@ RegMask Matcher::modL_proj_mask() { return RegMask(); } -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return FP_REG_mask(); -} - bool size_fits_all_mem_uses(AddPNode* addp, int shift) { for (DUIterator_Fast imax, i = addp->fast_outs(imax); i < imax; i++) { Node* u = addp->fast_out(i); diff --git a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp index 954e4abee14..9bf46678535 100644 --- a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp @@ -216,10 +216,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - if (_compute_lock) { - // lock_reg was destroyed by fast unlocking attempt => recompute it - ce->monitor_address(_monitor_ix, _lock_reg); - } + + // lock_reg was destroyed by fast unlocking attempt => recompute it + ce->monitor_address(_monitor_ix, _lock_reg); + ce->store_parameter(_lock_reg->as_register(), 0); // note: non-blocking leaf routine => no call info needed StubId exit_id; diff --git a/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp index 9d30092b45a..83d0952dcb4 100644 --- a/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_FrameMap_aarch64.cpp @@ -383,13 +383,6 @@ LIR_Opr FrameMap::stack_pointer() { return FrameMap::sp_opr; } - -// JSR 292 -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - return LIR_OprFact::illegalOpr; // Not needed on aarch64 -} - - bool FrameMap::validate_frame() { return true; } diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index d788c0c201a..9ab463125fe 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -409,7 +409,7 @@ int LIR_Assembler::emit_unwind_handler() { MonitorExitStub* stub = nullptr; if (method()->is_synchronized()) { monitor_address(0, FrameMap::r0_opr); - stub = new MonitorExitStub(FrameMap::r0_opr, true, 0); + stub = new MonitorExitStub(FrameMap::r0_opr, 0); __ unlock_object(r5, r4, r0, r6, *stub->entry()); __ bind(*stub->continuation()); } @@ -2481,7 +2481,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register lock = op->lock_opr()->as_register(); Register temp = op->scratch_opr()->as_register(); if (op->code() == lir_lock) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); // add debug info for NullPointerException only if one is possible int null_check_offset = __ lock_object(hdr, obj, lock, temp, *op->stub()->entry()); if (op->info() != nullptr) { @@ -2489,7 +2488,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { } // done } else if (op->code() == lir_unlock) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); __ unlock_object(hdr, obj, lock, temp, *op->stub()->entry()); } else { Unimplemented(); diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index 8a79274b2ff..31c36e749c5 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -59,28 +59,28 @@ void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result, } } -int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { - assert_different_registers(hdr, obj, disp_hdr, temp, rscratch2); +int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) { + assert_different_registers(hdr, obj, basic_lock, temp, rscratch2); int null_check_offset = -1; verify_oop(obj); // save object being locked into the BasicObjectLock - str(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + str(obj, Address(basic_lock, BasicObjectLock::obj_offset())); null_check_offset = offset(); - lightweight_lock(disp_hdr, obj, hdr, temp, rscratch2, slow_case); + lightweight_lock(basic_lock, obj, hdr, temp, rscratch2, slow_case); return null_check_offset; } -void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { - assert_different_registers(hdr, obj, disp_hdr, temp, rscratch2); +void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) { + assert_different_registers(hdr, obj, basic_lock, temp, rscratch2); // load object - ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + ldr(obj, Address(basic_lock, BasicObjectLock::obj_offset())); verify_oop(obj); lightweight_unlock(obj, hdr, temp, rscratch2, slow_case); diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp index fc8e83d706b..7b181b104c1 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -55,19 +55,19 @@ using MacroAssembler::null_check; Register result); // locking - // hdr : must be r0, contents destroyed - // obj : must point to the object to lock, contents preserved - // disp_hdr: must point to the displaced header location, contents preserved - // temp : temporary register, must not be rscratch1 or rscratch2 + // hdr : must be r0, contents destroyed + // obj : must point to the object to lock, contents preserved + // basic_lock: must point to the basic lock, contents preserved + // temp : temporary register, must not be rscratch1 or rscratch2 // returns code offset at which to add null check debug information - int lock_object (Register swap, Register obj, Register disp_hdr, Register temp, Label& slow_case); + int lock_object (Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case); // unlocking - // hdr : contents destroyed - // obj : must point to the object to lock, contents preserved - // disp_hdr: must be r0 & must point to the displaced header location, contents destroyed - // temp : temporary register, must not be rscratch1 or rscratch2 - void unlock_object(Register swap, Register obj, Register lock, Register temp, Label& slow_case); + // hdr : contents destroyed + // obj : must point to the object to lock, contents preserved + // basic_lock: must be r0 & must point to the basic lock, contents destroyed + // temp : temporary register, must not be rscratch1 or rscratch2 + void unlock_object(Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case); void initialize_object( Register obj, // result: pointer to object after successful allocation diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index aff50b9cf2f..bdbef53bfdb 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -228,8 +228,7 @@ bool frame::safe_for_sender(JavaThread *thread) { nmethod* nm = sender_blob->as_nmethod_or_null(); if (nm != nullptr) { - if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || - nm->method()->is_method_handle_intrinsic()) { + if (nm->is_deopt_entry(sender_pc) || nm->method()->is_method_handle_intrinsic()) { return false; } } @@ -454,48 +453,6 @@ JavaThread** frame::saved_thread_address(const frame& f) { return thread_addr; } -//------------------------------------------------------------------------------ -// frame::verify_deopt_original_pc -// -// Verifies the calculated original PC of a deoptimization PC for the -// given unextended SP. -#ifdef ASSERT -void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) { - frame fr; - - // This is ugly but it's better than to change {get,set}_original_pc - // to take an SP value as argument. And it's only a debugging - // method anyway. - fr._unextended_sp = unextended_sp; - - address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains_inclusive(original_pc), - "original PC must be in the main code section of the compiled method (or must be immediately following it)"); -} -#endif - -//------------------------------------------------------------------------------ -// frame::adjust_unextended_sp -#ifdef ASSERT -void frame::adjust_unextended_sp() { - // On aarch64, sites calling method handle intrinsics and lambda forms are treated - // as any other call site. Therefore, no special action is needed when we are - // returning to any of these call sites. - - if (_cb != nullptr) { - nmethod* sender_nm = _cb->as_nmethod_or_null(); - if (sender_nm != nullptr) { - // If the sender PC is a deoptimization point, get the original PC. - if (sender_nm->is_deopt_entry(_pc) || - sender_nm->is_deopt_mh_entry(_pc)) { - verify_deopt_original_pc(sender_nm, _unextended_sp); - } - } - } -} -#endif - - //------------------------------------------------------------------------------ // frame::sender_for_interpreter_frame frame frame::sender_for_interpreter_frame(RegisterMap* map) const { diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.hpp index da020b4234d..231710df7d7 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -141,8 +141,6 @@ int _offset_unextended_sp; // for use in stack-chunk frames }; - void adjust_unextended_sp() NOT_DEBUG_RETURN; - // true means _sp value is correct and we can use it to get the sender's sp // of the compiled frame, otherwise, _sp value may be invalid and we can use // _fp to get the sender's sp if PreserveFramePointer is enabled. @@ -152,11 +150,6 @@ return (intptr_t*) addr_at(offset); } -#ifdef ASSERT - // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp); -#endif - public: // Constructors diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp index 47ae93a4932..cb53d8663ad 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp @@ -116,8 +116,6 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) { } inline void frame::setup(address pc) { - adjust_unextended_sp(); - address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; @@ -223,7 +221,6 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) { // assert(_pc != nullptr, "no pc?"); _cb = CodeCache::find_blob(_pc); - adjust_unextended_sp(); address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp index a2b43d80746..021af3e5698 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp @@ -398,14 +398,18 @@ void BarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register OptoReg::Name BarrierSetAssembler::encode_float_vector_register_size(const Node* node, OptoReg::Name opto_reg) { switch (node->ideal_reg()) { case Op_RegF: + case Op_RegI: // RA may place scalar values (Op_RegI/N/L/P) in FP registers when UseFPUForSpilling is enabled + case Op_RegN: // No need to refine. The original encoding is already fine to distinguish. - assert(opto_reg % 4 == 0, "Float register should only occupy a single slot"); + assert(opto_reg % 4 == 0, "32-bit register should only occupy a single slot"); break; // Use different encoding values of the same fp/vector register to help distinguish different sizes. // Such as V16. The OptoReg::name and its corresponding slot value are // "V16": 64, "V16_H": 65, "V16_J": 66, "V16_K": 67. case Op_RegD: case Op_VecD: + case Op_RegL: + case Op_RegP: opto_reg &= ~3; opto_reg |= 1; break; diff --git a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp index 948ba97aa22..1e788590b64 100644 --- a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp @@ -35,8 +35,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define SUPPORTS_NATIVE_CX8 -#define SUPPORT_MONITOR_COUNT - // Aarch64 was not originally defined to be multi-copy-atomic, but now // is. See: "Simplifying ARM Concurrency: Multicopy-atomic Axiomatic // and Operational Models for ARMv8" diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 3999beeec2b..2622bda1d0b 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -5630,38 +5630,6 @@ void MacroAssembler::tlab_allocate(Register obj, bs->tlab_allocate(this, obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); } -void MacroAssembler::inc_held_monitor_count(Register tmp) { - Address dst(rthread, JavaThread::held_monitor_count_offset()); -#ifdef ASSERT - ldr(tmp, dst); - increment(tmp); - str(tmp, dst); - Label ok; - tbz(tmp, 63, ok); - STOP("assert(held monitor count underflow)"); - should_not_reach_here(); - bind(ok); -#else - increment(dst); -#endif -} - -void MacroAssembler::dec_held_monitor_count(Register tmp) { - Address dst(rthread, JavaThread::held_monitor_count_offset()); -#ifdef ASSERT - ldr(tmp, dst); - decrement(tmp); - str(tmp, dst); - Label ok; - tbz(tmp, 63, ok); - STOP("assert(held monitor count underflow)"); - should_not_reach_here(); - bind(ok); -#else - decrement(dst); -#endif -} - void MacroAssembler::verify_tlab() { #ifdef ASSERT if (UseTLAB && VerifyOops) { diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 0570fad5b8d..705bd19093c 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -983,9 +983,6 @@ class MacroAssembler: public Assembler { void push_cont_fastpath(Register java_thread = rthread); void pop_cont_fastpath(Register java_thread = rthread); - void inc_held_monitor_count(Register tmp); - void dec_held_monitor_count(Register tmp); - // Round up to a power of two void round_to(Register reg, int modulus); diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index f5d7d9e4387..94694b58d2f 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -90,7 +90,6 @@ void Relocation::pd_set_call_destination(address x) { void trampoline_stub_Relocation::pd_fix_owner_after_move() { NativeCall* call = nativeCall_at(owner()); - assert(call->raw_destination() == owner(), "destination should be empty"); address trampoline = addr(); address dest = nativeCallTrampolineStub_at(trampoline)->destination(); if (!Assembler::reachable_from_branch_at(owner(), dest)) { diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 4b3b8e58b9a..39609cbe0ac 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -985,11 +985,8 @@ static void fill_continuation_entry(MacroAssembler* masm) { __ ldr(rscratch1, Address(rthread, JavaThread::cont_fastpath_offset())); __ str(rscratch1, Address(sp, ContinuationEntry::parent_cont_fastpath_offset())); - __ ldr(rscratch1, Address(rthread, JavaThread::held_monitor_count_offset())); - __ str(rscratch1, Address(sp, ContinuationEntry::parent_held_monitor_count_offset())); __ str(zr, Address(rthread, JavaThread::cont_fastpath_offset())); - __ str(zr, Address(rthread, JavaThread::held_monitor_count_offset())); } // on entry, sp points to the ContinuationEntry @@ -1005,50 +1002,6 @@ static void continuation_enter_cleanup(MacroAssembler* masm) { #endif __ ldr(rscratch1, Address(sp, ContinuationEntry::parent_cont_fastpath_offset())); __ str(rscratch1, Address(rthread, JavaThread::cont_fastpath_offset())); - - if (CheckJNICalls) { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ ldrw(rscratch1, Address(sp, ContinuationEntry::flags_offset())); - __ cbzw(rscratch1, L_skip_vthread_code); - - // If the held monitor count is > 0 and this vthread is terminating then - // it failed to release a JNI monitor. So we issue the same log message - // that JavaThread::exit does. - __ ldr(rscratch1, Address(rthread, JavaThread::jni_monitor_count_offset())); - __ cbz(rscratch1, L_skip_vthread_code); - - // Save return value potentially containing the exception oop in callee-saved R19. - __ mov(r19, r0); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::log_jni_monitor_still_held)); - // Restore potential return value. - __ mov(r0, r19); - - // For vthreads we have to explicitly zero the JNI monitor count of the carrier - // on termination. The held count is implicitly zeroed below when we restore from - // the parent held count (which has to be zero). - __ str(zr, Address(rthread, JavaThread::jni_monitor_count_offset())); - - __ bind(L_skip_vthread_code); - } -#ifdef ASSERT - else { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ ldrw(rscratch1, Address(sp, ContinuationEntry::flags_offset())); - __ cbzw(rscratch1, L_skip_vthread_code); - - // See comment just above. If not checking JNI calls the JNI count is only - // needed for assertion checking. - __ str(zr, Address(rthread, JavaThread::jni_monitor_count_offset())); - - __ bind(L_skip_vthread_code); - } -#endif - - __ ldr(rscratch1, Address(sp, ContinuationEntry::parent_held_monitor_count_offset())); - __ str(rscratch1, Address(rthread, JavaThread::held_monitor_count_offset())); - __ ldr(rscratch2, Address(sp, ContinuationEntry::parent_offset())); __ str(rscratch2, Address(rthread, JavaThread::cont_entry_offset())); __ add(rfp, sp, (int)ContinuationEntry::size()); @@ -1761,9 +1714,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label lock_done; if (method->is_synchronized()) { - Label count; - const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes(); - // Get the handle (the 2nd argument) __ mov(oop_handle_reg, c_rarg1); diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 308deeaf5e2..a04e9defa4b 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2020, Red Hat Inc. All rights reserved. + * Copyright 2025 Arm Limited and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -222,10 +223,13 @@ void VM_Version::initialize() { // Neoverse // N1: 0xd0c // N2: 0xd49 + // N3: 0xd8e // V1: 0xd40 // V2: 0xd4f + // V3: 0xd84 if (_cpu == CPU_ARM && (model_is(0xd0c) || model_is(0xd49) || - model_is(0xd40) || model_is(0xd4f))) { + model_is(0xd40) || model_is(0xd4f) || + model_is(0xd8e) || model_is(0xd84))) { if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) { FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true); } @@ -260,7 +264,9 @@ void VM_Version::initialize() { // Neoverse // V1: 0xd40 // V2: 0xd4f - if (_cpu == CPU_ARM && (model_is(0xd40) || model_is(0xd4f))) { + // V3: 0xd84 + if (_cpu == CPU_ARM && + (model_is(0xd40) || model_is(0xd4f) || model_is(0xd84))) { if (FLAG_IS_DEFAULT(UseCryptoPmullForCRC32)) { FLAG_SET_DEFAULT(UseCryptoPmullForCRC32, true); } diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 2835a256153..68fece5263d 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -1154,10 +1154,6 @@ RegMask Matcher::modL_proj_mask() { return RegMask(); } -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return FP_REGP_mask(); -} - bool maybe_far_call(const CallNode *n) { return !MacroAssembler::_reachable_from_cache(n->as_Call()->entry_point()); } @@ -1248,23 +1244,6 @@ encode %{ __ set_inst_mark(mark); %} - enc_class preserve_SP %{ - // preserve mark - address mark = __ inst_mark(); - DEBUG_ONLY(int off0 = __ offset()); - // FP is preserved across all calls, even compiled calls. - // Use it to preserve SP in places where the callee might change the SP. - __ mov(Rmh_SP_save, SP); - DEBUG_ONLY(int off1 = __ offset()); - assert(off1 - off0 == 4, "correct size prediction"); - // restore mark - __ set_inst_mark(mark); - %} - - enc_class restore_SP %{ - __ mov(SP, Rmh_SP_save); - %} - enc_class Java_Dynamic_Call (method meth) %{ Register R8_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode()); assert(R8_ic_reg == Ricklass, "should be"); @@ -8799,7 +8778,6 @@ instruct safePoint_poll(iRegP poll, R12RegI tmp, flagsReg icc) %{ // Call Java Static Instruction instruct CallStaticJavaDirect( method meth ) %{ match(CallStaticJava); - predicate(! ((CallStaticJavaNode*)n)->is_method_handle_invoke()); effect(USE meth); ins_cost(CALL_COST); @@ -8808,20 +8786,6 @@ instruct CallStaticJavaDirect( method meth ) %{ ins_pipe(simple_call); %} -// Call Java Static Instruction (method handle version) -instruct CallStaticJavaHandle( method meth ) %{ - match(CallStaticJava); - predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke()); - effect(USE meth); - // FP is saved by all callees (for interpreter stack correction). - // We use it here for a similar purpose, in {preserve,restore}_FP. - - ins_cost(CALL_COST); - format %{ "CALL,static/MethodHandle ==> " %} - ins_encode( SetInstMark, preserve_SP, Java_Static_Call( meth ), restore_SP, call_epilog, ClearInstMark ); - ins_pipe(simple_call); -%} - // Call Java Dynamic Instruction instruct CallDynamicJavaDirect( method meth ) %{ match(CallDynamicJava); diff --git a/src/hotspot/cpu/arm/arm_32.ad b/src/hotspot/cpu/arm/arm_32.ad index 1c15d55fbc3..00bf3bd61e4 100644 --- a/src/hotspot/cpu/arm/arm_32.ad +++ b/src/hotspot/cpu/arm/arm_32.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -432,8 +432,7 @@ OptoRegPair c2::return_value(int ideal_reg) { int MachCallStaticJavaNode::ret_addr_offset() { bool far = (_method == nullptr) ? maybe_far_call(this) : !cache_reachable(); - return ((far ? 3 : 1) + (_method_handle_invoke ? 1 : 0)) * - NativeInstruction::instruction_size; + return (far ? 3 : 1) * NativeInstruction::instruction_size; } int MachCallDynamicJavaNode::ret_addr_offset() { diff --git a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp index efdc190f09a..8e49cfcbcaa 100644 --- a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp +++ b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp @@ -200,9 +200,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - if (_compute_lock) { - ce->monitor_address(_monitor_ix, _lock_reg); - } + + // lock_reg was destroyed by fast unlocking attempt => recompute it + ce->monitor_address(_monitor_ix, _lock_reg); + const Register lock_reg = _lock_reg->as_pointer_register(); ce->verify_reserved_argument_area_size(1); diff --git a/src/hotspot/cpu/arm/c1_FrameMap_arm.cpp b/src/hotspot/cpu/arm/c1_FrameMap_arm.cpp index 0fd113c8ceb..a820da4d283 100644 --- a/src/hotspot/cpu/arm/c1_FrameMap_arm.cpp +++ b/src/hotspot/cpu/arm/c1_FrameMap_arm.cpp @@ -174,11 +174,6 @@ LIR_Opr FrameMap::stack_pointer() { return FrameMap::SP_opr; } -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - assert(Rmh_SP_save == FP, "Fix register used for saving SP for MethodHandle calls"); - return FP_opr; -} - bool FrameMap::validate_frame() { int max_offset = in_bytes(framesize_in_bytes()); int java_index = 0; diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index d6ed82dcdb2..219c49d1f14 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -245,7 +245,7 @@ int LIR_Assembler::emit_unwind_handler() { MonitorExitStub* stub = nullptr; if (method()->is_synchronized()) { monitor_address(0, FrameMap::R0_opr); - stub = new MonitorExitStub(FrameMap::R0_opr, true, 0); + stub = new MonitorExitStub(FrameMap::R0_opr, 0); __ unlock_object(R2, R1, R0, *stub->entry()); __ bind(*stub->continuation()); } @@ -2427,7 +2427,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register lock = op->lock_opr()->as_pointer_register(); if (op->code() == lir_lock) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); int null_check_offset = __ lock_object(hdr, obj, lock, *op->stub()->entry()); if (op->info() != nullptr) { add_debug_info_for_null_check(null_check_offset, op->info()); diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp index f2b08269750..ca7711353d2 100644 --- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp @@ -176,17 +176,17 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, initialize_object(obj, tmp1, klass, len, tmp2, tmp3, header_size_in_bytes, -1, /* is_tlab_allocated */ UseTLAB); } -int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { +int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case) { int null_check_offset = 0; const Register tmp2 = Rtemp; // Rtemp should be free at c1 LIR level - assert_different_registers(hdr, obj, disp_hdr, tmp2); + assert_different_registers(hdr, obj, basic_lock, tmp2); assert(BasicObjectLock::lock_offset() == 0, "adjust this code"); assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions"); // save object being locked into the BasicObjectLock - str(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + str(obj, Address(basic_lock, BasicObjectLock::obj_offset())); null_check_offset = offset(); @@ -197,26 +197,26 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr b(slow_case, ne); } - Register t1 = disp_hdr; // Needs saving, probably - Register t2 = hdr; // blow - Register t3 = Rtemp; // blow + Register t1 = basic_lock; // Needs saving, probably + Register t2 = hdr; // blow + Register t3 = Rtemp; // blow lightweight_lock(obj, t1, t2, t3, 1 /* savemask - save t1 */, slow_case); // Success: fall through return null_check_offset; } -void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { - assert_different_registers(hdr, obj, disp_hdr, Rtemp); +void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case) { + assert_different_registers(hdr, obj, basic_lock, Rtemp); assert(BasicObjectLock::lock_offset() == 0, "adjust this code"); assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions"); - ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + ldr(obj, Address(basic_lock, BasicObjectLock::obj_offset())); - Register t1 = disp_hdr; // Needs saving, probably - Register t2 = hdr; // blow - Register t3 = Rtemp; // blow + Register t1 = basic_lock; // Needs saving, probably + Register t2 = hdr; // blow + Register t3 = Rtemp; // blow lightweight_unlock(obj, t1, t2, t3, 1 /* savemask - save t1 */, slow_case); // Success: fall through diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.hpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.hpp index 0a626822a9b..fd88b6c4fe9 100644 --- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,9 +59,9 @@ max_array_allocation_length = 0x01000000 }; - int lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case); + int lock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case); - void unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case); + void unlock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case); // This platform only uses signal-based null checks. The Label is not needed. void null_check(Register r, Label *Lnull = nullptr) { MacroAssembler::null_check(r); } diff --git a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp index 32da2c24d26..9983f2ce7a2 100644 --- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp +++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp @@ -275,14 +275,6 @@ OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address targe } -static void restore_sp_for_method_handle(StubAssembler* sasm) { - // Restore SP from its saved reg (FP) if the exception PC is a MethodHandle call site. - __ ldr_s32(Rtemp, Address(Rthread, JavaThread::is_method_handle_return_offset())); - __ cmp(Rtemp, 0); - __ mov(SP, Rmh_SP_save, ne); -} - - OopMapSet* Runtime1::generate_handle_exception(StubId id, StubAssembler* sasm) { __ block_comment("generate_handle_exception"); @@ -339,7 +331,6 @@ OopMapSet* Runtime1::generate_handle_exception(StubId id, StubAssembler* sasm) { break; case StubId::c1_handle_exception_from_callee_id: restore_live_registers_without_return(sasm); // must not jump immediately to handler - restore_sp_for_method_handle(sasm); __ ret(); break; default: ShouldNotReachHere(); @@ -372,9 +363,6 @@ void Runtime1::generate_unwind_exception(StubAssembler* sasm) { // Jump to handler __ verify_not_null_oop(Rexception_obj); - // JSR292 extension - restore_sp_for_method_handle(sasm); - __ jump(R0); } diff --git a/src/hotspot/cpu/arm/frame_arm.cpp b/src/hotspot/cpu/arm/frame_arm.cpp index 2722f93edec..7a23296a3d4 100644 --- a/src/hotspot/cpu/arm/frame_arm.cpp +++ b/src/hotspot/cpu/arm/frame_arm.cpp @@ -329,56 +329,6 @@ JavaThread** frame::saved_thread_address(const frame& f) { return nullptr; } -//------------------------------------------------------------------------------ -// frame::verify_deopt_original_pc -// -// Verifies the calculated original PC of a deoptimization PC for the -// given unextended SP. The unextended SP might also be the saved SP -// for MethodHandle call sites. -#ifdef ASSERT -void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) { - frame fr; - - // This is ugly but it's better than to change {get,set}_original_pc - // to take an SP value as argument. And it's only a debugging - // method anyway. - fr._unextended_sp = unextended_sp; - - address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains_inclusive(original_pc), - "original PC must be in the main code section of the compiled method (or must be immediately following it)"); - assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be"); -} -#endif - -//------------------------------------------------------------------------------ -// frame::adjust_unextended_sp -void frame::adjust_unextended_sp() { - // same as on x86 - - // If we are returning to a compiled MethodHandle call site, the - // saved_fp will in fact be a saved value of the unextended SP. The - // simplest way to tell whether we are returning to such a call site - // is as follows: - - nmethod* sender_nm = (_cb == nullptr) ? nullptr : _cb->as_nmethod_or_null(); - if (sender_nm != nullptr) { - // If the sender PC is a deoptimization point, get the original - // PC. For MethodHandle call site the unextended_sp is stored in - // saved_fp. - if (sender_nm->is_deopt_mh_entry(_pc)) { - DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, _fp)); - _unextended_sp = _fp; - } - else if (sender_nm->is_deopt_entry(_pc)) { - DEBUG_ONLY(verify_deopt_original_pc(sender_nm, _unextended_sp)); - } - else if (sender_nm->is_method_handle_return(_pc)) { - _unextended_sp = _fp; - } - } -} - //------------------------------------------------------------------------------ // frame::update_map_with_saved_link void frame::update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr) { diff --git a/src/hotspot/cpu/arm/frame_arm.hpp b/src/hotspot/cpu/arm/frame_arm.hpp index dec27554a47..6d4ac042831 100644 --- a/src/hotspot/cpu/arm/frame_arm.hpp +++ b/src/hotspot/cpu/arm/frame_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,20 +85,11 @@ // original sp. intptr_t* _unextended_sp; - void adjust_unextended_sp(); intptr_t* ptr_at_addr(int offset) const { return (intptr_t*) addr_at(offset); } -#ifdef ASSERT - // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false); - static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) { - verify_deopt_original_pc(nm, unextended_sp, true); - } -#endif - public: // Constructors diff --git a/src/hotspot/cpu/arm/frame_arm.inline.hpp b/src/hotspot/cpu/arm/frame_arm.inline.hpp index 4be190f0504..42e034cfdc7 100644 --- a/src/hotspot/cpu/arm/frame_arm.inline.hpp +++ b/src/hotspot/cpu/arm/frame_arm.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,8 +112,6 @@ inline void frame::init(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, add } inline void frame::setup(address pc) { - adjust_unextended_sp(); - address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; diff --git a/src/hotspot/cpu/arm/register_arm.hpp b/src/hotspot/cpu/arm/register_arm.hpp index fca23d07fee..e0688af0d36 100644 --- a/src/hotspot/cpu/arm/register_arm.hpp +++ b/src/hotspot/cpu/arm/register_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -364,7 +364,6 @@ class VFPSystemRegisterImpl : public AbstractRegisterImpl { // This does not seem to conflict with Rexception_pc // In case of issues, R3 might be OK but adapters calling the runtime would have to save it #define R5_mh R5 // MethodHandle register, used during the call setup -#define Rmh_SP_save FP // for C1 /* * C++ Interpreter Register Defines diff --git a/src/hotspot/cpu/arm/runtime_arm.cpp b/src/hotspot/cpu/arm/runtime_arm.cpp index ea4c9a76381..8d48de5795a 100644 --- a/src/hotspot/cpu/arm/runtime_arm.cpp +++ b/src/hotspot/cpu/arm/runtime_arm.cpp @@ -264,11 +264,6 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { __ raw_pop(FP, LR); - // Restore SP from its saved reg (FP) if the exception PC is a MethodHandle call site. - __ ldr(Rtemp, Address(Rthread, JavaThread::is_method_handle_return_offset())); - __ cmp(Rtemp, 0); - __ mov(SP, Rmh_SP_save, ne); - // R0 contains handler address // Since this may be the deopt blob we must set R5 to look like we returned // from the original pc that threw the exception diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 9e90b56f9f0..99d8773368d 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -1128,7 +1128,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, const Register sync_handle = R5; const Register sync_obj = R6; - const Register disp_hdr = altFP_7_11; + const Register basic_lock = altFP_7_11; const Register tmp = R8; Label slow_lock, lock_done, fast_lock; @@ -1139,7 +1139,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ mov(sync_handle, R1); log_trace(fastlock)("SharedRuntime lock fast"); - __ lightweight_lock(sync_obj /* object */, disp_hdr /* t1 */, tmp /* t2 */, Rtemp /* t3 */, + __ lightweight_lock(sync_obj /* object */, basic_lock /* t1 */, tmp /* t2 */, Rtemp /* t3 */, 0x7 /* savemask */, slow_lock); // Fall through to lock_done __ bind(lock_done); @@ -1254,7 +1254,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // last_Java_frame is already set, so do call_VM manually; no exception can occur __ mov(R0, sync_obj); - __ mov(R1, disp_hdr); + __ mov(R1, basic_lock); __ mov(R2, Rthread); __ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_locking_C)); @@ -1269,12 +1269,12 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Clear pending exception before reentering VM. // Can store the oop in register since it is a leaf call. - assert_different_registers(Rtmp_save1, sync_obj, disp_hdr); + assert_different_registers(Rtmp_save1, sync_obj, basic_lock); __ ldr(Rtmp_save1, Address(Rthread, Thread::pending_exception_offset())); Register zero = __ zero_register(Rtemp); __ str(zero, Address(Rthread, Thread::pending_exception_offset())); __ mov(R0, sync_obj); - __ mov(R1, disp_hdr); + __ mov(R1, basic_lock); __ mov(R2, Rthread); __ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C)); __ str(Rtmp_save1, Address(Rthread, Thread::pending_exception_offset())); diff --git a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp index 438521b0a9b..61780a73969 100644 --- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp @@ -268,9 +268,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - if (_compute_lock) { - ce->monitor_address(_monitor_ix, _lock_reg); - } + + // lock_reg was destroyed by fast unlocking attempt => recompute it + ce->monitor_address(_monitor_ix, _lock_reg); + address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? StubId::c1_monitorexit_id : StubId::c1_monitorexit_nofpu_id); //__ load_const_optimized(R0, stub); __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); diff --git a/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp b/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp index 8ce324a570b..cb9368f2ce9 100644 --- a/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp @@ -374,15 +374,6 @@ LIR_Opr FrameMap::stack_pointer() { return SP_opr; } - -// JSR 292 -// On PPC64, there is no need to save the SP, because neither -// method handle intrinsics, nor compiled lambda forms modify it. -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - return LIR_OprFact::illegalOpr; -} - - bool FrameMap::validate_frame() { int max_offset = in_bytes(framesize_in_bytes()); int java_index = 0; diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 3ca75305eca..108da2039f6 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -227,7 +227,7 @@ int LIR_Assembler::emit_unwind_handler() { MonitorExitStub* stub = nullptr; if (method()->is_synchronized()) { monitor_address(0, FrameMap::R4_opr); - stub = new MonitorExitStub(FrameMap::R4_opr, true, 0); + stub = new MonitorExitStub(FrameMap::R4_opr, 0); __ unlock_object(R5, R6, R4, *stub->entry()); __ bind(*stub->continuation()); } @@ -2614,7 +2614,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { // Obj may not be an oop. if (op->code() == lir_lock) { MonitorEnterStub* stub = (MonitorEnterStub*)op->stub(); - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); // Add debug info for NullPointerException only if one is possible. if (op->info() != nullptr) { if (!os::zero_page_read_protected() || !ImplicitNullChecks) { @@ -2626,7 +2625,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry()); } else { assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock"); - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); __ unlock_object(hdr, obj, lock, *op->stub()->entry()); } __ bind(*op->stub()->continuation()); diff --git a/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp b/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp index f8f15741301..6c41e56b20b 100644 --- a/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp +++ b/src/hotspot/cpu/ppc/globalDefinitions_ppc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -43,8 +43,6 @@ const bool CCallingConventionRequiresIntsAsLongs = true; #define SUPPORTS_NATIVE_CX8 -#define SUPPORT_MONITOR_COUNT - // PPC64 is not specified as multi-copy-atomic // So we must not #define CPU_MULTI_COPY_ATOMIC diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp index 4e93992f413..ebdfd9a57d6 100644 --- a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp +++ b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp @@ -402,7 +402,7 @@ void NativePostCallNop::make_deopt() { bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) { int32_t i2, i1; assert(is_aligned(cb_offset, 4), "cb offset alignment does not match instruction alignment"); - assert(!decode(i1, i2), "already patched"); + assert(!decode(i1, i2) || NMethodRelocation, "already patched"); cb_offset = cb_offset >> 2; if (((oopmap_slot & ppc_oopmap_slot_mask) != oopmap_slot) || ((cb_offset & ppc_cb_offset_mask) != cb_offset)) { diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 290369360fc..2c83b2d5765 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -2473,10 +2473,6 @@ RegMask Matcher::modL_proj_mask() { return RegMask(); } -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return RegMask(); -} - %} //----------ENCODING BLOCK----------------------------------------------------- @@ -3434,7 +3430,6 @@ encode %{ // Create the call node. CallDynamicJavaDirectSchedNode *call = new CallDynamicJavaDirectSchedNode(); - call->_method_handle_invoke = _method_handle_invoke; call->_vtable_index = _vtable_index; call->_method = _method; call->_optimized_virtual = _optimized_virtual; diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index aec36b3f3f9..9fe7e1f22ff 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -1639,7 +1639,6 @@ static void fill_continuation_entry(MacroAssembler* masm, Register reg_cont_obj, assert_different_registers(reg_cont_obj, reg_flags); Register zero = R8_ARG6; Register tmp2 = R9_ARG7; - Register tmp3 = R10_ARG8; DEBUG_ONLY(__ block_comment("fill {")); #ifdef ASSERT @@ -1655,12 +1654,9 @@ static void fill_continuation_entry(MacroAssembler* masm, Register reg_cont_obj, __ stw(zero, in_bytes(ContinuationEntry::pin_count_offset()), R1_SP); __ ld_ptr(tmp2, JavaThread::cont_fastpath_offset(), R16_thread); - __ ld(tmp3, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); __ st_ptr(tmp2, ContinuationEntry::parent_cont_fastpath_offset(), R1_SP); - __ std(tmp3, in_bytes(ContinuationEntry::parent_held_monitor_count_offset()), R1_SP); __ st_ptr(zero, JavaThread::cont_fastpath_offset(), R16_thread); - __ std(zero, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); DEBUG_ONLY(__ block_comment("} fill")); } @@ -1681,7 +1677,6 @@ static void fill_continuation_entry(MacroAssembler* masm, Register reg_cont_obj, static void continuation_enter_cleanup(MacroAssembler* masm) { Register tmp1 = R8_ARG6; Register tmp2 = R9_ARG7; - Register tmp3 = R10_ARG8; #ifdef ASSERT __ block_comment("clean {"); @@ -1692,57 +1687,8 @@ static void continuation_enter_cleanup(MacroAssembler* masm) { __ ld_ptr(tmp1, ContinuationEntry::parent_cont_fastpath_offset(), R1_SP); __ st_ptr(tmp1, JavaThread::cont_fastpath_offset(), R16_thread); - - if (CheckJNICalls) { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ lwz(R0, in_bytes(ContinuationEntry::flags_offset()), R1_SP); - __ cmpwi(CR0, R0, 0); - __ beq(CR0, L_skip_vthread_code); - - // If the held monitor count is > 0 and this vthread is terminating then - // it failed to release a JNI monitor. So we issue the same log message - // that JavaThread::exit does. - __ ld(R0, in_bytes(JavaThread::jni_monitor_count_offset()), R16_thread); - __ cmpdi(CR0, R0, 0); - __ beq(CR0, L_skip_vthread_code); - - // Save return value potentially containing the exception oop - Register ex_oop = R15_esp; // nonvolatile register - __ mr(ex_oop, R3_RET); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::log_jni_monitor_still_held)); - // Restore potental return value - __ mr(R3_RET, ex_oop); - - // For vthreads we have to explicitly zero the JNI monitor count of the carrier - // on termination. The held count is implicitly zeroed below when we restore from - // the parent held count (which has to be zero). - __ li(tmp1, 0); - __ std(tmp1, in_bytes(JavaThread::jni_monitor_count_offset()), R16_thread); - - __ bind(L_skip_vthread_code); - } -#ifdef ASSERT - else { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ lwz(R0, in_bytes(ContinuationEntry::flags_offset()), R1_SP); - __ cmpwi(CR0, R0, 0); - __ beq(CR0, L_skip_vthread_code); - - // See comment just above. If not checking JNI calls the JNI count is only - // needed for assertion checking. - __ li(tmp1, 0); - __ std(tmp1, in_bytes(JavaThread::jni_monitor_count_offset()), R16_thread); - - __ bind(L_skip_vthread_code); - } -#endif - - __ ld(tmp2, in_bytes(ContinuationEntry::parent_held_monitor_count_offset()), R1_SP); - __ ld_ptr(tmp3, ContinuationEntry::parent_offset(), R1_SP); - __ std(tmp2, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); - __ st_ptr(tmp3, JavaThread::cont_entry_offset(), R16_thread); + __ ld_ptr(tmp2, ContinuationEntry::parent_offset(), R1_SP); + __ st_ptr(tmp2, JavaThread::cont_entry_offset(), R16_thread); DEBUG_ONLY(__ block_comment("} clean")); } diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 0828342ee65..0712b60fb2a 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -914,6 +914,17 @@ class Assembler : public AbstractAssembler { public: + static uint32_t encode_csrrw(Register Rd, const uint32_t csr, Register Rs1) { + guarantee(is_uimm12(csr), "csr is invalid"); + uint32_t insn = 0; + patch((address)&insn, 6, 0, 0b1110011); + patch((address)&insn, 14, 12, 0b001); + patch_reg((address)&insn, 7, Rd); + patch_reg((address)&insn, 15, Rs1); + patch((address)&insn, 31, 20, csr); + return insn; + } + static uint32_t encode_jal(Register Rd, const int32_t offset) { guarantee(is_simm21(offset) && ((offset % 2) == 0), "offset is invalid."); uint32_t insn = 0; @@ -3693,19 +3704,15 @@ enum Nf { // -------------------------- // Upper Immediate Instruction // -------------------------- -#define INSN(NAME) \ - void NAME(Register Rd, int32_t imm) { \ - /* lui -> c.lui */ \ - if (do_compress() && (Rd != x0 && Rd != x2 && imm != 0 && is_simm18(imm))) { \ - c_lui(Rd, imm); \ - return; \ - } \ - _lui(Rd, imm); \ + void lui(Register Rd, int32_t imm) { + /* lui -> c.lui */ + if (do_compress() && (Rd != x0 && Rd != x2 && imm != 0 && is_simm18(imm))) { + c_lui(Rd, imm); + return; + } + _lui(Rd, imm); } - INSN(lui); - -#undef INSN // Cache Management Operations // These instruction may be turned off for user space. diff --git a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp index 0c16e632e5a..a8a21342248 100644 --- a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp @@ -204,10 +204,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - if (_compute_lock) { - // lock_reg was destroyed by fast unlocking attempt => recompute it - ce->monitor_address(_monitor_ix, _lock_reg); - } + + // lock_reg was destroyed by fast unlocking attempt => recompute it + ce->monitor_address(_monitor_ix, _lock_reg); + ce->store_parameter(_lock_reg->as_register(), 0); // note: non-blocking leaf routine => no call info needed StubId exit_id; diff --git a/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp b/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp index d3ccd46048b..b3a0b261f54 100644 --- a/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp @@ -377,11 +377,6 @@ LIR_Opr FrameMap::stack_pointer() { return FrameMap::sp_opr; } -// JSR 292 -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - return LIR_OprFact::illegalOpr; // Not needed on riscv -} - bool FrameMap::validate_frame() { return true; } diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index c3fe72870cf..9d8ae770ccf 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -338,7 +338,7 @@ int LIR_Assembler::emit_unwind_handler() { MonitorExitStub* stub = nullptr; if (method()->is_synchronized()) { monitor_address(0, FrameMap::r10_opr); - stub = new MonitorExitStub(FrameMap::r10_opr, true, 0); + stub = new MonitorExitStub(FrameMap::r10_opr, 0); __ unlock_object(x15, x14, x10, x16, *stub->entry()); __ bind(*stub->continuation()); } @@ -1350,6 +1350,7 @@ void LIR_Assembler::align_call(LIR_Code code) { } void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { + Assembler::IncompressibleScope scope(_masm); address call = __ reloc_call(Address(op->addr(), rtype)); if (call == nullptr) { bailout("reloc call address stub overflow"); @@ -1360,6 +1361,7 @@ void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { } void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { + Assembler::IncompressibleScope scope(_masm); address call = __ ic_call(op->addr()); if (call == nullptr) { bailout("reloc call address stub overflow"); @@ -1494,14 +1496,12 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register lock = op->lock_opr()->as_register(); Register temp = op->scratch_opr()->as_register(); if (op->code() == lir_lock) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); // add debug info for NullPointerException only if one is possible int null_check_offset = __ lock_object(hdr, obj, lock, temp, *op->stub()->entry()); if (op->info() != nullptr) { add_debug_info_for_null_check(null_check_offset, op->info()); } } else if (op->code() == lir_unlock) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); __ unlock_object(hdr, obj, lock, temp, *op->stub()->entry()); } else { Unimplemented(); @@ -1844,6 +1844,10 @@ void LIR_Assembler::leal(LIR_Opr addr, LIR_Opr dest, LIR_PatchCode patch_code, C void LIR_Assembler::rt_call(LIR_Opr result, address dest, const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) { assert(!tmp->is_valid(), "don't need temporary"); + Assembler::IncompressibleScope scope(_masm); + // Post call nops must be natural aligned due to cmodx rules. + align_call(lir_rtcall); + __ rt_call(dest); if (info != nullptr) { diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp index 8198192f506..8e989de2665 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp @@ -48,27 +48,27 @@ void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result, } } -int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { - assert_different_registers(hdr, obj, disp_hdr, temp, t0, t1); +int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) { + assert_different_registers(hdr, obj, basic_lock, temp, t0, t1); int null_check_offset = -1; verify_oop(obj); // save object being locked into the BasicObjectLock - sd(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + sd(obj, Address(basic_lock, BasicObjectLock::obj_offset())); null_check_offset = offset(); - lightweight_lock(disp_hdr, obj, hdr, temp, t1, slow_case); + lightweight_lock(basic_lock, obj, hdr, temp, t1, slow_case); return null_check_offset; } -void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { - assert_different_registers(hdr, obj, disp_hdr, temp, t0, t1); +void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) { + assert_different_registers(hdr, obj, basic_lock, temp, t0, t1); // load object - ld(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + ld(obj, Address(basic_lock, BasicObjectLock::obj_offset())); verify_oop(obj); lightweight_unlock(obj, hdr, temp, t1, slow_case); diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp index 561053045ec..16e76884049 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -56,19 +56,19 @@ using MacroAssembler::null_check; Register result); // locking - // hdr : must be x10, contents destroyed - // obj : must point to the object to lock, contents preserved - // disp_hdr: must point to the displaced header location, contents preserved - // temp : temporary register, must not be scratch register t0 or t1 + // hdr : must be x10, contents destroyed + // obj : must point to the object to lock, contents preserved + // basic_lock: must point to the basic_lock, contents preserved + // temp : temporary register, must not be scratch register t0 or t1 // returns code offset at which to add null check debug information - int lock_object(Register swap, Register obj, Register disp_hdr, Register temp, Label& slow_case); + int lock_object(Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case); // unlocking - // hdr : contents destroyed - // obj : must point to the object to lock, contents preserved - // disp_hdr: must be x10 & must point to the displaced header location, contents destroyed - // temp : temporary register, must not be scratch register t0 or t1 - void unlock_object(Register swap, Register obj, Register lock, Register temp, Label& slow_case); + // hdr : contents destroyed + // obj : must point to the object to lock, contents preserved + // basic_lock: must be x10 & must point to the basic lock, contents destroyed + // temp : temporary register, must not be scratch register t0 or t1 + void unlock_object(Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case); void initialize_object( Register obj, // result: pointer to object after successful allocation diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 1bdb7bc2f7c..154b62db47f 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -1687,6 +1687,7 @@ void C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register res Register tmp4, Register tmp5, Register tmp6, BasicType eltype) { + assert(!UseRVV, "sanity"); assert_different_registers(ary, cnt, result, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, t0, t1); const int elsize = arrays_hashcode_elsize(eltype); @@ -1759,29 +1760,143 @@ void C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register res BLOCK_COMMENT("} // arrays_hashcode"); } +void C2_MacroAssembler::arrays_hashcode_v(Register ary, Register cnt, Register result, + Register tmp1, Register tmp2, Register tmp3, + BasicType eltype) +{ + assert(UseRVV, "sanity"); + assert(StubRoutines::riscv::arrays_hashcode_powers_of_31() != nullptr, "sanity"); + assert_different_registers(ary, cnt, result, tmp1, tmp2, tmp3, t0, t1); + + // The MaxVectorSize should have been set by detecting RVV max vector register + // size when check UseRVV (i.e. MaxVectorSize == VM_Version::_initial_vector_length). + // Let's use T_INT as all hashCode calculations eventually deal with ints. + const int lmul = 2; + const int stride = MaxVectorSize / sizeof(jint) * lmul; + + const int elsize_bytes = arrays_hashcode_elsize(eltype); + const int elsize_shift = exact_log2(elsize_bytes); + + switch (eltype) { + case T_BOOLEAN: BLOCK_COMMENT("arrays_hashcode_v(unsigned byte) {"); break; + case T_CHAR: BLOCK_COMMENT("arrays_hashcode_v(char) {"); break; + case T_BYTE: BLOCK_COMMENT("arrays_hashcode_v(byte) {"); break; + case T_SHORT: BLOCK_COMMENT("arrays_hashcode_v(short) {"); break; + case T_INT: BLOCK_COMMENT("arrays_hashcode_v(int) {"); break; + default: + ShouldNotReachHere(); + } + + const Register pow31_highest = tmp1; + const Register ary_end = tmp2; + const Register consumed = tmp3; + + const VectorRegister v_sum = v2; + const VectorRegister v_src = v4; + const VectorRegister v_coeffs = v6; + const VectorRegister v_tmp = v8; + + const address adr_pows31 = StubRoutines::riscv::arrays_hashcode_powers_of_31() + + sizeof(jint); + Label VEC_LOOP, DONE, SCALAR_TAIL, SCALAR_TAIL_LOOP; + + // NB: at this point (a) 'result' already has some value, + // (b) 'cnt' is not 0 or 1, see java code for details. + + andi(t0, cnt, ~(stride - 1)); + beqz(t0, SCALAR_TAIL); + + la(t1, ExternalAddress(adr_pows31)); + lw(pow31_highest, Address(t1, -1 * sizeof(jint))); + + vsetvli(consumed, cnt, Assembler::e32, Assembler::m2); + vle32_v(v_coeffs, t1); // 31^^(stride - 1) ... 31^^0 + vmv_v_x(v_sum, x0); + + bind(VEC_LOOP); + arrays_hashcode_elload_v(v_src, v_tmp, ary, eltype); + vmul_vv(v_src, v_src, v_coeffs); + vmadd_vx(v_sum, pow31_highest, v_src); + mulw(result, result, pow31_highest); + shadd(ary, consumed, ary, t0, elsize_shift); + subw(cnt, cnt, consumed); + andi(t1, cnt, ~(stride - 1)); + bnez(t1, VEC_LOOP); + + vmv_s_x(v_tmp, x0); + vredsum_vs(v_sum, v_sum, v_tmp); + vmv_x_s(t0, v_sum); + addw(result, result, t0); + beqz(cnt, DONE); + + bind(SCALAR_TAIL); + shadd(ary_end, cnt, ary, t0, elsize_shift); + + bind(SCALAR_TAIL_LOOP); + arrays_hashcode_elload(t0, Address(ary), eltype); + slli(t1, result, 5); // optimize 31 * result + subw(result, t1, result); // with result<<5 - result + addw(result, result, t0); + addi(ary, ary, elsize_bytes); + bne(ary, ary_end, SCALAR_TAIL_LOOP); + + bind(DONE); + BLOCK_COMMENT("} // arrays_hashcode_v"); +} + int C2_MacroAssembler::arrays_hashcode_elsize(BasicType eltype) { switch (eltype) { - case T_BOOLEAN: return sizeof(jboolean); - case T_BYTE: return sizeof(jbyte); - case T_SHORT: return sizeof(jshort); - case T_CHAR: return sizeof(jchar); - case T_INT: return sizeof(jint); - default: - ShouldNotReachHere(); - return -1; + case T_BOOLEAN: return sizeof(jboolean); + case T_BYTE: return sizeof(jbyte); + case T_SHORT: return sizeof(jshort); + case T_CHAR: return sizeof(jchar); + case T_INT: return sizeof(jint); + default: + ShouldNotReachHere(); + return -1; } } void C2_MacroAssembler::arrays_hashcode_elload(Register dst, Address src, BasicType eltype) { switch (eltype) { - // T_BOOLEAN used as surrogate for unsigned byte - case T_BOOLEAN: lbu(dst, src); break; - case T_BYTE: lb(dst, src); break; - case T_SHORT: lh(dst, src); break; - case T_CHAR: lhu(dst, src); break; - case T_INT: lw(dst, src); break; - default: - ShouldNotReachHere(); + // T_BOOLEAN used as surrogate for unsigned byte + case T_BOOLEAN: lbu(dst, src); break; + case T_BYTE: lb(dst, src); break; + case T_SHORT: lh(dst, src); break; + case T_CHAR: lhu(dst, src); break; + case T_INT: lw(dst, src); break; + default: + ShouldNotReachHere(); + } +} + +void C2_MacroAssembler::arrays_hashcode_elload_v(VectorRegister vdst, + VectorRegister vtmp, + Register src, + BasicType eltype) { + assert_different_registers(vdst, vtmp); + switch (eltype) { + case T_BOOLEAN: + vle8_v(vtmp, src); + vzext_vf4(vdst, vtmp); + break; + case T_BYTE: + vle8_v(vtmp, src); + vsext_vf4(vdst, vtmp); + break; + case T_CHAR: + vle16_v(vtmp, src); + vzext_vf2(vdst, vtmp); + break; + case T_SHORT: + vle16_v(vtmp, src); + vsext_vf2(vdst, vtmp); + break; + case T_INT: + vle32_v(vdst, src); + break; + default: + ShouldNotReachHere(); } } diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index 309ef8d9d5e..2d5339dc153 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -92,11 +92,15 @@ Register tmp3, Register tmp4, Register tmp5, Register tmp6, BasicType eltype); - - // helper function for arrays_hashcode int arrays_hashcode_elsize(BasicType eltype); void arrays_hashcode_elload(Register dst, Address src, BasicType eltype); + void arrays_hashcode_v(Register ary, Register cnt, Register result, + Register tmp1, Register tmp2, Register tmp3, + BasicType eltype); + void arrays_hashcode_elload_v(VectorRegister vdst, VectorRegister vtmp, + Register src, BasicType eltype); + void string_equals(Register r1, Register r2, Register result, Register cnt1); diff --git a/src/hotspot/cpu/riscv/frame_riscv.cpp b/src/hotspot/cpu/riscv/frame_riscv.cpp index b677c980c78..19dbdd6aeae 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.cpp +++ b/src/hotspot/cpu/riscv/frame_riscv.cpp @@ -217,8 +217,7 @@ bool frame::safe_for_sender(JavaThread *thread) { nmethod* nm = sender_blob->as_nmethod_or_null(); if (nm != nullptr) { - if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || - nm->method()->is_method_handle_intrinsic()) { + if (nm->is_deopt_entry(sender_pc) || nm->method()->is_method_handle_intrinsic()) { return false; } } @@ -427,49 +426,6 @@ JavaThread** frame::saved_thread_address(const frame& f) { return thread_addr; } -//------------------------------------------------------------------------------ -// frame::verify_deopt_original_pc -// -// Verifies the calculated original PC of a deoptimization PC for the -// given unextended SP. -#ifdef ASSERT -void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) { - frame fr; - - // This is ugly but it's better than to change {get,set}_original_pc - // to take an SP value as argument. And it's only a debugging - // method anyway. - fr._unextended_sp = unextended_sp; - - assert_cond(nm != nullptr); - address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains_inclusive(original_pc), - "original PC must be in the main code section of the compiled method (or must be immediately following it)"); -} -#endif - -//------------------------------------------------------------------------------ -// frame::adjust_unextended_sp -#ifdef ASSERT -void frame::adjust_unextended_sp() { - // On riscv, sites calling method handle intrinsics and lambda forms are treated - // as any other call site. Therefore, no special action is needed when we are - // returning to any of these call sites. - - if (_cb != nullptr) { - nmethod* sender_nm = _cb->as_nmethod_or_null(); - if (sender_nm != nullptr) { - // If the sender PC is a deoptimization point, get the original PC. - if (sender_nm->is_deopt_entry(_pc) || - sender_nm->is_deopt_mh_entry(_pc)) { - verify_deopt_original_pc(sender_nm, _unextended_sp); - } - } - } -} -#endif - - //------------------------------------------------------------------------------ // frame::sender_for_interpreter_frame frame frame::sender_for_interpreter_frame(RegisterMap* map) const { diff --git a/src/hotspot/cpu/riscv/frame_riscv.hpp b/src/hotspot/cpu/riscv/frame_riscv.hpp index b4540c45ab8..ce5a8dde230 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.hpp +++ b/src/hotspot/cpu/riscv/frame_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -179,17 +179,10 @@ int _offset_unextended_sp; // for use in stack-chunk frames }; - void adjust_unextended_sp() NOT_DEBUG_RETURN; - intptr_t* ptr_at_addr(int offset) const { return (intptr_t*) addr_at(offset); } -#ifdef ASSERT - // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp); -#endif - public: // Constructors diff --git a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp index fb31760e20b..51a203c548c 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -114,8 +114,6 @@ inline void frame::init(intptr_t* ptr_sp, intptr_t* ptr_fp, address pc) { } inline void frame::setup(address pc) { - adjust_unextended_sp(); - address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; @@ -215,7 +213,6 @@ inline frame::frame(intptr_t* ptr_sp, intptr_t* ptr_fp) { // value. _cb = CodeCache::find_blob(_pc); - adjust_unextended_sp(); address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { diff --git a/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp b/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp index 407017ee1c0..57223cf4390 100644 --- a/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp +++ b/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -44,8 +44,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define SUPPORTS_NATIVE_CX8 -#define SUPPORT_MONITOR_COUNT - #define SUPPORT_RESERVED_STACK_AREA #define USE_POINTERS_TO_REGISTER_IMPL_ARRAY diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index c9de1db0308..115b90a0087 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -225,36 +225,6 @@ void MacroAssembler::pop_cont_fastpath(Register java_thread) { bind(done); } -void MacroAssembler::inc_held_monitor_count(Register tmp) { - Address dst(xthread, JavaThread::held_monitor_count_offset()); - ld(tmp, dst); - addi(tmp, tmp, 1); - sd(tmp, dst); -#ifdef ASSERT - Label ok; - test_bit(tmp, tmp, 63); - beqz(tmp, ok); - STOP("assert(held monitor count overflow)"); - should_not_reach_here(); - bind(ok); -#endif -} - -void MacroAssembler::dec_held_monitor_count(Register tmp) { - Address dst(xthread, JavaThread::held_monitor_count_offset()); - ld(tmp, dst); - subi(tmp, tmp, 1); - sd(tmp, dst); -#ifdef ASSERT - Label ok; - test_bit(tmp, tmp, 63); - beqz(tmp, ok); - STOP("assert(held monitor count underflow)"); - should_not_reach_here(); - bind(ok); -#endif -} - int MacroAssembler::align(int modulus, int extra_offset) { CompressibleScope scope(this); intptr_t before = offset(); @@ -355,14 +325,15 @@ void MacroAssembler::call_VM(Register oop_result, } void MacroAssembler::post_call_nop() { + assert(!in_compressible_scope(), "Must be"); + assert_alignment(pc()); if (!Continuations::enabled()) { return; } - relocate(post_call_nop_Relocation::spec(), [&] { - InlineSkippedInstructionsCounter skipCounter(this); - nop(); - li32(zr, 0); - }); + relocate(post_call_nop_Relocation::spec()); + InlineSkippedInstructionsCounter skipCounter(this); + nop(); + li32(zr, 0); } // these are no-ops overridden by InterpreterMacroAssembler @@ -5013,7 +4984,7 @@ address MacroAssembler::reloc_call(Address entry, Register tmp) { address MacroAssembler::ic_call(address entry, jint method_index) { RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); - IncompressibleScope scope(this); // relocations + assert(!in_compressible_scope(), "Must be"); movptr(t0, (address)Universe::non_oop_word(), t1); assert_cond(entry != nullptr); return reloc_call(Address(entry, rh)); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 13b70d5dbd7..9e713e90270 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -849,9 +849,6 @@ class MacroAssembler: public Assembler { void push_cont_fastpath(Register java_thread = xthread); void pop_cont_fastpath(Register java_thread = xthread); - void inc_held_monitor_count(Register tmp); - void dec_held_monitor_count(Register tmp); - // if heap base register is used - reinit it with the correct value void reinit_heapbase(); diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp index 72cc95a595d..5d1cac72ade 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp @@ -331,13 +331,10 @@ bool NativeInstruction::is_safepoint_poll() { return MacroAssembler::is_lwu_to_zr(address(this)); } -void NativeIllegalInstruction::insert(address code_pos) { - assert_cond(code_pos != nullptr); - Assembler::sd_instr(code_pos, 0xffffffff); // all bits ones is permanently reserved as an illegal instruction -} - bool NativeInstruction::is_stop() { - return uint_at(0) == 0xc0101073; // an illegal instruction, 'csrrw x0, time, x0' + // an illegal instruction, 'csrrw x0, time, x0' + uint32_t encoded = Assembler::encode_csrrw(x0, Assembler::time, x0); + return uint_at(0) == encoded; } //------------------------------------------------------------------- @@ -347,6 +344,8 @@ void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { MacroAssembler a(&cb); Assembler::IncompressibleScope scope(&a); // Fixed length: see NativeGeneralJump::get_instruction_size() + MacroAssembler::assert_alignment(code_pos); + int32_t offset = 0; a.movptr(t1, entry, offset, t0); // lui, lui, slli, add a.jr(t1, offset); // jalr @@ -378,6 +377,7 @@ bool NativePostCallNop::decode(int32_t& oopmap_slot, int32_t& cb_offset) const { } bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) { + MacroAssembler::assert_alignment(addr_at(4)); if (((oopmap_slot & 0xff) != oopmap_slot) || ((cb_offset & 0xffffff) != cb_offset)) { return false; // cannot encode } @@ -389,14 +389,17 @@ bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) { return true; // successfully encoded } -void NativeDeoptInstruction::verify() { +bool NativeDeoptInstruction::is_deopt_at(address instr) { + assert(instr != nullptr, "Must be"); + uint32_t value = Assembler::ld_instr(instr); + uint32_t encoded = Assembler::encode_csrrw(x0, Assembler::instret, x0); + return value == encoded; } // Inserts an undefined instruction at a given pc void NativeDeoptInstruction::insert(address code_pos) { - // 0xc0201073 encodes CSRRW x0, instret, x0 - uint32_t insn = 0xc0201073; - uint32_t *pos = (uint32_t *) code_pos; - *pos = insn; + MacroAssembler::assert_alignment(code_pos); + uint32_t encoded = Assembler::encode_csrrw(x0, Assembler::instret, x0); + Assembler::sd_instr(code_pos, encoded); ICache::invalidate_range(code_pos, 4); } diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp index 4235e23d421..d990cfbc50d 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp @@ -294,12 +294,6 @@ inline NativeGeneralJump* nativeGeneralJump_at(address addr) { return jump; } -class NativeIllegalInstruction: public NativeInstruction { - public: - // Insert illegal opcode as specific address - static void insert(address code_pos); -}; - inline bool NativeInstruction::is_nop() const { uint32_t insn = Assembler::ld_instr(addr_at(0)); return insn == 0x13; @@ -353,14 +347,7 @@ class NativeDeoptInstruction: public NativeInstruction { address instruction_address() const { return addr_at(instruction_offset); } address next_instruction_address() const { return addr_at(instruction_size); } - void verify(); - - static bool is_deopt_at(address instr) { - assert(instr != nullptr, ""); - uint32_t value = Assembler::ld_instr(instr); - // 0xc0201073 encodes CSRRW x0, instret, x0 - return value == 0xc0201073; - } + static bool is_deopt_at(address instr); // MT-safe patching static void insert(address code_pos); diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 739a525c9a4..009acd628a0 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1269,6 +1269,26 @@ int CallDynamicJavaDirectNode::compute_padding(int current_offset) const return align_up(current_offset, alignment_required()) - current_offset; } +int CallRuntimeDirectNode::compute_padding(int current_offset) const +{ + return align_up(current_offset, alignment_required()) - current_offset; +} + +int CallLeafDirectNode::compute_padding(int current_offset) const +{ + return align_up(current_offset, alignment_required()) - current_offset; +} + +int CallLeafDirectVectorNode::compute_padding(int current_offset) const +{ + return align_up(current_offset, alignment_required()) - current_offset; +} + +int CallLeafNoFPDirectNode::compute_padding(int current_offset) const +{ + return align_up(current_offset, alignment_required()) - current_offset; +} + //============================================================================= #ifndef PRODUCT @@ -2132,10 +2152,6 @@ RegMask Matcher::modL_proj_mask() { return RegMask(); } -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return FP_REG_mask(); -} - bool size_fits_all_mem_uses(AddPNode* addp, int shift) { assert_cond(addp != nullptr); for (DUIterator_Fast imax, i = addp->fast_outs(imax); i < imax; i++) { @@ -8175,7 +8191,7 @@ instruct unnecessary_membar_volatile_rvtso() %{ ins_cost(0); size(0); - + format %{ "#@unnecessary_membar_volatile_rvtso (unnecessary so empty encoding)" %} ins_encode %{ __ block_comment("unnecessary_membar_volatile_rvtso"); @@ -10509,6 +10525,7 @@ instruct CallRuntimeDirect(method meth) ins_encode(riscv_enc_java_to_runtime(meth)); ins_pipe(pipe_class_call); + ins_alignment(4); %} // Call Runtime Instruction @@ -10526,6 +10543,7 @@ instruct CallLeafDirect(method meth) ins_encode(riscv_enc_java_to_runtime(meth)); ins_pipe(pipe_class_call); + ins_alignment(4); %} // Call Runtime Instruction without safepoint and with vector arguments @@ -10543,6 +10561,7 @@ instruct CallLeafDirectVector(method meth) ins_encode(riscv_enc_java_to_runtime(meth)); ins_pipe(pipe_class_call); + ins_alignment(4); %} // Call Runtime Instruction @@ -10560,6 +10579,7 @@ instruct CallLeafNoFPDirect(method meth) ins_encode(riscv_enc_java_to_runtime(meth)); ins_pipe(pipe_class_call); + ins_alignment(4); %} // ============================================================================ @@ -10971,6 +10991,7 @@ instruct arrays_hashcode(iRegP_R11 ary, iRegI_R12 cnt, iRegI_R10 result, immI ba iRegLNoSp tmp3, iRegLNoSp tmp4, iRegLNoSp tmp5, iRegLNoSp tmp6, rFlagsReg cr) %{ + predicate(!UseRVV); match(Set result (VectorizedHashCode (Binary ary cnt) (Binary result basic_type))); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6, USE_KILL ary, USE_KILL cnt, USE basic_type, KILL cr); diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index f2845ee2a6c..fe323474d60 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -4080,6 +4080,28 @@ instruct varray_equalsC(iRegP_R11 ary1, iRegP_R12 ary2, iRegI_R10 result, ins_pipe(pipe_class_memory); %} +// fast ArraysSupport.vectorizedHashCode +instruct varrays_hashcode(iRegP_R11 ary, iRegI_R12 cnt, iRegI_R10 result, immI basic_type, + vReg_V2 v2, vReg_V3 v3, vReg_V4 v4, vReg_V5 v5, + vReg_V6 v6, vReg_V7 v7, vReg_V8 v8, vReg_V9 v9, + iRegLNoSp tmp1, iRegLNoSp tmp2, iRegLNoSp tmp3, + rFlagsReg cr) +%{ + predicate(UseRVV); + match(Set result (VectorizedHashCode (Binary ary cnt) (Binary result basic_type))); + effect(USE_KILL ary, USE_KILL cnt, USE basic_type, + TEMP v2, TEMP v3, TEMP v4, TEMP v5, TEMP v6, TEMP v7, TEMP v8, TEMP v9, + TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + + format %{ "Array HashCode array[] $ary,$cnt,$result,$basic_type -> $result // KILL all" %} + ins_encode %{ + __ arrays_hashcode_v($ary$$Register, $cnt$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, + (BasicType)$basic_type$$constant); + %} + ins_pipe(pipe_class_memory); +%} + instruct vstring_compareU_128b(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, iRegI_R10 result, vReg_V4 v4, vReg_V5 v5, vReg_V6 v6, vReg_V7 v7, vReg_V8 v8, vReg_V9 v9, vReg_V10 v10, vReg_V11 v11, diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 01970c68090..b303178a666 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -885,11 +885,8 @@ static void fill_continuation_entry(MacroAssembler* masm) { __ ld(t0, Address(xthread, JavaThread::cont_fastpath_offset())); __ sd(t0, Address(sp, ContinuationEntry::parent_cont_fastpath_offset())); - __ ld(t0, Address(xthread, JavaThread::held_monitor_count_offset())); - __ sd(t0, Address(sp, ContinuationEntry::parent_held_monitor_count_offset())); __ sd(zr, Address(xthread, JavaThread::cont_fastpath_offset())); - __ sd(zr, Address(xthread, JavaThread::held_monitor_count_offset())); } // on entry, sp points to the ContinuationEntry @@ -905,50 +902,6 @@ static void continuation_enter_cleanup(MacroAssembler* masm) { __ ld(t0, Address(sp, ContinuationEntry::parent_cont_fastpath_offset())); __ sd(t0, Address(xthread, JavaThread::cont_fastpath_offset())); - - if (CheckJNICalls) { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ lwu(t0, Address(sp, ContinuationEntry::flags_offset())); - __ beqz(t0, L_skip_vthread_code); - - // If the held monitor count is > 0 and this vthread is terminating then - // it failed to release a JNI monitor. So we issue the same log message - // that JavaThread::exit does. - __ ld(t0, Address(xthread, JavaThread::jni_monitor_count_offset())); - __ beqz(t0, L_skip_vthread_code); - - // Save return value potentially containing the exception oop in callee-saved x9 - __ mv(x9, x10); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::log_jni_monitor_still_held)); - // Restore potential return value - __ mv(x10, x9); - - // For vthreads we have to explicitly zero the JNI monitor count of the carrier - // on termination. The held count is implicitly zeroed below when we restore from - // the parent held count (which has to be zero). - __ sd(zr, Address(xthread, JavaThread::jni_monitor_count_offset())); - - __ bind(L_skip_vthread_code); - } -#ifdef ASSERT - else { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ lwu(t0, Address(sp, ContinuationEntry::flags_offset())); - __ beqz(t0, L_skip_vthread_code); - - // See comment just above. If not checking JNI calls the JNI count is only - // needed for assertion checking. - __ sd(zr, Address(xthread, JavaThread::jni_monitor_count_offset())); - - __ bind(L_skip_vthread_code); - } -#endif - - __ ld(t0, Address(sp, ContinuationEntry::parent_held_monitor_count_offset())); - __ sd(t0, Address(xthread, JavaThread::held_monitor_count_offset())); - __ ld(t0, Address(sp, ContinuationEntry::parent_offset())); __ sd(t0, Address(xthread, JavaThread::cont_entry_offset())); __ add(fp, sp, (int)ContinuationEntry::size() + 2 * wordSize /* 2 extra words to match up with leave() */); @@ -1002,20 +955,23 @@ static void gen_continuation_enter(MacroAssembler* masm, __ bnez(c_rarg2, call_thaw); - // Make sure the call is patchable - __ align(NativeInstruction::instruction_size); - - const address tr_call = __ reloc_call(resolve); - if (tr_call == nullptr) { - fatal("CodeCache is full at gen_continuation_enter"); - } + address call_pc; + { + Assembler::IncompressibleScope scope(masm); + // Make sure the call is patchable + __ align(NativeInstruction::instruction_size); - oop_maps->add_gc_map(__ pc() - start, map); - __ post_call_nop(); + call_pc = __ reloc_call(resolve); + if (call_pc == nullptr) { + fatal("CodeCache is full at gen_continuation_enter"); + } + oop_maps->add_gc_map(__ pc() - start, map); + __ post_call_nop(); + } __ j(exit); - address stub = CompiledDirectCall::emit_to_interp_stub(masm, tr_call); + address stub = CompiledDirectCall::emit_to_interp_stub(masm, call_pc); if (stub == nullptr) { fatal("CodeCache is full at gen_continuation_enter"); } @@ -1034,26 +990,36 @@ static void gen_continuation_enter(MacroAssembler* masm, __ bnez(c_rarg2, call_thaw); - // Make sure the call is patchable - __ align(NativeInstruction::instruction_size); + address call_pc; + { + Assembler::IncompressibleScope scope(masm); + // Make sure the call is patchable + __ align(NativeInstruction::instruction_size); - const address tr_call = __ reloc_call(resolve); - if (tr_call == nullptr) { - fatal("CodeCache is full at gen_continuation_enter"); - } + call_pc = __ reloc_call(resolve); + if (call_pc == nullptr) { + fatal("CodeCache is full at gen_continuation_enter"); + } - oop_maps->add_gc_map(__ pc() - start, map); - __ post_call_nop(); + oop_maps->add_gc_map(__ pc() - start, map); + __ post_call_nop(); + } __ j(exit); __ bind(call_thaw); - ContinuationEntry::_thaw_call_pc_offset = __ pc() - start; - __ rt_call(CAST_FROM_FN_PTR(address, StubRoutines::cont_thaw())); - oop_maps->add_gc_map(__ pc() - start, map->deep_copy()); - ContinuationEntry::_return_pc_offset = __ pc() - start; - __ post_call_nop(); + // Post call nops must be natural aligned due to cmodx rules. + { + Assembler::IncompressibleScope scope(masm); + __ align(NativeInstruction::instruction_size); + + ContinuationEntry::_thaw_call_pc_offset = __ pc() - start; + __ rt_call(CAST_FROM_FN_PTR(address, StubRoutines::cont_thaw())); + oop_maps->add_gc_map(__ pc() - start, map->deep_copy()); + ContinuationEntry::_return_pc_offset = __ pc() - start; + __ post_call_nop(); + } __ bind(exit); ContinuationEntry::_cleanup_offset = __ pc() - start; @@ -1082,7 +1048,7 @@ static void gen_continuation_enter(MacroAssembler* masm, __ jr(x11); // the exception handler } - address stub = CompiledDirectCall::emit_to_interp_stub(masm, tr_call); + address stub = CompiledDirectCall::emit_to_interp_stub(masm, call_pc); if (stub == nullptr) { fatal("CodeCache is full at gen_continuation_enter"); } @@ -1115,10 +1081,16 @@ static void gen_continuation_yield(MacroAssembler* masm, __ mv(c_rarg1, sp); + // Post call nops must be natural aligned due to cmodx rules. + __ align(NativeInstruction::instruction_size); + frame_complete = __ pc() - start; address the_pc = __ pc(); - __ post_call_nop(); // this must be exactly after the pc value that is pushed into the frame info, we use this nop for fast CodeBlob lookup + { + Assembler::IncompressibleScope scope(masm); + __ post_call_nop(); // this must be exactly after the pc value that is pushed into the frame info, we use this nop for fast CodeBlob lookup + } __ mv(c_rarg0, xthread); __ set_last_Java_frame(sp, fp, the_pc, t0); @@ -1677,8 +1649,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label lock_done; if (method->is_synchronized()) { - const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes(); - // Get the handle (the 2nd argument) __ mv(oop_handle_reg, c_rarg1); diff --git a/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp b/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp index fe7f52884fa..f977d759d20 100644 --- a/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp +++ b/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp @@ -73,6 +73,9 @@ do_stub(compiler, string_indexof_linear_ul) \ do_arch_entry(riscv, compiler, string_indexof_linear_ul, \ string_indexof_linear_ul, string_indexof_linear_ul) \ + do_stub(compiler, arrays_hashcode_powers_of_31) \ + do_arch_entry(riscv, compiler, arrays_hashcode_powers_of_31, \ + arrays_hashcode_powers_of_31, arrays_hashcode_powers_of_31) \ #define STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub, \ diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 88961ccd5a4..ec268d9bb65 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -6624,6 +6624,24 @@ static const int64_t right_3_bits = right_n_bits(3); return start; } + address generate_arrays_hashcode_powers_of_31() { + assert(UseRVV, "sanity"); + const int lmul = 2; + const int stride = MaxVectorSize / sizeof(jint) * lmul; + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "arrays_hashcode_powers_of_31"); + address start = __ pc(); + for (int i = stride; i >= 0; i--) { + jint power_of_31 = 1; + for (int j = i; j > 0; j--) { + power_of_31 = java_multiply(power_of_31, 31); + } + __ emit_int32(power_of_31); + } + + return start; + } + #endif // COMPILER2 /** @@ -6818,6 +6836,10 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_bigIntegerRightShiftWorker = generate_bigIntegerRightShift(); } + if (UseVectorizedHashCodeIntrinsic && UseRVV) { + StubRoutines::riscv::_arrays_hashcode_powers_of_31 = generate_arrays_hashcode_powers_of_31(); + } + if (UseSHA256Intrinsics) { Sha2Generator sha2(_masm, this); StubRoutines::_sha256_implCompress = sha2.generate_sha256_implCompress(StubId::stubgen_sha256_implCompress_id); diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 1bb9509cdde..53f7ff9bc66 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -35,15 +35,28 @@ uint32_t VM_Version::_initial_vector_length = 0; -#define DEF_RV_FEATURE(NAME, PRETTY, BIT, FSTRING, FLAGF) \ -VM_Version::NAME##RVFeatureValue VM_Version::NAME(PRETTY, BIT, FSTRING); -RV_FEATURE_FLAGS(DEF_RV_FEATURE) - -#define ADD_RV_FEATURE_IN_LIST(NAME, PRETTY, BIT, FSTRING, FLAGF) \ - &VM_Version::NAME, -VM_Version::RVFeatureValue* VM_Version::_feature_list[] = { -RV_FEATURE_FLAGS(ADD_RV_FEATURE_IN_LIST) +#define DEF_RV_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \ +VM_Version::NAME##RVExtFeatureValue VM_Version::NAME; +RV_EXT_FEATURE_FLAGS(DEF_RV_EXT_FEATURE) +#undef DEF_RV_EXT_FEATURE + +#define DEF_RV_NON_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \ +VM_Version::NAME##RVNonExtFeatureValue VM_Version::NAME; +RV_NON_EXT_FEATURE_FLAGS(DEF_RV_NON_EXT_FEATURE) +#undef DEF_RV_NON_EXT_FEATURE + +#define ADD_RV_EXT_FEATURE_IN_LIST(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \ + &VM_Version::NAME, +#define ADD_RV_NON_EXT_FEATURE_IN_LIST(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \ + &VM_Version::NAME, + VM_Version::RVFeatureValue* VM_Version::_feature_list[] = { + RV_EXT_FEATURE_FLAGS(ADD_RV_EXT_FEATURE_IN_LIST) + RV_NON_EXT_FEATURE_FLAGS(ADD_RV_NON_EXT_FEATURE_IN_LIST) nullptr}; +#undef ADD_RV_NON_EXT_FEATURE_IN_LIST +#undef ADD_RV_EXT_FEATURE_IN_LIST + +VM_Version::RVExtFeatures* VM_Version::_rv_ext_features = new VM_Version::RVExtFeatures(); void VM_Version::useRVA20U64Profile() { RV_USE_RVA20U64; @@ -147,7 +160,7 @@ void VM_Version::common_initialize() { if (FLAG_IS_DEFAULT(AvoidUnalignedAccesses)) { FLAG_SET_DEFAULT(AvoidUnalignedAccesses, - unaligned_access.value() != MISALIGNED_FAST); + unaligned_scalar.value() != MISALIGNED_SCALAR_FAST); } if (!AvoidUnalignedAccesses) { @@ -162,7 +175,12 @@ void VM_Version::common_initialize() { // This machine has fast unaligned memory accesses if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { FLAG_SET_DEFAULT(UseUnalignedAccesses, - unaligned_access.value() == MISALIGNED_FAST); + (unaligned_scalar.value() == MISALIGNED_SCALAR_FAST)); + } + + if (FLAG_IS_DEFAULT(AlignVector)) { + FLAG_SET_DEFAULT(AlignVector, + unaligned_vector.value() != MISALIGNED_VECTOR_FAST); } #ifdef __riscv_ztso @@ -195,13 +213,8 @@ void VM_Version::common_initialize() { } if (UseRVV) { - if (!ext_V.enabled() && FLAG_IS_DEFAULT(UseRVV)) { - warning("RVV is not supported on this CPU"); - FLAG_SET_DEFAULT(UseRVV, false); - } else { - // read vector length from vector CSR vlenb - _initial_vector_length = cpu_vector_length(); - } + // read vector length from vector CSR vlenb + _initial_vector_length = cpu_vector_length(); } // Misc Intrinsics that could depend on RVV. @@ -221,36 +234,6 @@ void VM_Version::common_initialize() { warning("CRC32C intrinsics are not available on this CPU."); FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); } - - // UseZvbb (depends on RVV). - if (UseZvbb && !UseRVV) { - warning("Cannot enable UseZvbb on cpu without RVV support."); - FLAG_SET_DEFAULT(UseZvbb, false); - } - - // UseZvbc (depends on RVV). - if (UseZvbc && !UseRVV) { - warning("Cannot enable UseZvbc on cpu without RVV support."); - FLAG_SET_DEFAULT(UseZvbc, false); - } - - // UseZvkn (depends on RVV). - if (UseZvkn && !UseRVV) { - warning("Cannot enable UseZvkn on cpu without RVV support."); - FLAG_SET_DEFAULT(UseZvkn, false); - } - - // UseZvfh (depends on RVV) - if (UseZvfh) { - if (!UseRVV) { - warning("Cannot enable UseZvfh on cpu without RVV support."); - FLAG_SET_DEFAULT(UseZvfh, false); - } - if (!UseZfh) { - warning("Cannot enable UseZvfh on cpu without Zfh support."); - FLAG_SET_DEFAULT(UseZvfh, false); - } - } } #ifdef COMPILER2 diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index d94385cd8ac..b3d905dff9d 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -46,31 +46,59 @@ class VM_Version : public Abstract_VM_Version { RIVOS = 0x6cf, // JEDEC: 0x4f, Bank: 14 }; + class RVExtFeatures; + class RVFeatureValue { const char* const _pretty; const bool _feature_string; - const uint64_t _feature_bit; - bool _enabled; + const uint64_t _linux_feature_bit; int64_t _value; public: - RVFeatureValue(const char* pretty, int bit_num, bool fstring) : - _pretty(pretty), _feature_string(fstring), _feature_bit(nth_bit(bit_num)), - _enabled(false), _value(-1) { + RVFeatureValue(const char* pretty, int linux_bit_num, bool fstring) : + _pretty(pretty), _feature_string(fstring), _linux_feature_bit(nth_bit(linux_bit_num)), + _value(-1) { } - void enable_feature(int64_t value = 0) { - _enabled = true; + virtual void enable_feature(int64_t value = 0) { _value = value; } - void disable_feature() { - _enabled = false; + virtual void disable_feature() { _value = -1; } const char* pretty() { return _pretty; } - uint64_t feature_bit() { return _feature_bit; } + uint64_t feature_bit() { return _linux_feature_bit; } bool feature_string() { return _feature_string; } - bool enabled() { return _enabled; } int64_t value() { return _value; } + virtual bool enabled() = 0; virtual void update_flag() = 0; + + protected: + bool deps_all_enabled(RVFeatureValue* dep0, ...) { + assert(dep0 != nullptr, "must not"); + + va_list va; + va_start(va, dep0); + RVFeatureValue* next = dep0; + bool enabled = true; + while (next != nullptr && enabled) { + enabled = next->enabled(); + next = va_arg(va, RVFeatureValue*); + } + va_end(va); + return enabled; + } + + void deps_string(stringStream& ss, RVFeatureValue* dep0, ...) { + assert(dep0 != nullptr, "must not"); + ss.print("%s (%s)", dep0->pretty(), dep0->enabled() ? "enabled" : "disabled"); + + va_list va; + va_start(va, dep0); + RVFeatureValue* next = nullptr; + while ((next = va_arg(va, RVFeatureValue*)) != nullptr) { + ss.print(", %s (%s)", next->pretty(), next->enabled() ? "enabled" : "disabled"); + } + va_end(va); + } }; #define UPDATE_DEFAULT(flag) \ @@ -86,31 +114,77 @@ class VM_Version : public Abstract_VM_Version { } \ } \ - #define UPDATE_DEFAULT_DEP(flag, dep) \ - void update_flag() { \ - assert(enabled(), "Must be."); \ - /* dep must be declared before */ \ - assert((uintptr_t)(this) > \ - (uintptr_t)(&dep), "Invalid"); \ - if (FLAG_IS_DEFAULT(flag)) { \ - if (dep.enabled()) { \ - FLAG_SET_DEFAULT(flag, true); \ - } else { \ - FLAG_SET_DEFAULT(flag, false); \ - /* Sync CPU features with flags */ \ - disable_feature(); \ - } \ - } else { \ - /* Sync CPU features with flags */ \ - if (!flag) { \ - disable_feature(); \ - } \ - } \ - } \ + #define UPDATE_DEFAULT_DEP(flag, dep0, ...) \ + void update_flag() { \ + assert(enabled(), "Must be."); \ + if (FLAG_IS_DEFAULT(flag)) { \ + if (this->deps_all_enabled(dep0, ##__VA_ARGS__)) { \ + FLAG_SET_DEFAULT(flag, true); \ + } else { \ + FLAG_SET_DEFAULT(flag, false); \ + stringStream ss; \ + deps_string(ss, dep0, ##__VA_ARGS__); \ + warning("Cannot enable " #flag ", it's missing dependent extension(s) %s", ss.as_string(true)); \ + /* Sync CPU features with flags */ \ + disable_feature(); \ + } \ + } else { \ + /* Sync CPU features with flags */ \ + if (!flag) { \ + disable_feature(); \ + } else if (!deps_all_enabled(dep0, ##__VA_ARGS__)) { \ + FLAG_SET_DEFAULT(flag, false); \ + stringStream ss; \ + deps_string(ss, dep0, ##__VA_ARGS__); \ + warning("Cannot enable " #flag ", it's missing dependent extension(s) %s", ss.as_string(true)); \ + /* Sync CPU features with flags */ \ + disable_feature(); \ + } \ + } \ + } \ #define NO_UPDATE_DEFAULT \ void update_flag() {} \ + + class RVExtFeatureValue : public RVFeatureValue { + const uint32_t _cpu_feature_index; + public: + RVExtFeatureValue(const char* pretty, int linux_bit_num, uint32_t cpu_feature_index, bool fstring) : + RVFeatureValue(pretty, linux_bit_num, fstring), + _cpu_feature_index(cpu_feature_index) { + } + bool enabled() { + return RVExtFeatures::current()->support_feature(_cpu_feature_index); + } + void enable_feature(int64_t value = 0) { + RVFeatureValue::enable_feature(value); + RVExtFeatures::current()->set_feature(_cpu_feature_index); + } + void disable_feature() { + RVFeatureValue::disable_feature(); + RVExtFeatures::current()->clear_feature(_cpu_feature_index); + } + }; + + class RVNonExtFeatureValue : public RVFeatureValue { + bool _enabled; + public: + RVNonExtFeatureValue(const char* pretty, int linux_bit_num, bool fstring) : + RVFeatureValue(pretty, linux_bit_num, fstring), + _enabled(false) { + } + bool enabled() { return _enabled; } + void enable_feature(int64_t value = 0) { + RVFeatureValue::enable_feature(value); + _enabled = true; + } + void disable_feature() { + RVFeatureValue::disable_feature(); + _enabled = false; + } + }; + // Frozen standard extensions // I RV64I // M Integer Multiplication and Division @@ -153,7 +227,8 @@ class VM_Version : public Abstract_VM_Version { // mvendorid Manufactory JEDEC id encoded, ISA vol 2 3.1.2.. // marchid Id for microarch. Mvendorid plus marchid uniquely identify the microarch. // mimpid A unique encoding of the version of the processor implementation. - // unaligned_access Unaligned memory accesses (unknown, unspported, emulated, slow, firmware, fast) + // unaligned_scalar Performance of misaligned scalar accesses (unknown, emulated, slow, fast, unsupported) + // unaligned_vector Performance of misaligned vector accesses (unknown, unspported, slow, fast) // satp mode SATP bits (number of virtual addr bits) mbare, sv39, sv48, sv57, sv64 public: @@ -161,58 +236,141 @@ class VM_Version : public Abstract_VM_Version { #define RV_NO_FLAG_BIT (BitsPerWord+1) // nth_bit will return 0 on values larger than BitsPerWord // Note: the order matters, depender should be after their dependee. E.g. ext_V before ext_Zvbb. - // declaration name , extension name, bit pos ,in str, mapped flag) - #define RV_FEATURE_FLAGS(decl) \ - decl(ext_I , "i" , ('I' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_M , "m" , ('M' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_A , "a" , ('A' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_F , "f" , ('F' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_D , "d" , ('D' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_C , "c" , ('C' - 'A'), true , UPDATE_DEFAULT(UseRVC)) \ - decl(ext_Q , "q" , ('Q' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_H , "h" , ('H' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_V , "v" , ('V' - 'A'), true , UPDATE_DEFAULT(UseRVV)) \ - decl(ext_Zicbom , "Zicbom" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbom)) \ - decl(ext_Zicboz , "Zicboz" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicboz)) \ - decl(ext_Zicbop , "Zicbop" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbop)) \ - decl(ext_Zba , "Zba" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZba)) \ - decl(ext_Zbb , "Zbb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \ - decl(ext_Zbc , "Zbc" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ - decl(ext_Zbs , "Zbs" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \ - decl(ext_Zbkb , "Zbkb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbkb)) \ - decl(ext_Zcb , "Zcb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZcb)) \ - decl(ext_Zfa , "Zfa" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfa)) \ - decl(ext_Zfh , "Zfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \ - decl(ext_Zfhmin , "Zfhmin" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfhmin)) \ - decl(ext_Zicsr , "Zicsr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ - decl(ext_Zicntr , "Zicntr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ - decl(ext_Zifencei , "Zifencei" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ - decl(ext_Zic64b , "Zic64b" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \ - decl(ext_Ztso , "Ztso" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso)) \ - decl(ext_Zihintpause , "Zihintpause" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \ - decl(ext_Zacas , "Zacas" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas)) \ - decl(ext_Zvbb , "Zvbb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbb, ext_V)) \ - decl(ext_Zvbc , "Zvbc" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbc, ext_V)) \ - decl(ext_Zvfh , "Zvfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvfh, ext_V)) \ - decl(ext_Zvkn , "Zvkn" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvkn, ext_V)) \ - decl(ext_Zicond , "Zicond" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicond)) \ - decl(mvendorid , "VendorId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ - decl(marchid , "ArchId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ - decl(mimpid , "ImpId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ - decl(unaligned_access , "Unaligned" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ - decl(satp_mode , "SATP" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ - decl(zicboz_block_size, "ZicbozBlockSize", RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ - - #define DECLARE_RV_FEATURE(NAME, PRETTY, BIT, FSTRING, FLAGF) \ - struct NAME##RVFeatureValue : public RVFeatureValue { \ - NAME##RVFeatureValue(const char* pretty, int bit, bool fstring) : \ - RVFeatureValue(pretty, bit, fstring) {} \ - FLAGF; \ - }; \ - static NAME##RVFeatureValue NAME; \ - - RV_FEATURE_FLAGS(DECLARE_RV_FEATURE) - #undef DECLARE_RV_FEATURE + // + // Fields description in `decl`: + // declaration name, extension name, bit value from linux, feature string?, mapped flag) + #define RV_EXT_FEATURE_FLAGS(decl) \ + decl(ext_I , i , ('I' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_M , m , ('M' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_A , a , ('A' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_F , f , ('F' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_D , d , ('D' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_C , c , ('C' - 'A'), true , UPDATE_DEFAULT(UseRVC)) \ + decl(ext_Q , q , ('Q' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_H , h , ('H' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_V , v , ('V' - 'A'), true , UPDATE_DEFAULT(UseRVV)) \ + decl(ext_Zicbom , Zicbom , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbom)) \ + decl(ext_Zicboz , Zicboz , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicboz)) \ + decl(ext_Zicbop , Zicbop , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbop)) \ + decl(ext_Zba , Zba , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZba)) \ + decl(ext_Zbb , Zbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \ + decl(ext_Zbc , Zbc , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ + decl(ext_Zbs , Zbs , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \ + decl(ext_Zbkb , Zbkb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbkb)) \ + decl(ext_Zcb , Zcb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZcb)) \ + decl(ext_Zfa , Zfa , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfa)) \ + decl(ext_Zfh , Zfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \ + decl(ext_Zfhmin , Zfhmin , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfhmin)) \ + decl(ext_Zicsr , Zicsr , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ + decl(ext_Zicntr , Zicntr , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ + decl(ext_Zifencei , Zifencei , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ + decl(ext_Zic64b , Zic64b , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \ + decl(ext_Ztso , Ztso , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso)) \ + decl(ext_Zihintpause , Zihintpause , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \ + decl(ext_Zacas , Zacas , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas)) \ + decl(ext_Zvbb , Zvbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbb, &ext_V, nullptr)) \ + decl(ext_Zvbc , Zvbc , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbc, &ext_V, nullptr)) \ + decl(ext_Zvfh , Zvfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvfh, &ext_V, &ext_Zfh, nullptr)) \ + decl(ext_Zvkn , Zvkn , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvkn, &ext_V, nullptr)) \ + decl(ext_Zicond , Zicond , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicond)) \ + + #define DECLARE_RV_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \ + struct NAME##RVExtFeatureValue : public RVExtFeatureValue { \ + NAME##RVExtFeatureValue() : \ + RVExtFeatureValue(#PRETTY, LINUX_BIT, RVExtFeatures::CPU_##NAME, FSTRING) {} \ + FLAGF; \ + }; \ + static NAME##RVExtFeatureValue NAME; \ + + RV_EXT_FEATURE_FLAGS(DECLARE_RV_EXT_FEATURE) + #undef DECLARE_RV_EXT_FEATURE + + // Non-extension features + // + #define RV_NON_EXT_FEATURE_FLAGS(decl) \ + decl(mvendorid , VendorId , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + decl(marchid , ArchId , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + decl(mimpid , ImpId , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + decl(satp_mode , SATP , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + decl(unaligned_scalar , UnalignedScalar , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + decl(unaligned_vector , UnalignedVector , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + decl(zicboz_block_size, ZicbozBlockSize , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + + #define DECLARE_RV_NON_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \ + struct NAME##RVNonExtFeatureValue : public RVNonExtFeatureValue { \ + NAME##RVNonExtFeatureValue() : \ + RVNonExtFeatureValue(#PRETTY, LINUX_BIT, FSTRING) {} \ + FLAGF; \ + }; \ + static NAME##RVNonExtFeatureValue NAME; \ + + RV_NON_EXT_FEATURE_FLAGS(DECLARE_RV_NON_EXT_FEATURE) + #undef DECLARE_RV_NON_EXT_FEATURE + +private: + // Utility for AOT CPU feature store/check. + class RVExtFeatures : public CHeapObj { + public: + enum RVFeatureIndex { + #define DECLARE_RV_FEATURE_ENUM(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) CPU_##NAME, + + RV_EXT_FEATURE_FLAGS(DECLARE_RV_FEATURE_ENUM) + MAX_CPU_FEATURE_INDEX + #undef DECLARE_RV_FEATURE_ENUM + }; + private: + uint64_t _features_bitmap[(MAX_CPU_FEATURE_INDEX / BitsPerLong) + 1]; + STATIC_ASSERT(sizeof(_features_bitmap) * BitsPerByte >= MAX_CPU_FEATURE_INDEX); + + // Number of 8-byte elements in _features_bitmap. + constexpr static int element_count() { + return sizeof(_features_bitmap) / sizeof(uint64_t); + } + + static int element_index(RVFeatureIndex feature) { + int idx = feature / BitsPerLong; + assert(idx < element_count(), "Features array index out of bounds"); + return idx; + } + + static uint64_t feature_bit(RVFeatureIndex feature) { + return (1ULL << (feature % BitsPerLong)); + } + + static RVFeatureIndex convert(uint32_t index) { + assert(index < MAX_CPU_FEATURE_INDEX, "must"); + return (RVFeatureIndex)index; + } + + public: + static RVExtFeatures* current() { + return _rv_ext_features; + } + + RVExtFeatures() { + for (int i = 0; i < element_count(); i++) { + _features_bitmap[i] = 0; + } + } + + void set_feature(uint32_t feature) { + RVFeatureIndex f = convert(feature); + int idx = element_index(f); + _features_bitmap[idx] |= feature_bit(f); + } + + void clear_feature(uint32_t feature) { + RVFeatureIndex f = convert(feature); + int idx = element_index(f); + _features_bitmap[idx] &= ~feature_bit(f); + } + + bool support_feature(uint32_t feature) { + RVFeatureIndex f = convert(feature); + int idx = element_index(f); + return (_features_bitmap[idx] & feature_bit(f)) != 0; + } + }; // enable extensions based on profile, current supported profiles: // RVA20U64 @@ -276,16 +434,24 @@ class VM_Version : public Abstract_VM_Version { static VM_MODE parse_satp_mode(const char* vm_mode); // Values from riscv_hwprobe() - enum UNALIGNED_ACCESS : int { - MISALIGNED_UNKNOWN = 0, - MISALIGNED_EMULATED = 1, - MISALIGNED_SLOW = 2, - MISALIGNED_FAST = 3, - MISALIGNED_UNSUPPORTED = 4 + enum UNALIGNED_SCALAR_ACCESS : int { + MISALIGNED_SCALAR_UNKNOWN = 0, + MISALIGNED_SCALAR_EMULATED = 1, + MISALIGNED_SCALAR_SLOW = 2, + MISALIGNED_SCALAR_FAST = 3, + MISALIGNED_SCALAR_UNSUPPORTED = 4 + }; + + enum UNALIGNED_VECTOR_ACCESS : int { + MISALIGNED_VECTOR_UNKNOWN = 0, + MISALIGNED_VECTOR_SLOW = 2, + MISALIGNED_VECTOR_FAST = 3, + MISALIGNED_VECTOR_UNSUPPORTED = 4 }; // Null terminated list static RVFeatureValue* _feature_list[]; + static RVExtFeatures* _rv_ext_features; // Enables features in _feature_list static void setup_cpu_available_features(); diff --git a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp index 68e7114b3b6..f1272ee1a22 100644 --- a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp +++ b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp @@ -234,12 +234,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); // Move address of the BasicObjectLock into Z_R1_scratch. - if (_compute_lock) { - // Lock_reg was destroyed by fast unlocking attempt => recompute it. - ce->monitor_address(_monitor_ix, FrameMap::as_opr(Z_R1_scratch)); - } else { - __ lgr_if_needed(Z_R1_scratch, _lock_reg->as_register()); - } + + // Lock_reg was destroyed by fast unlocking attempt => recompute it. + ce->monitor_address(_monitor_ix, FrameMap::as_opr(Z_R1_scratch)); + // Note: non-blocking leaf routine => no call info needed. StubId exit_id; if (ce->compilation()->has_fpu_code()) { diff --git a/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp b/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp index ddba445154a..e219e9bbb40 100644 --- a/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp +++ b/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp @@ -282,13 +282,6 @@ LIR_Opr FrameMap::stack_pointer() { return Z_SP_opr; } -// JSR 292 -// On ZARCH_64, there is no need to save the SP, because neither -// method handle intrinsics nor compiled lambda forms modify it. -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - return LIR_OprFact::illegalOpr; -} - bool FrameMap::validate_frame() { return true; } diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index b875eeca9ad..298234156c3 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -228,7 +228,7 @@ int LIR_Assembler::emit_unwind_handler() { // StubId::c1_monitorexit_id expects lock address in Z_R1_scratch. LIR_Opr lock = FrameMap::as_opr(Z_R1_scratch); monitor_address(0, lock); - stub = new MonitorExitStub(lock, true, 0); + stub = new MonitorExitStub(lock, 0); __ unlock_object(Rtmp1, Rtmp2, lock->as_register(), *stub->entry()); __ bind(*stub->continuation()); } @@ -2711,7 +2711,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); if (op->code() == lir_lock) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); // Add debug info for NullPointerException only if one is possible. if (op->info() != nullptr) { add_debug_info_for_null_check_here(op->info()); @@ -2719,7 +2718,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { __ lock_object(hdr, obj, lock, *op->stub()->entry()); // done } else if (op->code() == lir_unlock) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); __ unlock_object(hdr, obj, lock, *op->stub()->entry()); } else { ShouldNotReachHere(); diff --git a/src/hotspot/cpu/s390/c2_globals_s390.hpp b/src/hotspot/cpu/s390/c2_globals_s390.hpp index 94190c25f5b..f1e757889b0 100644 --- a/src/hotspot/cpu/s390/c2_globals_s390.hpp +++ b/src/hotspot/cpu/s390/c2_globals_s390.hpp @@ -45,8 +45,7 @@ define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, OnStackReplacePercentage, 140); define_pd_global(intx, ConditionalMoveLimit, 4); define_pd_global(intx, FreqInlineSize, 175); -// 10 prevents spill-split-recycle sanity check in JVM2008.xml.transform. -define_pd_global(intx, InteriorEntryAlignment, 2); +define_pd_global(intx, InteriorEntryAlignment, 4); define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, RegisterCostAreaRatio, 12000); define_pd_global(intx, LoopUnrollLimit, 60); diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 4c6b0d96e6f..cfc8b19534b 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -1947,6 +1947,7 @@ bool Matcher::is_spillable_arg(int reg) { uint Matcher::int_pressure_limit() { // Medium size register set, 6 special purpose regs, 3 SOE regs. + // 10 prevents spill-split-recycle sanity check in JVM2008.xml.transform. return (INTPRESSURE == -1) ? 10 : INTPRESSURE; } @@ -1979,11 +1980,6 @@ RegMask Matcher::modL_proj_mask() { return _Z_RARG3_LONG_REG_mask; } -// Copied from sparc. -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return RegMask(); -} - // Should the matcher clone input 'm' of node 'n'? bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { if (is_encode_and_store_pattern(n, m)) { diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 3f1140c937b..fd62e9358bf 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -2225,6 +2225,44 @@ void Assembler::cvttss2sil(Register dst, XMMRegister src) { emit_int16(0x2C, (0xC0 | encode)); } +void Assembler::evcvttss2sisl(Register dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttss2sisl(Register dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + +void Assembler::evcvttss2sisq(Register dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttss2sisq(Register dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::cvttpd2dq(XMMRegister dst, XMMRegister src) { int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_128bit; InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2310,6 +2348,25 @@ void Assembler::vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len) { emit_int16(0x5B, (0xC0 | encode)); } +void Assembler::evcvttps2dqs(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttps2dqs(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len) { assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2317,6 +2374,25 @@ void Assembler::vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len) { emit_int16((unsigned char)0xE6, (0xC0 | encode)); } +void Assembler::evcvttpd2dqs(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttpd2dqs(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len) { assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2332,6 +2408,25 @@ void Assembler::evcvttps2qq(XMMRegister dst, XMMRegister src, int vector_len) { emit_int16(0x7A, (0xC0 | encode)); } +void Assembler::evcvttps2qqs(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttps2qqs(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_HV, /* input_size_in_bits */ EVEX_32bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2356,6 +2451,25 @@ void Assembler::evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len) { emit_int16(0x7A, (0xC0 | encode)); } +void Assembler::evcvttpd2qqs(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttpd2qqs(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::evcvtqq2pd(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -14988,6 +15102,44 @@ void Assembler::cvttsd2siq(Register dst, Address src) { emit_operand(dst, src, 0); } +void Assembler::evcvttsd2sisl(Register dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttsd2sisl(Register dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + +void Assembler::evcvttsd2sisq(Register dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttsd2sisq(Register dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::cvttsd2siq(Register dst, XMMRegister src) { InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 99dade412b2..c863191df4c 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -1316,11 +1316,19 @@ class Assembler : public AbstractAssembler { void cvttsd2sil(Register dst, XMMRegister src); void cvttsd2siq(Register dst, Address src); void cvttsd2siq(Register dst, XMMRegister src); + void evcvttsd2sisl(Register dst, XMMRegister src); + void evcvttsd2sisl(Register dst, Address src); + void evcvttsd2sisq(Register dst, XMMRegister src); + void evcvttsd2sisq(Register dst, Address src); // Convert with Truncation Scalar Single-Precision Floating-Point Value to Doubleword Integer void cvttss2sil(Register dst, XMMRegister src); void cvttss2siq(Register dst, XMMRegister src); void cvtss2sil(Register dst, XMMRegister src); + void evcvttss2sisl(Register dst, XMMRegister src); + void evcvttss2sisl(Register dst, Address src); + void evcvttss2sisq(Register dst, XMMRegister src); + void evcvttss2sisq(Register dst, Address src); // Convert vector double to int void cvttpd2dq(XMMRegister dst, XMMRegister src); @@ -1332,7 +1340,11 @@ class Assembler : public AbstractAssembler { // Convert vector float to int/long void vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len); void vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttps2dqs(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttps2dqs(XMMRegister dst, Address src, int vector_len); void evcvttps2qq(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttps2qqs(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttps2qqs(XMMRegister dst, Address src, int vector_len); // Convert vector long to vector FP void evcvtqq2ps(XMMRegister dst, XMMRegister src, int vector_len); @@ -1341,9 +1353,13 @@ class Assembler : public AbstractAssembler { // Convert vector double to long void evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len); void evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttpd2qqs(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttpd2qqs(XMMRegister dst, Address src, int vector_len); // Convert vector double to int void vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttpd2dqs(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttpd2dqs(XMMRegister dst, Address src, int vector_len); // Evex casts with truncation void evpmovwb(XMMRegister dst, XMMRegister src, int vector_len); diff --git a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp index 2fd067a7749..95ce48f34db 100644 --- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp @@ -207,10 +207,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - if (_compute_lock) { - // lock_reg was destroyed by fast unlocking attempt => recompute it - ce->monitor_address(_monitor_ix, _lock_reg); - } + + // lock_reg was destroyed by fast unlocking attempt => recompute it + ce->monitor_address(_monitor_ix, _lock_reg); + ce->store_parameter(_lock_reg->as_register(), 0); // note: non-blocking leaf routine => no call info needed StubId exit_id; diff --git a/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp b/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp index bdbab432180..68c9814fd20 100644 --- a/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp +++ b/src/hotspot/cpu/x86/c1_FrameMap_x86.cpp @@ -326,13 +326,6 @@ LIR_Opr FrameMap::stack_pointer() { return FrameMap::rsp_opr; } -// JSR 292 -// On x86, there is no need to save the SP, because neither -// method handle intrinsics, nor compiled lambda forms modify it. -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - return LIR_OprFact::illegalOpr; -} - bool FrameMap::validate_frame() { return true; } diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index 98759295bb1..edeb0baea0e 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -412,7 +412,7 @@ int LIR_Assembler::emit_unwind_handler() { MonitorExitStub* stub = nullptr; if (method()->is_synchronized()) { monitor_address(0, FrameMap::rax_opr); - stub = new MonitorExitStub(FrameMap::rax_opr, true, 0); + stub = new MonitorExitStub(FrameMap::rax_opr, 0); __ unlock_object(rdi, rsi, rax, *stub->entry()); __ bind(*stub->continuation()); } @@ -2730,7 +2730,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); if (op->code() == lir_lock) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); Register tmp = op->scratch_opr()->as_register(); // add debug info for NullPointerException only if one is possible int null_check_offset = __ lock_object(hdr, obj, lock, tmp, *op->stub()->entry()); @@ -2739,7 +2738,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { } // done } else if (op->code() == lir_unlock) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); __ unlock_object(hdr, obj, lock, *op->stub()->entry()); } else { Unimplemented(); diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index 36efeafa940..c3d45f9d15d 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -41,32 +41,32 @@ #include "utilities/checkedCast.hpp" #include "utilities/globalDefinitions.hpp" -int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register tmp, Label& slow_case) { +int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Register tmp, Label& slow_case) { assert(hdr == rax, "hdr must be rax, for the cmpxchg instruction"); - assert_different_registers(hdr, obj, disp_hdr, tmp); + assert_different_registers(hdr, obj, basic_lock, tmp); int null_check_offset = -1; verify_oop(obj); // save object being locked into the BasicObjectLock - movptr(Address(disp_hdr, BasicObjectLock::obj_offset()), obj); + movptr(Address(basic_lock, BasicObjectLock::obj_offset()), obj); null_check_offset = offset(); - lightweight_lock(disp_hdr, obj, hdr, tmp, slow_case); + lightweight_lock(basic_lock, obj, hdr, tmp, slow_case); return null_check_offset; } -void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { - assert(disp_hdr == rax, "disp_hdr must be rax, for the cmpxchg instruction"); - assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different"); +void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case) { + assert(basic_lock == rax, "basic_lock must be rax, for the cmpxchg instruction"); + assert(hdr != obj && hdr != basic_lock && obj != basic_lock, "registers must be different"); // load object - movptr(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + movptr(obj, Address(basic_lock, BasicObjectLock::obj_offset())); verify_oop(obj); - lightweight_unlock(obj, disp_hdr, hdr, slow_case); + lightweight_unlock(obj, rax, hdr, slow_case); } diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp index 6344a7b6ef1..f33e47aadb3 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,17 +46,17 @@ void initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register t1); // locking - // hdr : must be rax, contents destroyed - // obj : must point to the object to lock, contents preserved - // disp_hdr: must point to the displaced header location, contents preserved + // hdr : must be rax, contents destroyed + // obj : must point to the object to lock, contents preserved + // basic_lock: must point to the basic lock, contents preserved // returns code offset at which to add null check debug information - int lock_object (Register swap, Register obj, Register disp_hdr, Register tmp, Label& slow_case); + int lock_object (Register swap, Register obj, Register basic_lock, Register tmp, Label& slow_case); // unlocking - // hdr : contents destroyed - // obj : must point to the object to lock, contents preserved - // disp_hdr: must be eax & must point to the displaced header location, contents destroyed - void unlock_object(Register swap, Register obj, Register lock, Label& slow_case); + // hdr : contents destroyed + // obj : must point to the object to lock, contents preserved + // basic_lock: must be eax & must point to the basic lock, contents destroyed + void unlock_object(Register swap, Register obj, Register basic_lock, Label& slow_case); void initialize_object( Register obj, // result: pointer to object after successful allocation diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 8c3f33e0aca..8386e57c389 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -5053,12 +5053,12 @@ void C2_MacroAssembler::vector_cast_int_to_subword(BasicType to_elem_bt, XMMRegi } vpackuswb(dst, dst, zero, vec_enc); break; - default: assert(false, "%s", type2name(to_elem_bt)); + default: assert(false, "Unexpected basic type for target of vector cast int to subword: %s", type2name(to_elem_bt)); } } /* - * Algorithm for vector D2L and F2I conversions:- + * Algorithm for vector D2L and F2I conversions (AVX 10.2 unsupported):- * a) Perform vector D2L/F2I cast. * b) Choose fast path if none of the result vector lane contains 0x80000000 value. * It signifies that source value could be any of the special floating point @@ -5096,7 +5096,7 @@ void C2_MacroAssembler::vector_castF2X_evex(BasicType to_elem_bt, XMMRegister ds case T_BYTE: evpmovdb(dst, dst, vec_enc); break; - default: assert(false, "%s", type2name(to_elem_bt)); + default: assert(false, "Unexpected basic type for target of vector castF2X EVEX: %s", type2name(to_elem_bt)); } } @@ -5143,7 +5143,7 @@ void C2_MacroAssembler::vector_castD2X_evex(BasicType to_elem_bt, XMMRegister ds evpmovsqd(dst, dst, vec_enc); evpmovdb(dst, dst, vec_enc); break; - default: assert(false, "%s", type2name(to_elem_bt)); + default: assert(false, "Unexpected basic type for target of vector castD2X AVX512DQ EVEX: %s", type2name(to_elem_bt)); } } else { assert(type2aelembytes(to_elem_bt) <= 4, ""); @@ -5158,11 +5158,91 @@ void C2_MacroAssembler::vector_castD2X_evex(BasicType to_elem_bt, XMMRegister ds case T_BYTE: evpmovdb(dst, dst, vec_enc); break; - default: assert(false, "%s", type2name(to_elem_bt)); + default: assert(false, "Unexpected basic type for target of vector castD2X EVEX: %s", type2name(to_elem_bt)); } } } +void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) { + switch(to_elem_bt) { + case T_LONG: + evcvttps2qqs(dst, src, vec_enc); + break; + case T_INT: + evcvttps2dqs(dst, src, vec_enc); + break; + case T_SHORT: + evcvttps2dqs(dst, src, vec_enc); + evpmovdw(dst, dst, vec_enc); + break; + case T_BYTE: + evcvttps2dqs(dst, src, vec_enc); + evpmovdb(dst, dst, vec_enc); + break; + default: assert(false, "Unexpected basic type for target of vector castF2X AVX10 (reg src): %s", type2name(to_elem_bt)); + } +} + +void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) { + switch(to_elem_bt) { + case T_LONG: + evcvttps2qqs(dst, src, vec_enc); + break; + case T_INT: + evcvttps2dqs(dst, src, vec_enc); + break; + case T_SHORT: + evcvttps2dqs(dst, src, vec_enc); + evpmovdw(dst, dst, vec_enc); + break; + case T_BYTE: + evcvttps2dqs(dst, src, vec_enc); + evpmovdb(dst, dst, vec_enc); + break; + default: assert(false, "Unexpected basic type for target of vector castF2X AVX10 (mem src): %s", type2name(to_elem_bt)); + } +} + +void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) { + switch(to_elem_bt) { + case T_LONG: + evcvttpd2qqs(dst, src, vec_enc); + break; + case T_INT: + evcvttpd2dqs(dst, src, vec_enc); + break; + case T_SHORT: + evcvttpd2dqs(dst, src, vec_enc); + evpmovdw(dst, dst, vec_enc); + break; + case T_BYTE: + evcvttpd2dqs(dst, src, vec_enc); + evpmovdb(dst, dst, vec_enc); + break; + default: assert(false, "Unexpected basic type for target of vector castD2X AVX10 (reg src): %s", type2name(to_elem_bt)); + } +} + +void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) { + switch(to_elem_bt) { + case T_LONG: + evcvttpd2qqs(dst, src, vec_enc); + break; + case T_INT: + evcvttpd2dqs(dst, src, vec_enc); + break; + case T_SHORT: + evcvttpd2dqs(dst, src, vec_enc); + evpmovdw(dst, dst, vec_enc); + break; + case T_BYTE: + evcvttpd2dqs(dst, src, vec_enc); + evpmovdb(dst, dst, vec_enc); + break; + default: assert(false, "Unexpected basic type for target of vector castD2X AVX10 (mem src): %s", type2name(to_elem_bt)); + } +} + void C2_MacroAssembler::vector_round_double_evex(XMMRegister dst, XMMRegister src, AddressLiteral double_sign_flip, AddressLiteral new_mxcsr, int vec_enc, Register tmp, XMMRegister xtmp1, XMMRegister xtmp2, KRegister ktmp1, KRegister ktmp2) { diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index 950fcb75290..aaee25f440a 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -347,6 +347,13 @@ XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, XMMRegister xtmp5, AddressLiteral float_sign_flip, Register rscratch, int vec_enc); + void vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc); + + void vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc); + + void vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc); + + void vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc); void vector_cast_double_to_int_special_cases_avx(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, XMMRegister xtmp5, Register rscratch, diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index 46ffda93699..5f52f2fabf2 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -219,8 +219,7 @@ bool frame::safe_for_sender(JavaThread *thread) { nmethod* nm = sender_blob->as_nmethod_or_null(); if (nm != nullptr) { - if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || - nm->method()->is_method_handle_intrinsic()) { + if (nm->is_deopt_entry(sender_pc) || nm->method()->is_method_handle_intrinsic()) { return false; } } @@ -443,47 +442,6 @@ JavaThread** frame::saved_thread_address(const frame& f) { return thread_addr; } -//------------------------------------------------------------------------------ -// frame::verify_deopt_original_pc -// -// Verifies the calculated original PC of a deoptimization PC for the -// given unextended SP. -#ifdef ASSERT -void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) { - frame fr; - - // This is ugly but it's better than to change {get,set}_original_pc - // to take an SP value as argument. And it's only a debugging - // method anyway. - fr._unextended_sp = unextended_sp; - - address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains_inclusive(original_pc), - "original PC must be in the main code section of the compiled method (or must be immediately following it) original_pc: " INTPTR_FORMAT " unextended_sp: " INTPTR_FORMAT " name: %s", p2i(original_pc), p2i(unextended_sp), nm->name()); -} -#endif - -//------------------------------------------------------------------------------ -// frame::adjust_unextended_sp -#ifdef ASSERT -void frame::adjust_unextended_sp() { - // On x86, sites calling method handle intrinsics and lambda forms are treated - // as any other call site. Therefore, no special action is needed when we are - // returning to any of these call sites. - - if (_cb != nullptr) { - nmethod* sender_nm = _cb->as_nmethod_or_null(); - if (sender_nm != nullptr) { - // If the sender PC is a deoptimization point, get the original PC. - if (sender_nm->is_deopt_entry(_pc) || - sender_nm->is_deopt_mh_entry(_pc)) { - verify_deopt_original_pc(sender_nm, _unextended_sp); - } - } - } -} -#endif - //------------------------------------------------------------------------------ // frame::sender_for_interpreter_frame frame frame::sender_for_interpreter_frame(RegisterMap* map) const { diff --git a/src/hotspot/cpu/x86/frame_x86.hpp b/src/hotspot/cpu/x86/frame_x86.hpp index f3034ee9263..19f37c42cf4 100644 --- a/src/hotspot/cpu/x86/frame_x86.hpp +++ b/src/hotspot/cpu/x86/frame_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,17 +138,10 @@ int _offset_unextended_sp; // for use in stack-chunk frames }; - void adjust_unextended_sp() NOT_DEBUG_RETURN; - intptr_t* ptr_at_addr(int offset) const { return (intptr_t*) addr_at(offset); } -#ifdef ASSERT - // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp); -#endif - public: // Constructors diff --git a/src/hotspot/cpu/x86/frame_x86.inline.hpp b/src/hotspot/cpu/x86/frame_x86.inline.hpp index afc4ab8767b..ca51fe66786 100644 --- a/src/hotspot/cpu/x86/frame_x86.inline.hpp +++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp @@ -111,8 +111,6 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) { } inline void frame::setup(address pc) { - adjust_unextended_sp(); - address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; @@ -209,7 +207,6 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) { // assert(_pc != nullptr, "no pc?"); _cb = CodeCache::find_blob(_pc); - adjust_unextended_sp(); address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { diff --git a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp index 3c1474ae861..abbeb66a1ca 100644 --- a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp +++ b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define SUPPORTS_NATIVE_CX8 -#define SUPPORT_MONITOR_COUNT - #define CPU_MULTI_COPY_ATOMIC // The expected size in bytes of a cache line. diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index c1319b2ef7f..4f19b30b832 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -2431,14 +2431,6 @@ void MacroAssembler::pop_cont_fastpath() { bind(L_done); } -void MacroAssembler::inc_held_monitor_count() { - incrementq(Address(r15_thread, JavaThread::held_monitor_count_offset())); -} - -void MacroAssembler::dec_held_monitor_count() { - decrementq(Address(r15_thread, JavaThread::held_monitor_count_offset())); -} - #ifdef ASSERT void MacroAssembler::stop_if_in_cont(Register cont, const char* name) { Label no_cont; @@ -5847,7 +5839,7 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned, orl(value, rtmp); } - cmpptr(count, 2< 0 and this vthread is terminating then - // it failed to release a JNI monitor. So we issue the same log message - // that JavaThread::exit does. - __ cmpptr(Address(r15_thread, JavaThread::jni_monitor_count_offset()), 0); - __ jcc(Assembler::equal, L_skip_vthread_code); - - // rax may hold an exception oop, save it before the call - __ push(rax); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::log_jni_monitor_still_held)); - __ pop(rax); - - // For vthreads we have to explicitly zero the JNI monitor count of the carrier - // on termination. The held count is implicitly zeroed below when we restore from - // the parent held count (which has to be zero). - __ movq(Address(r15_thread, JavaThread::jni_monitor_count_offset()), 0); - - __ bind(L_skip_vthread_code); - } -#ifdef ASSERT - else { - // Check if this is a virtual thread continuation - Label L_skip_vthread_code; - __ cmpl(Address(rsp, ContinuationEntry::flags_offset()), 0); - __ jcc(Assembler::equal, L_skip_vthread_code); - - // See comment just above. If not checking JNI calls the JNI count is only - // needed for assertion checking. - __ movq(Address(r15_thread, JavaThread::jni_monitor_count_offset()), 0); - - __ bind(L_skip_vthread_code); - } -#endif - - __ movq(rbx, Address(rsp, ContinuationEntry::parent_held_monitor_count_offset())); - __ movq(Address(r15_thread, JavaThread::held_monitor_count_offset()), rbx); - __ movptr(rbx, Address(rsp, ContinuationEntry::parent_offset())); __ movptr(Address(r15_thread, JavaThread::cont_entry_offset()), rbx); __ addptr(rsp, checked_cast(ContinuationEntry::size())); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp index c35f1b9f65e..73330dedc0f 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp @@ -49,142 +49,142 @@ /* Represents 0x7FFFFFFFFFFFFFFF double precision in lower 64 bits*/ ATTRIBUTE_ALIGNED(16) static const juint _ABS_MASK[] = { - 4294967295, 2147483647, 0, 0 + 0xFFFFFFFFUL, 0x7FFFFFFFUL, 0x00000000UL, 0x00000000UL }; ATTRIBUTE_ALIGNED(4) static const juint _SIG_MASK[] = { - 0, 1032192 + 0x00000000UL, 0x000FC000UL }; ATTRIBUTE_ALIGNED(4) static const juint _EXP_MASK[] = { - 0, 3220176896 + 0x00000000UL, 0xBFF00000UL }; ATTRIBUTE_ALIGNED(4) static const juint _EXP_MSK2[] = { - 0, 3220193280 + 0x00000000UL, 0xBFF04000UL }; ATTRIBUTE_ALIGNED(4) static const juint _EXP_MSK3[] = { - 4294967295, 1048575 + 0xFFFFFFFFUL, 0x000FFFFFUL }; ATTRIBUTE_ALIGNED(4) static const juint _SCALE63[] = { - 0, 1138753536 + 0x00000000UL, 0x43E00000UL }; ATTRIBUTE_ALIGNED(4) static const juint _ZERON[] = { - 0, 2147483648 + 0x00000000UL, 0x80000000UL }; ATTRIBUTE_ALIGNED(4) static const juint _INF[] = { - 0, 2146435072 + 0x00000000UL, 0x7FF00000UL }; ATTRIBUTE_ALIGNED(4) static const juint _NEG_INF[] = { - 0, 4293918720 + 0x00000000UL, 0xFFF00000UL }; ATTRIBUTE_ALIGNED(16) static const juint _coeff_table[] = { - 1553778919, 3213899486, 3534952507, 3215266280, 1646371399, - 3214412045, 477218588, 3216798151, 3582521621, 1066628362, - 1007461464, 1068473053, 889629714, 1067378449, 1431655765, - 1070945621 + 0x5C9CC8E7UL, 0xBF9036DEUL, 0xD2B3183BUL, 0xBFA511E8UL, 0x6221A247UL, + 0xBF98090DUL, 0x1C71C71CUL, 0xBFBC71C7UL, 0xD588F115UL, 0x3F93750AUL, + 0x3C0CA458UL, 0x3FAF9ADDUL, 0x3506AC12UL, 0x3F9EE711UL, 0x55555555UL, + 0x3FD55555UL }; ATTRIBUTE_ALIGNED(4) static const juint _rcp_table[] = { - 528611360, 3220144632, 2884679527, 3220082993, 1991868891, 3220024928, - 2298714891, 3219970134, 58835168, 3219918343, 3035110223, 3219869313, - 1617585086, 3219822831, 2500867033, 3219778702, 4241943008, 3219736752, - 258732970, 3219696825, 404232216, 3219658776, 2172167368, 3219622476, - 1544257904, 3219587808, 377579543, 3219554664, 1616385542, 3219522945, - 813783277, 3219492562, 3940743189, 3219463431, 2689777499, 3219435478, - 1700977147, 3219408632, 3169102082, 3219382828, 327235604, 3219358008, - 1244336319, 3219334115, 1300311200, 3219311099, 3095471925, 3219288912, - 2166487928, 3219267511, 2913108253, 3219246854, 293672978, 3219226904, - 288737297, 3219207624, 1810275472, 3219188981, 174592167, 3219170945, - 3539053052, 3219153485, 2164392968, 3219136576 + 0x1F81F820UL, 0xBFEF81F8UL, 0xABF0B767UL, 0xBFEE9131UL, 0x76B981DBUL, 0xBFEDAE60UL, + 0x89039B0BUL, 0xBFECD856UL, 0x0381C0E0UL, 0xBFEC0E07UL, 0xB4E81B4FUL, 0xBFEB4E81UL, + 0x606A63BEUL, 0xBFEA98EFUL, 0x951033D9UL, 0xBFE9EC8EUL, 0xFCD6E9E0UL, 0xBFE948B0UL, + 0x0F6BF3AAUL, 0xBFE8ACB9UL, 0x18181818UL, 0xBFE81818UL, 0x8178A4C8UL, 0xBFE78A4CUL, + 0x5C0B8170UL, 0xBFE702E0UL, 0x16816817UL, 0xBFE68168UL, 0x60581606UL, 0xBFE60581UL, + 0x308158EDUL, 0xBFE58ED2UL, 0xEAE2F815UL, 0xBFE51D07UL, 0xA052BF5BUL, 0xBFE4AFD6UL, + 0x6562D9FBUL, 0xBFE446F8UL, 0xBCE4A902UL, 0xBFE3E22CUL, 0x13813814UL, 0xBFE38138UL, + 0x4A2B10BFUL, 0xBFE323E3UL, 0x4D812CA0UL, 0xBFE2C9FBUL, 0xB8812735UL, 0xBFE27350UL, + 0x8121FB78UL, 0xBFE21FB7UL, 0xADA2811DUL, 0xBFE1CF06UL, 0x11811812UL, 0xBFE18118UL, + 0x1135C811UL, 0xBFE135C8UL, 0x6BE69C90UL, 0xBFE0ECF5UL, 0x0A6810A7UL, 0xBFE0A681UL, + 0xD2F1A9FCUL, 0xBFE0624DUL, 0x81020408UL, 0xBFE02040UL }; ATTRIBUTE_ALIGNED(4) static const juint _cbrt_table[] = { - 572345495, 1072698681, 1998204467, 1072709382, 3861501553, 1072719872, - 2268192434, 1072730162, 2981979308, 1072740260, 270859143, 1072750176, - 2958651392, 1072759916, 313113243, 1072769490, 919449400, 1072778903, - 2809328903, 1072788162, 2222981587, 1072797274, 2352530781, 1072806244, - 594152517, 1072815078, 1555767199, 1072823780, 4282421314, 1072832355, - 2355578597, 1072840809, 1162590619, 1072849145, 797864051, 1072857367, - 431273680, 1072865479, 2669831148, 1072873484, 733477752, 1072881387, - 4280220604, 1072889189, 801961634, 1072896896, 2915370760, 1072904508, - 1159613482, 1072912030, 2689944798, 1072919463, 1248687822, 1072926811, - 2967951030, 1072934075, 630170432, 1072941259, 3760898254, 1072948363, - 0, 1072955392, 2370273294, 1072962345, 1261754802, 1072972640, - 546334065, 1072986123, 1054893830, 1072999340, 1571187597, 1073012304, - 1107975175, 1073025027, 3606909377, 1073037519, 1113616747, 1073049792, - 4154744632, 1073061853, 3358931423, 1073073713, 4060702372, 1073085379, - 747576176, 1073096860, 3023138255, 1073108161, 1419988548, 1073119291, - 1914185305, 1073130255, 294389948, 1073141060, 3761802570, 1073151710, - 978281566, 1073162213, 823148820, 1073172572, 2420954441, 1073182792, - 3815449908, 1073192878, 2046058587, 1073202835, 1807524753, 1073212666, - 2628681401, 1073222375, 3225667357, 1073231966, 1555307421, 1073241443, - 3454043099, 1073250808, 1208137896, 1073260066, 3659916772, 1073269218, - 1886261264, 1073278269, 3593647839, 1073287220, 3086012205, 1073296075, - 2769796922, 1073304836, 888716057, 1073317807, 2201465623, 1073334794, - 164369365, 1073351447, 3462666733, 1073367780, 2773905457, 1073383810, - 1342879088, 1073399550, 2543933975, 1073415012, 1684477781, 1073430209, - 3532178543, 1073445151, 1147747300, 1073459850, 1928031793, 1073474314, - 2079717015, 1073488553, 4016765315, 1073502575, 3670431139, 1073516389, - 3549227225, 1073530002, 11637607, 1073543422, 588220169, 1073556654, - 2635407503, 1073569705, 2042029317, 1073582582, 1925128962, 1073595290, - 4136375664, 1073607834, 759964600, 1073620221, 4257606771, 1073632453, - 297278907, 1073644538, 3655053093, 1073656477, 2442253172, 1073668277, - 1111876799, 1073679941, 3330973139, 1073691472, 3438879452, 1073702875, - 3671565478, 1073714153, 1317849547, 1073725310, 1642364115, 1073736348 + 0x221D4C97UL, 0x3FF01539UL, 0x771A2E33UL, 0x3FF03F06UL, 0xE629D671UL, 0x3FF06800UL, + 0x8731DEB2UL, 0x3FF09032UL, 0xB1BD64ACUL, 0x3FF0B7A4UL, 0x1024FB87UL, 0x3FF0DE60UL, + 0xB0597000UL, 0x3FF1046CUL, 0x12A9BA9BUL, 0x3FF129D2UL, 0x36CDAF38UL, 0x3FF14E97UL, + 0xA772F507UL, 0x3FF172C2UL, 0x848001D3UL, 0x3FF1965AUL, 0x8C38C55DUL, 0x3FF1B964UL, + 0x236A0C45UL, 0x3FF1DBE6UL, 0x5CBB1F9FUL, 0x3FF1FDE4UL, 0xFF409042UL, 0x3FF21F63UL, + 0x8C6746E5UL, 0x3FF24069UL, 0x454BB99BUL, 0x3FF260F9UL, 0x2F8E7073UL, 0x3FF28117UL, + 0x19B4B6D0UL, 0x3FF2A0C7UL, 0x9F2263ECUL, 0x3FF2C00CUL, 0x2BB7FB78UL, 0x3FF2DEEBUL, + 0xFF1EFBBCUL, 0x3FF2FD65UL, 0x2FCCF6A2UL, 0x3FF31B80UL, 0xADC50708UL, 0x3FF3393CUL, + 0x451E4C2AUL, 0x3FF3569EUL, 0xA0554CDEUL, 0x3FF373A7UL, 0x4A6D76CEUL, 0x3FF3905BUL, + 0xB0E756B6UL, 0x3FF3ACBBUL, 0x258FA340UL, 0x3FF3C8CBUL, 0xE02AC0CEUL, 0x3FF3E48BUL, + 0x00000000UL, 0x3FF40000UL, 0x8D47800EUL, 0x3FF41B29UL, 0x4B34D9B2UL, 0x3FF44360UL, + 0x20906571UL, 0x3FF4780BUL, 0x3EE06706UL, 0x3FF4ABACUL, 0x5DA66B8DUL, 0x3FF4DE50UL, + 0x420A5C07UL, 0x3FF51003UL, 0xD6FD11C1UL, 0x3FF540CFUL, 0x4260716BUL, 0x3FF570C0UL, + 0xF7A45F38UL, 0x3FF59FDDUL, 0xC83539DFUL, 0x3FF5CE31UL, 0xF20966A4UL, 0x3FF5FBC3UL, + 0x2C8F1B70UL, 0x3FF6289CUL, 0xB4316DCFUL, 0x3FF654C1UL, 0x54A34E44UL, 0x3FF6803BUL, + 0x72182659UL, 0x3FF6AB0FUL, 0x118C08BCUL, 0x3FF6D544UL, 0xE0388D4AUL, 0x3FF6FEDEUL, + 0x3A4F645EUL, 0x3FF727E5UL, 0x31104114UL, 0x3FF7505CUL, 0x904CD549UL, 0x3FF77848UL, + 0xE36B2534UL, 0x3FF79FAEUL, 0x79F4605BUL, 0x3FF7C693UL, 0x6BBCA391UL, 0x3FF7ECFAUL, + 0x9CAE7EB9UL, 0x3FF812E7UL, 0xC043C71DUL, 0x3FF8385EUL, 0x5CB41B9DUL, 0x3FF85D63UL, + 0xCDE083DBUL, 0x3FF881F8UL, 0x4802B8A8UL, 0x3FF8A622UL, 0xDA25E5E4UL, 0x3FF8C9E2UL, + 0x706E1010UL, 0x3FF8ED3DUL, 0xD632B6DFUL, 0x3FF91034UL, 0xB7F0CF2DUL, 0x3FF932CBUL, + 0xA517BF3AUL, 0x3FF95504UL, 0x34F8BB19UL, 0x3FF987AFUL, 0x8337B317UL, 0x3FF9CA0AUL, + 0x09CC13D5UL, 0x3FFA0B17UL, 0xCE6419EDUL, 0x3FFA4AE4UL, 0xA5567031UL, 0x3FFA8982UL, + 0x500AB570UL, 0x3FFAC6FEUL, 0x97A15A17UL, 0x3FFB0364UL, 0x64671755UL, 0x3FFB3EC1UL, + 0xD288C46FUL, 0x3FFB791FUL, 0x44693BE4UL, 0x3FFBB28AUL, 0x72EB6E31UL, 0x3FFBEB0AUL, + 0x7BF5F697UL, 0x3FFC22A9UL, 0xEF6AF983UL, 0x3FFC596FUL, 0xDAC655A3UL, 0x3FFC8F65UL, + 0xD38CE8D9UL, 0x3FFCC492UL, 0x00B19367UL, 0x3FFCF8FEUL, 0x230F8709UL, 0x3FFD2CAEUL, + 0x9D15208FUL, 0x3FFD5FA9UL, 0x79B6E505UL, 0x3FFD91F6UL, 0x72BF2302UL, 0x3FFDC39AUL, + 0xF68C1570UL, 0x3FFDF49AUL, 0x2D4C23B8UL, 0x3FFE24FDUL, 0xFDC5EC73UL, 0x3FFE54C5UL, + 0x11B81DBBUL, 0x3FFE83FAUL, 0xD9DBAF25UL, 0x3FFEB29DUL, 0x9191D374UL, 0x3FFEE0B5UL, + 0x4245E4BFUL, 0x3FFF0E45UL, 0xC68A9DD3UL, 0x3FFF3B50UL, 0xCCF922DCUL, 0x3FFF67DBUL, + 0xDAD7A4A6UL, 0x3FFF93E9UL, 0x4E8CC9CBUL, 0x3FFFBF7EUL, 0x61E47CD3UL, 0x3FFFEA9CUL }; ATTRIBUTE_ALIGNED(4) static const juint _D_table[] = { - 4050900474, 1014427190, 1157977860, 1016444461, 1374568199, 1017271387, - 2809163288, 1016882676, 3742377377, 1013168191, 3101606597, 1017541672, - 65224358, 1017217597, 2691591250, 1017266643, 4020758549, 1017689313, - 1316310992, 1018030788, 1031537856, 1014090882, 3261395239, 1016413641, - 886424999, 1016313335, 3114776834, 1014195875, 1681120620, 1017825416, - 1329600273, 1016625740, 465474623, 1017097119, 4251633980, 1017169077, - 1986990133, 1017710645, 752958613, 1017159641, 2216216792, 1018020163, - 4282860129, 1015924861, 1557627859, 1016039538, 3889219754, 1018086237, - 3684996408, 1017353275, 723532103, 1017717141, 2951149676, 1012528470, - 831890937, 1017830553, 1031212645, 1017387331, 2741737450, 1017604974, - 2863311531, 1003776682, 4276736099, 1013153088, 4111778382, 1015673686, - 1728065769, 1016413986, 2708718031, 1018078833, 1069335005, 1015291224, - 700037144, 1016482032, 2904566452, 1017226861, 4074156649, 1017622651, - 25019565, 1015245366, 3601952608, 1015771755, 3267129373, 1017904664, - 503203103, 1014921629, 2122011730, 1018027866, 3927295461, 1014189456, - 2790625147, 1016024251, 1330460186, 1016940346, 4033568463, 1015538390, - 3695818227, 1017509621, 257573361, 1017208868, 3227697852, 1017337964, - 234118548, 1017169577, 4009025803, 1017278524, 1948343394, 1017749310, - 678398162, 1018144239, 3083864863, 1016669086, 2415453452, 1017890370, - 175467344, 1017330033, 3197359580, 1010339928, 2071276951, 1015941358, - 268372543, 1016737773, 938132959, 1017389108, 1816750559, 1017337448, - 4119203749, 1017152174, 2578653878, 1013108497, 2470331096, 1014678606, - 123855735, 1016553320, 1265650889, 1014782687, 3414398172, 1017182638, - 1040773369, 1016158401, 3483628886, 1016886550, 4140499405, 1016191425, - 3893477850, 1016964495, 3935319771, 1009634717, 2978982660, 1015027112, - 2452709923, 1017990229, 3190365712, 1015835149, 4237588139, 1015832925, - 2610678389, 1017962711, 2127316774, 1017405770, 824267502, 1017959463, - 2165924042, 1017912225, 2774007076, 1013257418, 4123916326, 1017582284, - 1976417958, 1016959909, 4092806412, 1017711279, 119251817, 1015363631, - 3475418768, 1017675415, 1972580503, 1015470684, 815541017, 1017517969, - 2429917451, 1017397776, 4062888482, 1016749897, 68284153, 1017925678, - 2207779246, 1016320298, 1183466520, 1017408657, 143326427, 1017060403 + 0xF173D5FAUL, 0x3C76EE36UL, 0x45055704UL, 0x3C95B62DUL, 0x51EE3F07UL, 0x3CA2545BUL, + 0xA7706E18UL, 0x3C9C65F4UL, 0xDF1025A1UL, 0x3C63B83FUL, 0xB8DEC2C5UL, 0x3CA67428UL, + 0x03E33EA6UL, 0x3CA1823DUL, 0xA06E6C52UL, 0x3CA241D3UL, 0xEFA7E815UL, 0x3CA8B4E1UL, + 0x4E754FD0UL, 0x3CADEAC4UL, 0x3D7C04C0UL, 0x3C71CC82UL, 0xC264F127UL, 0x3C953DC9UL, + 0x34D5C5A7UL, 0x3C93B5F7UL, 0xB9A7B902UL, 0x3C7366A3UL, 0x6433DD6CUL, 0x3CAAC888UL, + 0x4F401711UL, 0x3C987A4CUL, 0x1BBE943FUL, 0x3C9FAB9FUL, 0xFD6AC93CUL, 0x3CA0C4B5UL, + 0x766F1035UL, 0x3CA90835UL, 0x2CE13C95UL, 0x3CA09FD9UL, 0x8418C8D8UL, 0x3CADC143UL, + 0xFF474261UL, 0x3C8DC87DUL, 0x5CD783D3UL, 0x3C8F8872UL, 0xE7D0C8AAUL, 0x3CAEC35DUL, + 0xDBA49538UL, 0x3CA3943BUL, 0x2B203947UL, 0x3CA92195UL, 0xAFE6F86CUL, 0x3C59F556UL, + 0x3195A5F9UL, 0x3CAADC99UL, 0x3D770E65UL, 0x3CA41943UL, 0xA36B97EAUL, 0x3CA76B6EUL, + 0xAAAAAAABUL, 0x3BD46AAAUL, 0xFEE9D063UL, 0x3C637D40UL, 0xF514C24EUL, 0x3C89F356UL, + 0x670030E9UL, 0x3C953F22UL, 0xA173C1CFUL, 0x3CAEA671UL, 0x3FBCC1DDUL, 0x3C841D58UL, + 0x29B9B818UL, 0x3C9648F0UL, 0xAD202AB4UL, 0x3CA1A66DUL, 0xF2D6B269UL, 0x3CA7B07BUL, + 0x017DC4ADUL, 0x3C836A36UL, 0xD6B16F60UL, 0x3C8B726BUL, 0xC2BC701DUL, 0x3CABFE18UL, + 0x1DFE451FUL, 0x3C7E799DUL, 0x7E7B5452UL, 0x3CADDF5AUL, 0xEA15C5E5UL, 0x3C734D90UL, + 0xA6558F7BUL, 0x3C8F4CBBUL, 0x4F4D361AUL, 0x3C9D473AUL, 0xF06B5ECFUL, 0x3C87E2D6UL, + 0xDC49B5F3UL, 0x3CA5F6F5UL, 0x0F5A41F1UL, 0x3CA16024UL, 0xC062C2BCUL, 0x3CA3586CUL, + 0x0DF45D94UL, 0x3CA0C6A9UL, 0xEEF4E10BUL, 0x3CA2703CUL, 0x74215C62UL, 0x3CA99F3EUL, + 0x286F88D2UL, 0x3CAFA5EFUL, 0xB7D00B1FUL, 0x3C99239EUL, 0x8FF8E50CUL, 0x3CABC642UL, + 0x0A756B50UL, 0x3CA33971UL, 0xBE93D5DCUL, 0x3C389058UL, 0x7B752D97UL, 0x3C8E08EEUL, + 0x0FFF0A3FUL, 0x3C9A2FEDUL, 0x37EAC5DFUL, 0x3CA42034UL, 0x6C4969DFUL, 0x3CA35668UL, + 0xF5860FA5UL, 0x3CA082AEUL, 0x99B322B6UL, 0x3C62CF11UL, 0x933E42D8UL, 0x3C7AC44EUL, + 0x0761E377UL, 0x3C975F68UL, 0x4B704CC9UL, 0x3C7C5ADFUL, 0xCB8394DCUL, 0x3CA0F9AEUL, + 0x3E08F0F9UL, 0x3C9158C1UL, 0xCFA3F556UL, 0x3C9C7516UL, 0xF6CB01CDUL, 0x3C91D9C1UL, + 0xE811C1DAUL, 0x3C9DA58FUL, 0xEA9036DBUL, 0x3C2DCD9DUL, 0xB18FAB04UL, 0x3C8015A8UL, + 0x92316223UL, 0x3CAD4C55UL, 0xBE291E10UL, 0x3C8C6A0DUL, 0xFC9476ABUL, 0x3C8C615DUL, + 0x9B9BCA75UL, 0x3CACE0D7UL, 0x7ECC4726UL, 0x3CA4614AUL, 0x312152EEUL, 0x3CACD427UL, + 0x811960CAUL, 0x3CAC1BA1UL, 0xA557FD24UL, 0x3C6514CAUL, 0xF5CDF826UL, 0x3CA712CCUL, + 0x75CDBEA6UL, 0x3C9D93A5UL, 0xF3F3450CUL, 0x3CA90AAFUL, 0x071BA369UL, 0x3C85382FUL, + 0xCF26AE90UL, 0x3CA87E97UL, 0x75933097UL, 0x3C86DA5CUL, 0x309C2B19UL, 0x3CA61791UL, + 0x90D5990BUL, 0x3CA44210UL, 0xF22AC222UL, 0x3C9A5F49UL, 0x0411EEF9UL, 0x3CAC502EUL, + 0x839809AEUL, 0x3C93D12AUL, 0x468A4418UL, 0x3CA46C91UL, 0x088AFCDBUL, 0x3C9F1C33UL }; #define __ _masm-> diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp index 372c4898f37..dce4fbfc455 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp @@ -77,226 +77,226 @@ ATTRIBUTE_ALIGNED(4) static const juint _HALFMASK[] = { - 4160749568, 2147483647 + 0xF8000000UL, 0x7FFFFFFFUL }; ATTRIBUTE_ALIGNED(4) static const juint _ONEMASK[] = { - 0, 1072693248 + 0x00000000UL, 0x3FF00000UL }; ATTRIBUTE_ALIGNED(4) static const juint _TWOMASK[] = { - 0, 1073741824 + 0x00000000UL, 0x40000000UL }; ATTRIBUTE_ALIGNED(16) static const juint _MASK3[] = { - 0, 4294967280, 0, 4294967280 + 0x00000000UL, 0xFFFFFFF0UL, 0x00000000UL, 0xFFFFFFF0UL }; ATTRIBUTE_ALIGNED(16) static const juint _RMASK[] = { - 4294705152, 4294967295, 4294705152, 4294967295 + 0xFFFC0000UL, 0xFFFFFFFFUL, 0xFFFC0000UL, 0xFFFFFFFFUL }; ATTRIBUTE_ALIGNED(16) static const juint _L2E[] = { - 1610612736, 1082594631, 4166901572, 1055174155 + 0x60000000UL, 0x40871547UL, 0xF85DDF44UL, 0x3EE4AE0BUL }; ATTRIBUTE_ALIGNED(16) static const juint _Shifter[] = { - 0, 1127743488, 0, 3275227136 + 0x00000000UL, 0x43380000UL, 0x00000000UL, 0xC3380000UL }; ATTRIBUTE_ALIGNED(16) static const juint _cv[] = { - 3884607281, 3168131199, 3607404735, 3190582024, 1874480759, - 1032041131, 4286760334, 1053736893, 4277811695, 3211144770, - 0, 0 + 0xE78A6731UL, 0xBCD5D87FUL, 0xD704A0BFUL, 0xBE2C6B08UL, 0x6FBA4E77UL, + 0x3D83B2ABUL, 0xFF82C58EUL, 0x3ECEBFBDUL, 0xFEFA39EFUL, 0xBF662E42UL, + 0x00000000UL, 0x00000000UL }; ATTRIBUTE_ALIGNED(4) static const juint _pv[] = { - 236289503, 1064135997, 463583772, 3215696314, 1441186365, - 3212977891, 286331153, 1069617425, 2284589306, 1066820852, - 1431655765, 3218429269 + 0x0E157DDFUL, 0x3F6D6D3DUL, 0x1BA1BA1CUL, 0xBFABA1BAUL, 0x55E6C23DUL, + 0xBF8226E3UL, 0x11111111UL, 0x3FC11111UL, 0x882C10FAUL, 0x3F9664F4UL, + 0x55555555UL, 0xBFD55555UL }; ATTRIBUTE_ALIGNED(16) static const juint _T2_neg_f[] = { - 0, 1072693248, 0, 0, 1797923801, 1072687577, - 1950547427, 1013229059, 730821105, 1072681922, 2523232743, 1012067188, - 915592468, 1072676282, 352947894, 3161024371, 2174652632, 1072670657, - 4087714590, 1014450259, 35929225, 1072665048, 2809788041, 3159436968, - 2912730644, 1072659453, 3490067722, 3163405074, 2038973688, 1072653874, - 892941374, 1016046459, 1533953344, 1072648310, 769171851, 1015665633, - 1222472308, 1072642761, 1054357470, 3161021018, 929806999, 1072637227, - 3205336643, 1015259557, 481706282, 1072631708, 1696079173, 3162710528, - 3999357479, 1072626203, 2258941616, 1015924724, 2719515920, 1072620714, - 2760332941, 1015137933, 764307441, 1072615240, 3021057420, 3163329523, - 2256325230, 1072609780, 580117746, 1015317295, 2728693978, 1072604335, - 396109971, 3163462691, 2009970496, 1072598905, 2159039665, 3162572948, - 4224142467, 1072593489, 3389820386, 1015207202, 610758006, 1072588089, - 1965209397, 3161866232, 3884662774, 1072582702, 2158611599, 1014210185, - 991358482, 1072577331, 838715019, 3163157668, 351641897, 1072571974, - 2172261526, 3163010599, 1796832535, 1072566631, 3176955716, 3160585513, - 863738719, 1072561303, 1326992220, 3162613197, 1679558232, 1072555989, - 2390342287, 3163333970, 4076975200, 1072550689, 2029000899, 1015208535, - 3594158869, 1072545404, 2456521700, 3163256561, 64696965, 1072540134, - 1768797490, 1015816960, 1912561781, 1072534877, 3147495102, 1015678253, - 382305176, 1072529635, 2347622376, 3162578625, 3898795731, 1072524406, - 1249994144, 1011869818, 3707479175, 1072519192, 3613079303, 1014164738, - 3939148246, 1072513992, 3210352148, 1015274323, 135105010, 1072508807, - 1906148728, 3163375739, 721996136, 1072503635, 563754734, 1015371318, - 1242007932, 1072498477, 1132034716, 3163339831, 1532734324, 1072493333, - 3094216535, 3163162857, 1432208378, 1072488203, 1401068914, 3162363963, - 778901109, 1072483087, 2248183955, 3161268751, 3706687593, 1072477984, - 3521726940, 1013253067, 1464976603, 1072472896, 3507292405, 3161977534, - 2483480501, 1072467821, 1216371780, 1013034172, 2307442995, 1072462760, - 3190117721, 3162404539, 777507147, 1072457713, 4282924205, 1015187533, - 2029714210, 1072452679, 613660079, 1015099143, 1610600570, 1072447659, - 3766732298, 1015760183, 3657065772, 1072442652, 399025623, 3162957078, - 3716502172, 1072437659, 2303740125, 1014042725, 1631695677, 1072432680, - 2717633076, 3162344026, 1540824585, 1072427714, 1064017011, 3163487690, - 3287523847, 1072422761, 1625971539, 3157009955, 2420883922, 1072417822, - 2049810052, 1014119888, 3080351519, 1072412896, 3379126788, 3157218001, - 815859274, 1072407984, 240396590, 3163487443, 4062661092, 1072403084, - 1422616006, 3163255318, 4076559943, 1072398198, 2119478331, 3160758351, - 703710506, 1072393326, 1384660846, 1015195891, 2380618042, 1072388466, - 3149557219, 3163320799, 364333489, 1072383620, 3923737744, 3161421373, - 3092190715, 1072378786, 814012168, 3159523422, 1822067026, 1072373966, - 1241994956, 1015340290, 697153126, 1072369159, 1283515429, 3163283189, - 3861050111, 1072364364, 254893773, 3162813180, 2572866477, 1072359583, - 878562433, 1015521741, 977020788, 1072354815, 3065100517, 1015541563, - 3218338682, 1072350059, 3404164304, 3162477108, 557149882, 1072345317, - 3672720709, 1014537265, 1434058175, 1072340587, 251133233, 1015085769, - 1405169241, 1072335870, 2998539689, 3162830951, 321958744, 1072331166, - 3401933767, 1015794558, 2331271250, 1072326474, 812057446, 1012207446, - 2990417245, 1072321795, 3683467745, 3163369326, 2152073944, 1072317129, - 1486860576, 3163203456, 3964284211, 1072312475, 2111583915, 1015427164, - 3985553595, 1072307834, 4002146062, 1015834136, 2069751141, 1072303206, - 1562170675, 3162724681, 2366108318, 1072298590, 2867985102, 3161762254, - 434316067, 1072293987, 2028358766, 1013458122, 424392917, 1072289396, - 2749202995, 3162838718, 2191782032, 1072284817, 2960257726, 1013742662, - 1297350157, 1072280251, 1308022040, 3163412558, 1892288442, 1072275697, - 2446255666, 3162600381, 3833209506, 1072271155, 2722920684, 1013754842, - 2682146384, 1072266626, 2082178513, 3163363419, 2591453363, 1072262109, - 2132396182, 3159074198, 3418903055, 1072257604, 2527457337, 3160820604, - 727685349, 1072253112, 2038246809, 3162358742, 2966275557, 1072248631, - 2176155324, 3159842759, 1403662306, 1072244163, 2788809599, 3161671007, - 194117574, 1072239707, 777528612, 3163412089, 3492293770, 1072235262, - 2248032210, 1015386826, 2568320822, 1072230830, 2732824428, 1014352915, - 1577608921, 1072226410, 1875489510, 3162968394, 380978316, 1072222002, - 854188970, 3160462686, 3134592888, 1072217605, 4232266862, 1015991134, - 1110089947, 1072213221, 1451641639, 1015474673, 2759350287, 1072208848, - 1148526634, 1015894933, 3649726105, 1072204487, 4085036346, 1015649474, - 3643909174, 1072200138, 3537586109, 1014354647, 2604962541, 1072195801, - 2614425274, 3163539192, 396319521, 1072191476, 4172420816, 3159074632, - 1176749997, 1072187162, 2738998779, 3162035844, 515457527, 1072182860, - 836709333, 1015651226, 2571947539, 1072178569, 3558159064, 3163376669, - 2916157145, 1072174290, 219487565, 1015309367, 1413356050, 1072170023, - 1651349291, 3162668166, 2224145553, 1072165767, 3482522030, 3161489169, - 919555682, 1072161523, 3121969534, 1012948226, 1660913392, 1072157290, - 4218599604, 1015135707, 19972402, 1072153069, 3507899862, 1016009292, - 158781403, 1072148859, 2221464712, 3163286453, 1944781191, 1072144660, - 3993278767, 3161724279, 950803702, 1072140473, 1655364926, 1015237032, - 1339972927, 1072136297, 167908909, 1015572152, 2980802057, 1072132132, - 378619896, 1015773303, 1447192521, 1072127979, 1462857171, 3162514521, - 903334909, 1072123837, 1636462108, 1015039997, 1218806132, 1072119706, - 1818613052, 3162548441, 2263535754, 1072115586, 752233586, 3162639008, - 3907805044, 1072111477, 2257091225, 3161550407, 1727278727, 1072107380, - 3562710623, 1011471940, 4182873220, 1072103293, 629542646, 3161996303, - 2555984613, 1072099218, 2652555442, 3162552692, 1013258799, 1072095154, - 1748797611, 3160129082, 3721688645, 1072091100, 3069276937, 1015839401, - 1963711167, 1072087058, 1744767757, 3160574294, 4201977662, 1072083026, - 748330254, 1013594357, 1719614413, 1072079006, 330458198, 3163282740, - 2979960120, 1072074996, 2599109725, 1014498493, 3561793907, 1072070997, - 1157054053, 1011890350, 3339203574, 1072067009, 1483497780, 3162408754, - 2186617381, 1072063032, 2270764084, 3163272713, 4273770423, 1072059065, - 3383180809, 3163218901, 885834528, 1072055110, 1973258547, 3162261564, - 488188413, 1072051165, 3199821029, 1015564048, 2956612997, 1072047230, - 2118169751, 3162735553, 3872257780, 1072043306, 1253592103, 1015958334, - 3111574537, 1072039393, 2606161479, 3162759746, 551349105, 1072035491, - 3821916050, 3162106589, 363667784, 1072031599, 813753950, 1015785209, - 2425981843, 1072027717, 2830390851, 3163346599, 2321106615, 1072023846, - 2171176610, 1009535771, 4222122499, 1072019985, 1277378074, 3163256737, - 3712504873, 1072016135, 88491949, 1015427660, 671025100, 1072012296, - 3832014351, 3163022030, 3566716925, 1072008466, 1536826856, 1014142433, - 3689071823, 1072004647, 2321004996, 3162552716, 917841882, 1072000839, - 18715565, 1015659308, 3723038930, 1071997040, 378465264, 3162569582, - 3395129871, 1071993252, 4025345435, 3162335388, 4109806887, 1071989474, - 422403966, 1014469229, 1453150082, 1071985707, 498154669, 3161488062, - 3896463087, 1071981949, 1139797873, 3161233805, 2731501122, 1071978202, - 1774031855, 3162470021, 2135241198, 1071974465, 1236747871, 1013589147, - 1990012071, 1071970738, 3529070563, 3162813193, 2178460671, 1071967021, - 777878098, 3162842493, 2583551245, 1071963314, 3161094195, 1015606491, - 3088564500, 1071959617, 1762311517, 1015045673, 3577096743, 1071955930, - 2951496418, 1013793687, 3933059031, 1071952253, 2133366768, 3161531832, - 4040676318, 1071948586, 4090609238, 1015663458, 3784486610, 1071944929, - 1581883040, 3161698953, 3049340112, 1071941282, 3062915824, 1013170595, - 1720398391, 1071937645, 3980678963, 3163300080, 3978100823, 1071934017, - 3513027190, 1015845963, 1118294578, 1071930400, 2197495694, 3159909401, - 1617004845, 1071926792, 82804944, 1010342778, 1065662932, 1071923194, - 2533670915, 1014530238, 3645941911, 1071919605, 3814685081, 3161573341, - 654919306, 1071916027, 3232961757, 3163047469, 569847338, 1071912458, - 472945272, 3159290729, 3278348324, 1071908898, 3069497416, 1014750712, - 78413852, 1071905349, 4183226867, 3163017251, 3743175029, 1071901808, - 2072812490, 3162175075, 1276261410, 1071898278, 300981948, 1014684169, - 1156440435, 1071894757, 2351451249, 1013967056, 3272845541, 1071891245, - 928852419, 3163488248, 3219942644, 1071887743, 3798990616, 1015368806, - 887463927, 1071884251, 3596744163, 3160794166, 460407023, 1071880768, - 4237175092, 3163138469, 1829099622, 1071877294, 1016661181, 3163461005, - 589198666, 1071873830, 2664346172, 3163157962, 926591435, 1071870375, - 3208833762, 3162913514, 2732492859, 1071866929, 2691479646, 3162255684, - 1603444721, 1071863493, 1548633640, 3162201326, 1726216749, 1071860066, - 2466808228, 3161676405, 2992903935, 1071856648, 2218154406, 1015228193, - 1000925746, 1071853240, 1018491672, 3163309544, 4232894513, 1071849840, - 2383938684, 1014668519, 3991843581, 1071846450, 4092853457, 1014585763, - 171030293, 1071843070, 3526460132, 1014428778, 1253935211, 1071839698, - 1395382931, 3159702613, 2839424854, 1071836335, 1171596163, 1013041679, - 526652809, 1071832982, 4223459736, 1015879375, 2799960843, 1071829637, - 1423655381, 1015022151, 964107055, 1071826302, 2800439588, 3162833221, - 3504003472, 1071822975, 3594001060, 3157330652, 1724976915, 1071819658, - 420909223, 3163117379, 4112506593, 1071816349, 2947355221, 1014371048, - 1972484976, 1071813050, 675290301, 3161640050, 3790955393, 1071809759, - 2352942462, 3163180090, 874372905, 1071806478, 100263788, 1015940732, - 1709341917, 1071803205, 2571168217, 1014152499, 1897844341, 1071799941, - 1254300460, 1015275938, 1337108031, 1071796686, 3203724452, 1014677845, - 4219606026, 1071793439, 2434574742, 1014681548, 1853186616, 1071790202, - 3066496371, 1015656574, 2725843665, 1071786973, 1433917087, 1014838523, - 2440944790, 1071783753, 2492769774, 1014147454, 897099801, 1071780542, - 754756297, 1015241005, 2288159958, 1071777339, 2169144469, 1014876021, - 2218315341, 1071774145, 2694295388, 3163288868, 586995997, 1071770960, - 41662348, 3162627992, 1588871207, 1071767783, 143439582, 3162963416, - 828946858, 1071764615, 10642492, 1015939438, 2502433899, 1071761455, - 2148595913, 1015023991, 2214878420, 1071758304, 892270087, 3163116422, - 4162030108, 1071755161, 2763428480, 1015529349, 3949972341, 1071752027, - 2068408548, 1014913868, 1480023343, 1071748902, 2247196168, 1015327453, - 948735466, 1071745785, 3516338028, 3162574883, 2257959872, 1071742676, - 3802946148, 1012964927, 1014845819, 1071739576, 3117910646, 3161559105, - 1416741826, 1071736484, 2196380210, 1011413563, 3366293073, 1071733400, - 3119426314, 1014120554, 2471440686, 1071730325, 968836267, 3162214888, - 2930322912, 1071727258, 2599499422, 3162714047, 351405227, 1071724200, - 3125337328, 3159822479, 3228316108, 1071721149, 3010241991, 3158422804, - 2875075254, 1071718107, 4144233330, 3163333716, 3490863953, 1071715073, - 960797498, 3162948880, 685187902, 1071712048, 378731989, 1014843115, - 2952712987, 1071709030, 3293494651, 3160120301, 1608493509, 1071706021, - 3159622171, 3162807737, 852742562, 1071703020, 667253586, 1009793559, - 590962156, 1071700027, 3829346666, 3163275597, 728909815, 1071697042, - 383930225, 1015029468, 1172597893, 1071694065, 114433263, 1015347593, - 1828292879, 1071691096, 1255956747, 1015588398, 2602514713, 1071688135, - 2268929336, 1014354284, 3402036099, 1071685182, 405889334, 1015105656, - 4133881824, 1071682237, 2148155345, 3162931299, 410360776, 1071679301, - 1269990655, 1011975870, 728934454, 1071676372, 1413842688, 1014178612, - 702412510, 1071673451, 3803266087, 3162280415, 238821257, 1071670538, - 1469694871, 3162884987, 3541402996, 1071667632, 2759177317, 1014854626, - 1928746161, 1071664735, 983617676, 1014285177, 3899555717, 1071661845, - 427280750, 3162546972, 772914124, 1071658964, 4004372762, 1012230161, - 1048019041, 1071656090, 1398474845, 3160510595, 339411585, 1071653224, - 264588982, 3161636657, 2851812149, 1071650365, 2595802551, 1015767337, - 4200250559, 1071647514, 2808127345, 3161781938 + 0x00000000UL, 0x3FF00000UL, 0x00000000UL, 0x00000000UL, 0x6B2A23D9UL, 0x3FEFE9D9UL, + 0x7442FDE3UL, 0x3C64A603UL, 0x2B8F71F1UL, 0x3FEFD3C2UL, 0x966579E7UL, 0x3C52EB74UL, + 0x3692D514UL, 0x3FEFBDBAUL, 0x15098EB6UL, 0xBC696773UL, 0x819E90D8UL, 0x3FEFA7C1UL, + 0xF3A5931EUL, 0x3C774853UL, 0x02243C89UL, 0x3FEF91D8UL, 0xA779F689UL, 0xBC512EA8UL, + 0xAD9CBE14UL, 0x3FEF7BFDUL, 0xD006350AUL, 0xBC8DBB12UL, 0x798844F8UL, 0x3FEF6632UL, + 0x3539343EUL, 0x3C8FA37BUL, 0x5B6E4540UL, 0x3FEF5076UL, 0x2DD8A18BUL, 0x3C89D3E1UL, + 0x48DD7274UL, 0x3FEF3AC9UL, 0x3ED837DEUL, 0xBC695A5AUL, 0x376BBA97UL, 0x3FEF252BUL, + 0xBF0D8E43UL, 0x3C83A1A5UL, 0x1CB6412AUL, 0x3FEF0F9CUL, 0x65181D45UL, 0xBC832200UL, + 0xEE615A27UL, 0x3FEEFA1BUL, 0x86A4B6B0UL, 0x3C8DC7F4UL, 0xA2188510UL, 0x3FEEE4AAUL, + 0xA487568DUL, 0x3C81C68DUL, 0x2D8E67F1UL, 0x3FEECF48UL, 0xB411AD8CUL, 0xBC8C93F3UL, + 0x867CCA6EUL, 0x3FEEB9F4UL, 0x2293E4F2UL, 0x3C84832FUL, 0xA2A490DAUL, 0x3FEEA4AFUL, + 0x179C2893UL, 0xBC8E9C23UL, 0x77CDB740UL, 0x3FEE8F79UL, 0x80B054B1UL, 0xBC810894UL, + 0xFBC74C83UL, 0x3FEE7A51UL, 0xCA0C8DE2UL, 0x3C82D522UL, 0x24676D76UL, 0x3FEE6539UL, + 0x7522B735UL, 0xBC763FF8UL, 0xE78B3FF6UL, 0x3FEE502EUL, 0x80A9CC8FUL, 0x3C739E89UL, + 0x3B16EE12UL, 0x3FEE3B33UL, 0x31FDC68BUL, 0xBC89F4A4UL, 0x14F5A129UL, 0x3FEE2646UL, + 0x817A1496UL, 0xBC87B627UL, 0x6B197D17UL, 0x3FEE1167UL, 0xBD5C7F44UL, 0xBC62B529UL, + 0x337B9B5FUL, 0x3FEDFC97UL, 0x4F184B5CUL, 0xBC81A5CDUL, 0x641C0658UL, 0x3FEDE7D5UL, + 0x8E79BA8FUL, 0xBC8CA552UL, 0xF301B460UL, 0x3FEDD321UL, 0x78F018C3UL, 0x3C82DA57UL, + 0xD63A8315UL, 0x3FEDBE7CUL, 0x926B8BE4UL, 0xBC8B76F1UL, 0x03DB3285UL, 0x3FEDA9E6UL, + 0x696DB532UL, 0x3C8C2300UL, 0x71FF6075UL, 0x3FED955DUL, 0xBB9AF6BEUL, 0x3C8A052DUL, + 0x16C98398UL, 0x3FED80E3UL, 0x8BEDDFE8UL, 0xBC811EC1UL, 0xE862E6D3UL, 0x3FED6C76UL, + 0x4A8165A0UL, 0x3C4FE87AUL, 0xDCFBA487UL, 0x3FED5818UL, 0xD75B3707UL, 0x3C72ED02UL, + 0xEACAA1D6UL, 0x3FED43C8UL, 0xBF5A1614UL, 0x3C83DB53UL, 0x080D89F2UL, 0x3FED2F87UL, + 0x719D8578UL, 0xBC8D487BUL, 0x2B08C968UL, 0x3FED1B53UL, 0x219A36EEUL, 0x3C855636UL, + 0x4A07897CUL, 0x3FED072DUL, 0x43797A9CUL, 0xBC8CBC37UL, 0x5B5BAB74UL, 0x3FECF315UL, + 0xB86DFF57UL, 0xBC8A08E9UL, 0x555DC3FAUL, 0x3FECDF0BUL, 0x53829D72UL, 0xBC7DD83BUL, + 0x2E6D1675UL, 0x3FECCB0FUL, 0x86009093UL, 0xBC6D220FUL, 0xDCEF9069UL, 0x3FECB720UL, + 0xD1E949DCUL, 0x3C6503CBUL, 0x5751C4DBUL, 0x3FECA340UL, 0xD10D08F5UL, 0xBC77F2BEUL, + 0x9406E7B5UL, 0x3FEC8F6DUL, 0x48805C44UL, 0x3C61ACBCUL, 0x8988C933UL, 0x3FEC7BA8UL, + 0xBE255559UL, 0xBC7E76BBUL, 0x2E57D14BUL, 0x3FEC67F1UL, 0xFF483CADUL, 0x3C82884DUL, + 0x78FAFB22UL, 0x3FEC5447UL, 0x2493B5AFUL, 0x3C812F07UL, 0x5FFFD07AUL, 0x3FEC40ABUL, + 0xE083C60AUL, 0x3C8B4537UL, 0xD9FA652CUL, 0x3FEC2D1CUL, 0x17C8A5D7UL, 0xBC86E516UL, + 0xDD85529CUL, 0x3FEC199BUL, 0x895048DDUL, 0x3C711065UL, 0x6141B33DUL, 0x3FEC0628UL, + 0xA1FBCA34UL, 0xBC7D8A5AUL, 0x5BD71E09UL, 0x3FEBF2C2UL, 0x3F6B9C73UL, 0xBC8EFDCAUL, + 0xC3F3A207UL, 0x3FEBDF69UL, 0x60EA5B53UL, 0xBC2C2623UL, 0x904BC1D2UL, 0x3FEBCC1EUL, + 0x7A2D9E84UL, 0x3C723DD0UL, 0xB79A6F1FUL, 0x3FEBB8E0UL, 0xC9696204UL, 0xBC2F52D1UL, + 0x30A1064AUL, 0x3FEBA5B0UL, 0x0E54292EUL, 0xBC8EFCD3UL, 0xF22749E4UL, 0x3FEB928CUL, + 0x54CB65C6UL, 0xBC8B7216UL, 0xF2FB5E47UL, 0x3FEB7F76UL, 0x7E54AC3BUL, 0xBC65584FUL, + 0x29F1C52AUL, 0x3FEB6C6EUL, 0x52883F6EUL, 0x3C82A8F3UL, 0x8DE5593AUL, 0x3FEB5972UL, + 0xBBBA6DE3UL, 0xBC8C71DFUL, 0x15B749B1UL, 0x3FEB4684UL, 0xE9DF7C90UL, 0xBC6F763DUL, + 0xB84F15FBUL, 0x3FEB33A2UL, 0x3084D708UL, 0xBC52805EUL, 0x6C9A8952UL, 0x3FEB20CEUL, + 0x4A0756CCUL, 0x3C84DD02UL, 0x298DB666UL, 0x3FEB0E07UL, 0x4C80E425UL, 0xBC8BDEF5UL, + 0xE622F2FFUL, 0x3FEAFB4CUL, 0x0F315ECDUL, 0xBC84B2FCUL, 0x995AD3ADUL, 0x3FEAE89FUL, + 0x345DCC81UL, 0x3C87A1CDUL, 0x3A3C2774UL, 0x3FEAD5FFUL, 0xB6B1B8E5UL, 0x3C87EF3BUL, + 0xBFD3F37AUL, 0x3FEAC36BUL, 0xCAE76CD0UL, 0xBC7F9234UL, 0x21356EBAUL, 0x3FEAB0E5UL, + 0xDAE94545UL, 0x3C789C31UL, 0x5579FDBFUL, 0x3FEA9E6BUL, 0x0EF7FD31UL, 0x3C80FAC9UL, + 0x53C12E59UL, 0x3FEA8BFEUL, 0xB2BA15A9UL, 0xBC84F867UL, 0x1330B358UL, 0x3FEA799EUL, + 0xCAC563C7UL, 0x3C8BCB7EUL, 0x8AF46052UL, 0x3FEA674AUL, 0x30670366UL, 0x3C550F56UL, + 0xB23E255DUL, 0x3FEA5503UL, 0xDB8D41E1UL, 0xBC8D2F6EUL, 0x80460AD8UL, 0x3FEA42C9UL, + 0x589FB120UL, 0xBC8AA780UL, 0xEC4A2D33UL, 0x3FEA309BUL, 0x7DDC36ABUL, 0x3C86305CUL, + 0xED8EB8BBUL, 0x3FEA1E7AUL, 0xEE8BE70EUL, 0x3C8C6618UL, 0x7B5DE565UL, 0x3FEA0C66UL, + 0x5D1CD533UL, 0xBC835949UL, 0x8D07F29EUL, 0x3FE9FA5EUL, 0xAAF1FACEUL, 0xBC74A9CEUL, + 0x19E32323UL, 0x3FE9E863UL, 0x78E64C6EUL, 0x3C6824CAUL, 0x194BB8D5UL, 0x3FE9D674UL, + 0xA3DD8233UL, 0xBC8516BEUL, 0x82A3F090UL, 0x3FE9C491UL, 0xB071F2BEUL, 0x3C6C7C46UL, + 0x4D53FE0DUL, 0x3FE9B2BBUL, 0x4DF6D518UL, 0xBC8DD84EUL, 0x70CA07BAUL, 0x3FE9A0F1UL, + 0x91CEE632UL, 0xBC8173BDUL, 0xE47A22A2UL, 0x3FE98F33UL, 0xA24C78ECUL, 0x3C6CABDAUL, + 0x9FDE4E50UL, 0x3FE97D82UL, 0x7C1B85D1UL, 0xBC8D185BUL, 0x9A7670B3UL, 0x3FE96BDDUL, + 0x7F19C896UL, 0xBC4BA596UL, 0xCBC8520FUL, 0x3FE95A44UL, 0x96A5F039UL, 0xBC664B7CUL, + 0x2B5F98E5UL, 0x3FE948B8UL, 0x797D2D99UL, 0xBC7DC3D6UL, 0xB0CDC5E5UL, 0x3FE93737UL, + 0x81B57EBCUL, 0xBC575FC7UL, 0x53AA2FE2UL, 0x3FE925C3UL, 0xA639DB7FUL, 0xBC73455FUL, + 0x0B91FFC6UL, 0x3FE9145BUL, 0x2E582524UL, 0xBC8DD679UL, 0xD0282C8AUL, 0x3FE902FEUL, + 0x85FE3FD2UL, 0x3C8592CAUL, 0x99157736UL, 0x3FE8F1AEUL, 0xA2E3976CUL, 0x3C75CC13UL, + 0x5E0866D9UL, 0x3FE8E06AUL, 0x6FC9B2E6UL, 0xBC87114AUL, 0x16B5448CUL, 0x3FE8CF32UL, + 0x32E9E3AAUL, 0xBC60D55EUL, 0xBAD61778UL, 0x3FE8BE05UL, 0xFC43446EUL, 0x3C8ECB5EUL, + 0x422AA0DBUL, 0x3FE8ACE5UL, 0x56864B27UL, 0x3C86E9F1UL, 0xA478580FUL, 0x3FE89BD0UL, + 0x4475202AUL, 0x3C8D5395UL, 0xD98A6699UL, 0x3FE88AC7UL, 0xF37CB53AUL, 0x3C8994C2UL, + 0xD931A436UL, 0x3FE879CAUL, 0xD2DB47BDUL, 0x3C75D2D7UL, 0x9B4492EDUL, 0x3FE868D9UL, + 0x9BD4F6BAUL, 0xBC8FC6F8UL, 0x179F5B21UL, 0x3FE857F4UL, 0xF8B216D0UL, 0xBC4BA748UL, + 0x4623C7ADUL, 0x3FE8471AUL, 0xA341CDFBUL, 0xBC78D684UL, 0x1EB941F7UL, 0x3FE8364CUL, + 0x31DF2BD5UL, 0x3C899B9AUL, 0x994CCE13UL, 0x3FE82589UL, 0xD41532D8UL, 0xBC8D4C1DUL, + 0xADD106D9UL, 0x3FE814D2UL, 0x0D151D4DUL, 0x3C846437UL, 0x543E1A12UL, 0x3FE80427UL, + 0x626D972BUL, 0xBC827C86UL, 0x8491C491UL, 0x3FE7F387UL, 0xCF9311AEUL, 0xBC707F11UL, + 0x36CF4E62UL, 0x3FE7E2F3UL, 0xBA15797EUL, 0x3C605D02UL, 0x62FF86F0UL, 0x3FE7D26AUL, + 0xFB72B8B4UL, 0x3C81BDDBUL, 0x0130C132UL, 0x3FE7C1EDUL, 0xD1164DD6UL, 0x3C8F124CUL, + 0x0976CFDBUL, 0x3FE7B17BUL, 0x8468DC88UL, 0xBC8BEBB5UL, 0x73EB0187UL, 0x3FE7A114UL, + 0xEE04992FUL, 0xBC741577UL, 0x38AC1CF6UL, 0x3FE790B9UL, 0x62AADD3EUL, 0x3C8349A8UL, + 0x4FDE5D3FUL, 0x3FE78069UL, 0x0A02162DUL, 0x3C8866B8UL, 0xB1AB6E09UL, 0x3FE77024UL, + 0x169147F8UL, 0x3C8B7877UL, 0x564267C9UL, 0x3FE75FEBUL, 0x57316DD3UL, 0xBC802459UL, + 0x35D7CBFDUL, 0x3FE74FBDUL, 0x618A6E1CUL, 0x3C8047FDUL, 0x48A58174UL, 0x3FE73F9AUL, + 0x6C65D53CUL, 0xBC80A8D9UL, 0x86EAD08AUL, 0x3FE72F82UL, 0x2CD62C72UL, 0xBC820AA0UL, + 0xE8EC5F74UL, 0x3FE71F75UL, 0x86887A99UL, 0xBC716E47UL, 0x66F42E87UL, 0x3FE70F74UL, + 0xD45AA65FUL, 0x3C49D644UL, 0xF9519484UL, 0x3FE6FF7DUL, 0x25860EF6UL, 0xBC783C0FUL, + 0x98593AE5UL, 0x3FE6EF92UL, 0x9E1AC8B2UL, 0xBC80B974UL, 0x3C651A2FUL, 0x3FE6DFB2UL, + 0x683C88ABUL, 0xBC5BBE3AUL, 0xDDD47645UL, 0x3FE6CFDCUL, 0xB6F17309UL, 0x3C8C7AA9UL, + 0x750BDABFUL, 0x3FE6C012UL, 0x67FF0B0DUL, 0xBC628956UL, 0xFA75173EUL, 0x3FE6B052UL, + 0x2C9A9D0EUL, 0x3C6A38F5UL, 0x667F3BCDUL, 0x3FE6A09EUL, 0x13B26456UL, 0xBC8BDD34UL, + 0xB19E9538UL, 0x3FE690F4UL, 0x9AEB445DUL, 0x3C7804BDUL, 0xD44CA973UL, 0x3FE68155UL, + 0x44F73E65UL, 0x3C5038AEUL, 0xC70833F6UL, 0x3FE671C1UL, 0x586C6134UL, 0xBC7E8732UL, + 0x82552225UL, 0x3FE66238UL, 0x87591C34UL, 0xBC8BB609UL, 0xFEBC8FB7UL, 0x3FE652B9UL, + 0xC9A73E09UL, 0xBC8AE3D5UL, 0x34CCC320UL, 0x3FE64346UL, 0x759D8933UL, 0xBC7C483CUL, + 0x1D1929FDUL, 0x3FE633DDUL, 0xBEB964E5UL, 0x3C884710UL, 0xB03A5585UL, 0x3FE6247EUL, + 0x7E40B497UL, 0xBC8383C1UL, 0xE6CDF6F4UL, 0x3FE6152AUL, 0x4AB84C27UL, 0x3C8E4B3EUL, + 0xB976DC09UL, 0x3FE605E1UL, 0x9B56DE47UL, 0xBC83E242UL, 0x20DCEB71UL, 0x3FE5F6A3UL, + 0xE3CDCF92UL, 0xBC79EADDUL, 0x15AD2148UL, 0x3FE5E76FUL, 0x3080E65EUL, 0x3C8BA6F9UL, + 0x90998B93UL, 0x3FE5D845UL, 0xA8B45643UL, 0xBC8CD6A7UL, 0x8A5946B7UL, 0x3FE5C926UL, + 0x816986A2UL, 0x3C2C4B1BUL, 0xFBA87A03UL, 0x3FE5BA11UL, 0x4C233E1AUL, 0xBC8B77A1UL, + 0xDD485429UL, 0x3FE5AB07UL, 0x054647ADUL, 0x3C86324CUL, 0x27FF07CCUL, 0x3FE59C08UL, + 0xE467E60FUL, 0xBC87E2CEUL, 0xD497C7FDUL, 0x3FE58D12UL, 0x5B9A1DE8UL, 0x3C7295E1UL, + 0xDBE2C4CFUL, 0x3FE57E27UL, 0x8A57B9C4UL, 0xBC80B98CUL, 0x36B527DAUL, 0x3FE56F47UL, + 0x011D93ADUL, 0x3C89BB2CUL, 0xDDE910D2UL, 0x3FE56070UL, 0x168EEBF0UL, 0xBC80FB6EUL, + 0xCA5D920FUL, 0x3FE551A4UL, 0xEFEDE59BUL, 0xBC7D689CUL, 0xF4F6AD27UL, 0x3FE542E2UL, + 0x192D5F7EUL, 0x3C77926DUL, 0x569D4F82UL, 0x3FE5342BUL, 0x1DB13CADUL, 0xBC707ABEUL, + 0xE83F4EEFUL, 0x3FE5257DUL, 0x43EFEF71UL, 0xBC6C998DUL, 0xA2CF6642UL, 0x3FE516DAUL, + 0x69BD93EFUL, 0xBC7F7685UL, 0x7F4531EEUL, 0x3FE50841UL, 0x49B7465FUL, 0x3C6A249BUL, + 0x769D2CA7UL, 0x3FE4F9B2UL, 0xD25957E3UL, 0xBC84B309UL, 0x81D8ABFFUL, 0x3FE4EB2DUL, + 0x2E5D7A52UL, 0xBC85257DUL, 0x99FDDD0DUL, 0x3FE4DCB2UL, 0xBC6A7833UL, 0x3C88ECDBUL, + 0xB817C114UL, 0x3FE4CE41UL, 0x690ABD5DUL, 0x3C805E29UL, 0xD5362A27UL, 0x3FE4BFDAUL, + 0xAFEC42E2UL, 0x3C6D4397UL, 0xEA6DB7D7UL, 0x3FE4B17DUL, 0x7F2897F0UL, 0xBC7125B8UL, + 0xF0D7D3DEUL, 0x3FE4A32AUL, 0xF3D1BE56UL, 0x3C89CB62UL, 0xE192AED2UL, 0x3FE494E1UL, + 0x5E499EA0UL, 0xBC73B289UL, 0xB5C13CD0UL, 0x3FE486A2UL, 0xB69062F0UL, 0x3C63C1A3UL, + 0x668B3237UL, 0x3FE4786DUL, 0xED445733UL, 0xBC8C20F0UL, 0xED1D0057UL, 0x3FE46A41UL, + 0xD1648A76UL, 0x3C8C944BUL, 0x42A7D232UL, 0x3FE45C20UL, 0x82FB1F8EUL, 0xBC586419UL, + 0x6061892DUL, 0x3FE44E08UL, 0x04EF80D0UL, 0x3C389B7AUL, 0x3F84B9D4UL, 0x3FE43FFAUL, + 0x9704C003UL, 0x3C7880BEUL, 0xD950A897UL, 0x3FE431F5UL, 0xE35F7999UL, 0xBC71C7DDUL, + 0x2709468AUL, 0x3FE423FBUL, 0xC0B314DDUL, 0xBC88462DUL, 0x21F72E2AUL, 0x3FE4160AUL, + 0x1C309278UL, 0xBC4EF369UL, 0xC367A024UL, 0x3FE40822UL, 0xB6F4D048UL, 0x3C7BDDF8UL, + 0x04AC801CUL, 0x3FE3FA45UL, 0xF956F9F3UL, 0xBC87D023UL, 0xDF1C5175UL, 0x3FE3EC70UL, + 0x7B8C9BCAUL, 0xBC7AF663UL, 0x4C123422UL, 0x3FE3DEA6UL, 0x11F09EBCUL, 0x3C7ADA09UL, + 0x44EDE173UL, 0x3FE3D0E5UL, 0x8C284C71UL, 0x3C6FE8D0UL, 0xC313A8E5UL, 0x3FE3C32DUL, + 0x375D29C3UL, 0xBC8EFFF8UL, 0xBFEC6CF4UL, 0x3FE3B57FUL, 0xE26FFF18UL, 0x3C854C66UL, + 0x34E59FF7UL, 0x3FE3A7DBUL, 0xD661F5E3UL, 0xBC65E436UL, 0x1B7140EFUL, 0x3FE39A40UL, + 0xFC8E2934UL, 0xBC89A9A5UL, 0x6D05D866UL, 0x3FE38CAEUL, 0x3C9904BDUL, 0xBC8E958DUL, + 0x231E754AUL, 0x3FE37F26UL, 0x9ECEB23CUL, 0xBC89F5CAUL, 0x373AA9CBUL, 0x3FE371A7UL, + 0xBF42EAE2UL, 0xBC863AEAUL, 0xA2DE883BUL, 0x3FE36431UL, 0xA06CB85EUL, 0xBC7C3144UL, + 0x5F929FF1UL, 0x3FE356C5UL, 0x5C4E4628UL, 0xBC7B5CEEUL, 0x66E3FA2DUL, 0x3FE34962UL, + 0x930881A4UL, 0xBC735A75UL, 0xB26416FFUL, 0x3FE33C08UL, 0x843659A6UL, 0x3C832721UL, + 0x3BA8EA32UL, 0x3FE32EB8UL, 0x3CB4F318UL, 0xBC8C45E8UL, 0xFC4CD831UL, 0x3FE32170UL, + 0x8E18047CUL, 0x3C7A9CE7UL, 0xEDEEB2FDUL, 0x3FE31432UL, 0xF3F3FCD1UL, 0x3C7959A3UL, + 0x0A31B715UL, 0x3FE306FEUL, 0xD23182E4UL, 0x3C76F46AUL, 0x4ABD886BUL, 0x3FE2F9D2UL, + 0x532BDA93UL, 0xBC553C55UL, 0xA93E2F56UL, 0x3FE2ECAFUL, 0x45D52383UL, 0x3C61CA0FUL, + 0x1F641589UL, 0x3FE2DF96UL, 0xFBBCE198UL, 0x3C8D16CFUL, 0xA6E4030BUL, 0x3FE2D285UL, + 0x54DB41D5UL, 0x3C800247UL, 0x39771B2FUL, 0x3FE2C57EUL, 0xA6EB5124UL, 0xBC850145UL, + 0xD0DAD990UL, 0x3FE2B87FUL, 0xD6381AA4UL, 0xBC310ADCUL, 0x66D10F13UL, 0x3FE2AB8AUL, + 0x191690A7UL, 0xBC895743UL, 0xF51FDEE1UL, 0x3FE29E9DUL, 0xAFAD1255UL, 0x3C7612E8UL, + 0x7591BB70UL, 0x3FE291BAUL, 0x28401CBDUL, 0xBC72CC72UL, 0xE1F56381UL, 0x3FE284DFUL, + 0x8C3F0D7EUL, 0xBC8A4C3AUL, 0x341DDF29UL, 0x3FE2780EUL, 0x05F9E76CUL, 0x3C8E067CUL, + 0x65E27CDDUL, 0x3FE26B45UL, 0x9940E9D9UL, 0x3C72BD33UL, 0x711ECE75UL, 0x3FE25E85UL, + 0x4AC31B2CUL, 0x3C83E1A2UL, 0x4FB2A63FUL, 0x3FE251CEUL, 0xBEF4F4A4UL, 0x3C7AC155UL, + 0xFB82140AUL, 0x3FE2451FUL, 0x911CA996UL, 0x3C7ACFCCUL, 0x6E756238UL, 0x3FE2387AUL, + 0xB6C70573UL, 0x3C89B07EUL, 0xA27912D1UL, 0x3FE22BDDUL, 0x5577D69FUL, 0x3C7D34FBUL, + 0x917DDC96UL, 0x3FE21F49UL, 0x9494A5EEUL, 0x3C72A97EUL, 0x3578A819UL, 0x3FE212BEUL, + 0x2CFCAAC9UL, 0x3C83592DUL, 0x88628CD6UL, 0x3FE2063BUL, 0x814A8495UL, 0x3C7DC775UL, + 0x8438CE4DUL, 0x3FE1F9C1UL, 0xA097AF5CUL, 0xBC8BF524UL, 0x22FCD91DUL, 0x3FE1ED50UL, + 0x027BB78CUL, 0xBC81DF98UL, 0x5EB44027UL, 0x3FE1E0E7UL, 0x088CB6DEUL, 0xBC86FDD8UL, + 0x3168B9AAUL, 0x3FE1D487UL, 0x00A2643CUL, 0x3C8E016EUL, 0x95281C6BUL, 0x3FE1C82FUL, + 0x8010F8C9UL, 0x3C800977UL, 0x84045CD4UL, 0x3FE1BBE0UL, 0x352EF607UL, 0xBC895386UL, + 0xF8138A1CUL, 0x3FE1AF99UL, 0xA4B69280UL, 0x3C87BF85UL, 0xEB6FCB75UL, 0x3FE1A35BUL, + 0x7B4968E4UL, 0x3C7E5B4CUL, 0x58375D2FUL, 0x3FE19726UL, 0x85F17E08UL, 0x3C84AADDUL, + 0x388C8DEAUL, 0x3FE18AF9UL, 0xD1970F6CUL, 0xBC811023UL, 0x8695BBC0UL, 0x3FE17ED4UL, + 0xE2AC5A64UL, 0x3C609E3FUL, 0x3C7D517BUL, 0x3FE172B8UL, 0xB9D78A76UL, 0xBC719041UL, + 0x5471C3C2UL, 0x3FE166A4UL, 0x82EA1A32UL, 0x3C48F23BUL, 0xC8A58E51UL, 0x3FE15A98UL, + 0xB9EEAB0AUL, 0x3C72406AUL, 0x934F312EUL, 0x3FE14E95UL, 0x39BF44ABUL, 0xBC7B91E8UL, + 0xAEA92DE0UL, 0x3FE1429AUL, 0x9AF1369EUL, 0xBC832FBFUL, 0x14F204ABUL, 0x3FE136A8UL, + 0xBA48DCF0UL, 0xBC57108FUL, 0xC06C31CCUL, 0x3FE12ABDUL, 0xB36CA5C7UL, 0xBC41B514UL, + 0xAB5E2AB6UL, 0x3FE11EDBUL, 0xF703FB72UL, 0xBC8CA454UL, 0xD0125B51UL, 0x3FE11301UL, + 0x39449B3AUL, 0xBC86C510UL, 0x28D7233EUL, 0x3FE10730UL, 0x1692FDD5UL, 0x3C7D46EBUL, + 0xAFFED31BUL, 0x3FE0FB66UL, 0xC44EBD7BUL, 0xBC5B9BEDUL, 0x5FDFA9C5UL, 0x3FE0EFA5UL, + 0xBC54021BUL, 0xBC849DB9UL, 0x32D3D1A2UL, 0x3FE0E3ECUL, 0x27C57B52UL, 0x3C303A17UL, + 0x23395DECUL, 0x3FE0D83BUL, 0xE43F316AUL, 0xBC8BC14DUL, 0x2B7247F7UL, 0x3FE0CC92UL, + 0x16E24F71UL, 0x3C801EDCUL, 0x45E46C85UL, 0x3FE0C0F1UL, 0x06D21CEFUL, 0x3C84F989UL, + 0x6CF9890FUL, 0x3FE0B558UL, 0x4ADC610BUL, 0x3C88A62EUL, 0x9B1F3919UL, 0x3FE0A9C7UL, + 0x873D1D38UL, 0x3C75D16CUL, 0xCAC6F383UL, 0x3FE09E3EUL, 0x18316136UL, 0x3C814878UL, + 0xF66607E0UL, 0x3FE092BDUL, 0x800A3FD1UL, 0xBC868063UL, 0x18759BC8UL, 0x3FE08745UL, + 0x4BB284FFUL, 0x3C5186BEUL, 0x2B72A836UL, 0x3FE07BD4UL, 0x54458700UL, 0x3C732334UL, + 0x29DDF6DEUL, 0x3FE0706BUL, 0xE2B13C27UL, 0xBC7C91DFUL, 0x0E3C1F89UL, 0x3FE0650AUL, + 0x5799C397UL, 0xBC85CB7BUL, 0xD3158574UL, 0x3FE059B0UL, 0xA475B465UL, 0x3C7D73E2UL, + 0x72F654B1UL, 0x3FE04E5FUL, 0x3AA0D08CUL, 0x3C74C379UL, 0xE86E7F85UL, 0x3FE04315UL, + 0x1977C96EUL, 0xBC80A31CUL, 0x2E11BBCCUL, 0x3FE037D4UL, 0xEEADE11AUL, 0x3C556811UL, + 0x3E778061UL, 0x3FE02C9AUL, 0x535B085DUL, 0xBC619083UL, 0x143B0281UL, 0x3FE02168UL, + 0x0FC54EB6UL, 0xBC72BF31UL, 0xA9FB3335UL, 0x3FE0163DUL, 0x9AB8CDB7UL, 0x3C8B6129UL, + 0xFA5ABCBFUL, 0x3FE00B1AUL, 0xA7609F71UL, 0xBC74F6B2UL }; #define __ _masm-> diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 2eb748e350c..efe0482e095 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -7664,8 +7664,11 @@ instruct vcastFtoD_reg(vec dst, vec src) %{ instruct castFtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n->in(1)) < 64 && - type2aelembytes(Matcher::vector_element_basic_type(n)) <= 4); + predicate(!VM_Version::supports_avx10_2() && + !VM_Version::supports_avx512vl() && + Matcher::vector_length_in_bytes(n->in(1)) < 64 && + type2aelembytes(Matcher::vector_element_basic_type(n)) <= 4 && + is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastF2X src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP xtmp4, KILL cr); format %{ "vector_cast_f2x $dst,$src\t! using $xtmp1, $xtmp2, $xtmp3 and $xtmp4 as TEMP" %} @@ -7687,7 +7690,8 @@ instruct castFtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec %} instruct castFtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2, rFlagsReg cr) %{ - predicate((VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) && + predicate(!VM_Version::supports_avx10_2() && + (VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastF2X src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2, KILL cr); @@ -7709,6 +7713,33 @@ instruct castFtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, k ins_pipe( pipe_slow ); %} +instruct castFtoX_reg_avx10(vec dst, vec src) %{ + predicate(VM_Version::supports_avx10_2() && + is_integral_type(Matcher::vector_element_basic_type(n))); + match(Set dst (VectorCastF2X src)); + format %{ "vector_cast_f2x_avx10 $dst, $src\t!" %} + ins_encode %{ + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + int vlen_enc = (to_elem_bt == T_LONG) ? vector_length_encoding(this) : vector_length_encoding(this, $src); + __ vector_castF2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct castFtoX_mem_avx10(vec dst, memory src) %{ + predicate(VM_Version::supports_avx10_2() && + is_integral_type(Matcher::vector_element_basic_type(n))); + match(Set dst (VectorCastF2X (LoadVector src))); + format %{ "vector_cast_f2x_avx10 $dst, $src\t!" %} + ins_encode %{ + int vlen = Matcher::vector_length(this); + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + int vlen_enc = (to_elem_bt == T_LONG) ? vector_length_encoding(this) : vector_length_encoding(vlen * sizeof(jfloat)); + __ vector_castF2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + instruct vcastDtoF_reg(vec dst, vec src) %{ predicate(Matcher::vector_element_basic_type(n) == T_FLOAT); match(Set dst (VectorCastD2X src)); @@ -7721,7 +7752,9 @@ instruct vcastDtoF_reg(vec dst, vec src) %{ %} instruct castDtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4, vec xtmp5, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n->in(1)) < 64 && + predicate(!VM_Version::supports_avx10_2() && + !VM_Version::supports_avx512vl() && + Matcher::vector_length_in_bytes(n->in(1)) < 64 && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastD2X src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP xtmp4, TEMP xtmp5, KILL cr); @@ -7737,7 +7770,8 @@ instruct castDtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec %} instruct castDtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2, rFlagsReg cr) %{ - predicate((VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) && + predicate(!VM_Version::supports_avx10_2() && + (VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastD2X src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2, KILL cr); @@ -7753,6 +7787,33 @@ instruct castDtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, k ins_pipe( pipe_slow ); %} +instruct castDtoX_reg_avx10(vec dst, vec src) %{ + predicate(VM_Version::supports_avx10_2() && + is_integral_type(Matcher::vector_element_basic_type(n))); + match(Set dst (VectorCastD2X src)); + format %{ "vector_cast_d2x_avx10 $dst, $src\t!" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this, $src); + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + __ vector_castD2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct castDtoX_mem_avx10(vec dst, memory src) %{ + predicate(VM_Version::supports_avx10_2() && + is_integral_type(Matcher::vector_element_basic_type(n))); + match(Set dst (VectorCastD2X (LoadVector src))); + format %{ "vector_cast_d2x_avx10 $dst, $src\t!" %} + ins_encode %{ + int vlen = Matcher::vector_length(this); + int vlen_enc = vector_length_encoding(vlen * sizeof(jdouble)); + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + __ vector_castD2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + instruct vucast(vec dst, vec src) %{ match(Set dst (VectorUCastB2X src)); match(Set dst (VectorUCastS2X src)); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 0914bea82a1..b40f9e2924a 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -1697,11 +1697,6 @@ RegMask Matcher::modL_proj_mask() { return LONG_RDX_REG_mask(); } -// Register for saving SP into on method handle invokes. Not used on x86_64. -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return NO_REG_mask(); -} - %} //----------ENCODING BLOCK----------------------------------------------------- @@ -11712,6 +11707,7 @@ instruct convD2F_reg_mem(regF dst, memory src) // XXX do mem variants instruct convF2I_reg_reg(rRegI dst, regF src, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (ConvF2I src)); effect(KILL cr); format %{ "convert_f2i $dst, $src" %} @@ -11721,8 +11717,31 @@ instruct convF2I_reg_reg(rRegI dst, regF src, rFlagsReg cr) ins_pipe(pipe_slow); %} +instruct convF2I_reg_reg_avx10(rRegI dst, regF src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2I src)); + format %{ "evcvttss2sisl $dst, $src" %} + ins_encode %{ + __ evcvttss2sisl($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convF2I_reg_mem_avx10(rRegI dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2I (LoadF src))); + format %{ "evcvttss2sisl $dst, $src" %} + ins_encode %{ + __ evcvttss2sisl($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + instruct convF2L_reg_reg(rRegL dst, regF src, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (ConvF2L src)); effect(KILL cr); format %{ "convert_f2l $dst, $src"%} @@ -11732,8 +11751,31 @@ instruct convF2L_reg_reg(rRegL dst, regF src, rFlagsReg cr) ins_pipe(pipe_slow); %} +instruct convF2L_reg_reg_avx10(rRegL dst, regF src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2L src)); + format %{ "evcvttss2sisq $dst, $src" %} + ins_encode %{ + __ evcvttss2sisq($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convF2L_reg_mem_avx10(rRegL dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2L (LoadF src))); + format %{ "evcvttss2sisq $dst, $src" %} + ins_encode %{ + __ evcvttss2sisq($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + instruct convD2I_reg_reg(rRegI dst, regD src, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (ConvD2I src)); effect(KILL cr); format %{ "convert_d2i $dst, $src"%} @@ -11743,8 +11785,31 @@ instruct convD2I_reg_reg(rRegI dst, regD src, rFlagsReg cr) ins_pipe(pipe_slow); %} +instruct convD2I_reg_reg_avx10(rRegI dst, regD src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2I src)); + format %{ "evcvttsd2sisl $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisl($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convD2I_reg_mem_avx10(rRegI dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2I (LoadD src))); + format %{ "evcvttsd2sisl $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisl($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + instruct convD2L_reg_reg(rRegL dst, regD src, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (ConvD2L src)); effect(KILL cr); format %{ "convert_d2l $dst, $src"%} @@ -11754,6 +11819,28 @@ instruct convD2L_reg_reg(rRegL dst, regD src, rFlagsReg cr) ins_pipe(pipe_slow); %} +instruct convD2L_reg_reg_avx10(rRegL dst, regD src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2L src)); + format %{ "evcvttsd2sisq $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisq($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convD2L_reg_mem_avx10(rRegL dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2L (LoadD src))); + format %{ "evcvttsd2sisq $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisq($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + instruct round_double_reg(rRegL dst, regD src, rRegL rtmp, rcx_RegL rcx, rFlagsReg cr) %{ match(Set dst (RoundD src)); diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index dbdc66b0eb6..0c0c2808fa1 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -169,7 +169,7 @@ static void vmembk_print_on(outputStream* os); //////////////////////////////////////////////////////////////////////////////// // global variables (for a description see os_aix.hpp) -size_t os::Aix::_physical_memory = 0; +physical_memory_size_type os::Aix::_physical_memory = 0; pthread_t os::Aix::_main_thread = ((pthread_t)0); @@ -254,43 +254,43 @@ static bool is_close_to_brk(address a) { return false; } -bool os::free_memory(size_t& value) { +bool os::free_memory(physical_memory_size_type& value) { return Aix::available_memory(value); } -bool os::available_memory(size_t& value) { +bool os::available_memory(physical_memory_size_type& value) { return Aix::available_memory(value); } -bool os::Aix::available_memory(size_t& value) { +bool os::Aix::available_memory(physical_memory_size_type& value) { os::Aix::meminfo_t mi; if (os::Aix::get_meminfo(&mi)) { - value = static_cast(mi.real_free); + value = static_cast(mi.real_free); return true; } else { return false; } } -bool os::total_swap_space(size_t& value) { +bool os::total_swap_space(physical_memory_size_type& value) { perfstat_memory_total_t memory_info; if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { return false; } - value = static_cast(memory_info.pgsp_total * 4 * K); + value = static_cast(memory_info.pgsp_total * 4 * K); return true; } -bool os::free_swap_space(size_t& value) { +bool os::free_swap_space(physical_memory_size_type& value) { perfstat_memory_total_t memory_info; if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { return false; } - value = static_cast(memory_info.pgsp_free * 4 * K); + value = static_cast(memory_info.pgsp_free * 4 * K); return true; } -size_t os::physical_memory() { +physical_memory_size_type os::physical_memory() { return Aix::physical_memory(); } @@ -329,7 +329,7 @@ void os::Aix::initialize_system_info() { if (!os::Aix::get_meminfo(&mi)) { assert(false, "os::Aix::get_meminfo failed."); } - _physical_memory = static_cast(mi.real_total); + _physical_memory = static_cast(mi.real_total); } // Helper function for tracing page sizes. @@ -2192,7 +2192,7 @@ jint os::init_2(void) { os::Posix::init_2(); trcVerbose("processor count: %d", os::_processor_count); - trcVerbose("physical memory: %zu", Aix::_physical_memory); + trcVerbose("physical memory: " PHYS_MEM_TYPE_FORMAT, Aix::_physical_memory); // Initially build up the loaded dll map. LoadedLibraries::reload(); diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp index 1530f2adb76..a7bac40e79b 100644 --- a/src/hotspot/os/aix/os_aix.hpp +++ b/src/hotspot/os/aix/os_aix.hpp @@ -35,7 +35,7 @@ class os::Aix { private: - static size_t _physical_memory; + static physical_memory_size_type _physical_memory; static pthread_t _main_thread; // 0 = uninitialized, otherwise 16 bit number: @@ -54,9 +54,9 @@ class os::Aix { // 1 - EXTSHM=ON static int _extshm; - static bool available_memory(size_t& value); - static bool free_memory(size_t& value); - static size_t physical_memory() { return _physical_memory; } + static bool available_memory(physical_memory_size_type& value); + static bool free_memory(physical_memory_size_type& value); + static physical_memory_size_type physical_memory() { return _physical_memory; } static void initialize_system_info(); // OS recognitions (AIX OS level) call this before calling Aix::os_version(). diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index b03dbd48cf8..8c5bbd58a84 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -114,7 +114,7 @@ //////////////////////////////////////////////////////////////////////////////// // global variables -size_t os::Bsd::_physical_memory = 0; +physical_memory_size_type os::Bsd::_physical_memory = 0; #ifdef __APPLE__ mach_timebase_info_data_t os::Bsd::_timebase_info = {0, 0}; @@ -133,19 +133,19 @@ static volatile int processor_id_next = 0; //////////////////////////////////////////////////////////////////////////////// // utility functions -bool os::available_memory(size_t& value) { +bool os::available_memory(physical_memory_size_type& value) { return Bsd::available_memory(value); } -bool os::free_memory(size_t& value) { +bool os::free_memory(physical_memory_size_type& value) { return Bsd::available_memory(value); } // Available here means free. Note that this number is of no much use. As an estimate // for future memory pressure it is far too conservative, since MacOS will use a lot // of unused memory for caches, and return it willingly in case of needs. -bool os::Bsd::available_memory(size_t& value) { - uint64_t available = static_cast(physical_memory() >> 2); +bool os::Bsd::available_memory(physical_memory_size_type& value) { + physical_memory_size_type available = physical_memory() >> 2; #ifdef __APPLE__ mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; vm_statistics64_data_t vmstat; @@ -160,7 +160,7 @@ bool os::Bsd::available_memory(size_t& value) { return false; } #endif - value = static_cast(available); + value = available; return true; } @@ -180,35 +180,35 @@ void os::Bsd::print_uptime_info(outputStream* st) { } } -bool os::total_swap_space(size_t& value) { +bool os::total_swap_space(physical_memory_size_type& value) { #if defined(__APPLE__) struct xsw_usage vmusage; size_t size = sizeof(vmusage); if (sysctlbyname("vm.swapusage", &vmusage, &size, nullptr, 0) != 0) { return false; } - value = static_cast(vmusage.xsu_total); + value = static_cast(vmusage.xsu_total); return true; #else return false; #endif } -bool os::free_swap_space(size_t& value) { +bool os::free_swap_space(physical_memory_size_type& value) { #if defined(__APPLE__) struct xsw_usage vmusage; size_t size = sizeof(vmusage); if (sysctlbyname("vm.swapusage", &vmusage, &size, nullptr, 0) != 0) { return false; } - value = static_cast(vmusage.xsu_avail); + value = static_cast(vmusage.xsu_avail); return true; #else return false; #endif } -size_t os::physical_memory() { +physical_memory_size_type os::physical_memory() { return Bsd::physical_memory(); } @@ -286,7 +286,7 @@ void os::Bsd::initialize_system_info() { len = sizeof(mem_val); if (sysctl(mib, 2, &mem_val, &len, nullptr, 0) != -1) { assert(len == sizeof(mem_val), "unexpected data size"); - _physical_memory = static_cast(mem_val); + _physical_memory = static_cast(mem_val); } else { _physical_memory = 256 * 1024 * 1024; // fallback (XXXBSD?) } @@ -297,7 +297,7 @@ void os::Bsd::initialize_system_info() { // datasize rlimit restricts us anyway. struct rlimit limits; getrlimit(RLIMIT_DATA, &limits); - _physical_memory = MIN2(_physical_memory, static_cast(limits.rlim_cur)); + _physical_memory = MIN2(_physical_memory, static_cast(limits.rlim_cur)); } #endif } @@ -1469,12 +1469,12 @@ void os::print_memory_info(outputStream* st) { st->print("Memory:"); st->print(" %zuk page", os::vm_page_size()>>10); - size_t phys_mem = os::physical_memory(); - st->print(", physical %zuk", + physical_memory_size_type phys_mem = os::physical_memory(); + st->print(", physical " PHYS_MEM_TYPE_FORMAT "k", phys_mem >> 10); - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; (void)os::available_memory(avail_mem); - st->print("(%zuk free)", + st->print("(" PHYS_MEM_TYPE_FORMAT "k free)", avail_mem >> 10); if((sysctlbyname("vm.swapusage", &swap_usage, &size, nullptr, 0) == 0) || (errno == ENOMEM)) { diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp index 173cc5a40ad..82002917f39 100644 --- a/src/hotspot/os/bsd/os_bsd.hpp +++ b/src/hotspot/os/bsd/os_bsd.hpp @@ -42,12 +42,12 @@ class os::Bsd { protected: - static size_t _physical_memory; + static physical_memory_size_type _physical_memory; static pthread_t _main_thread; - static bool available_memory(size_t& value); - static bool free_memory(size_t& value); - static size_t physical_memory() { return _physical_memory; } + static bool available_memory(physical_memory_size_type& value); + static bool free_memory(physical_memory_size_type& value); + static physical_memory_size_type physical_memory() { return _physical_memory; } static void initialize_system_info(); static void rebuild_cpu_to_node_map(); diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index f935e2cbb9c..f5c4abeb4ca 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -665,15 +665,13 @@ int CgroupSubsystem::active_processor_count() { * -1 for unlimited * OSCONTAINER_ERROR for not supported */ -jlong CgroupSubsystem::memory_limit_in_bytes() { +jlong CgroupSubsystem::memory_limit_in_bytes(julong upper_bound) { CachingCgroupController* contrl = memory_controller(); CachedMetric* memory_limit = contrl->metrics_cache(); if (!memory_limit->should_check_metric()) { return memory_limit->value(); } - julong phys_mem = static_cast(os::Linux::physical_memory()); - log_trace(os, container)("total physical memory: " JULONG_FORMAT, phys_mem); - jlong mem_limit = contrl->controller()->read_memory_limit_in_bytes(phys_mem); + jlong mem_limit = contrl->controller()->read_memory_limit_in_bytes(upper_bound); // Update cached metric to avoid re-reading container settings too often memory_limit->set_value(mem_limit, OSCONTAINER_CACHE_TIMEOUT); return mem_limit; @@ -841,21 +839,16 @@ jlong CgroupController::limit_from_str(char* limit_str) { // CgroupSubsystem implementations -jlong CgroupSubsystem::memory_and_swap_limit_in_bytes() { - julong phys_mem = static_cast(os::Linux::physical_memory()); - julong host_swap = os::Linux::host_swap(); - return memory_controller()->controller()->memory_and_swap_limit_in_bytes(phys_mem, host_swap); +jlong CgroupSubsystem::memory_and_swap_limit_in_bytes(julong upper_mem_bound, julong upper_swap_bound) { + return memory_controller()->controller()->memory_and_swap_limit_in_bytes(upper_mem_bound, upper_swap_bound); } -jlong CgroupSubsystem::memory_and_swap_usage_in_bytes() { - julong phys_mem = static_cast(os::Linux::physical_memory()); - julong host_swap = os::Linux::host_swap(); - return memory_controller()->controller()->memory_and_swap_usage_in_bytes(phys_mem, host_swap); +jlong CgroupSubsystem::memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound) { + return memory_controller()->controller()->memory_and_swap_usage_in_bytes(upper_mem_bound, upper_swap_bound); } -jlong CgroupSubsystem::memory_soft_limit_in_bytes() { - julong phys_mem = static_cast(os::Linux::physical_memory()); - return memory_controller()->controller()->memory_soft_limit_in_bytes(phys_mem); +jlong CgroupSubsystem::memory_soft_limit_in_bytes(julong upper_bound) { + return memory_controller()->controller()->memory_soft_limit_in_bytes(upper_bound); } jlong CgroupSubsystem::memory_throttle_limit_in_bytes() { @@ -894,7 +887,6 @@ jlong CgroupSubsystem::cpu_usage_in_micros() { return cpuacct_controller()->cpu_usage_in_micros(); } -void CgroupSubsystem::print_version_specific_info(outputStream* st) { - julong phys_mem = static_cast(os::Linux::physical_memory()); - memory_controller()->controller()->print_version_specific_info(st, phys_mem); +void CgroupSubsystem::print_version_specific_info(outputStream* st, julong upper_mem_bound) { + memory_controller()->controller()->print_version_specific_info(st, upper_mem_bound); } diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index 22e57d56c93..62a61432665 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -233,14 +233,14 @@ class CgroupMemoryController: public CHeapObj { public: virtual jlong read_memory_limit_in_bytes(julong upper_bound) = 0; virtual jlong memory_usage_in_bytes() = 0; - virtual jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) = 0; - virtual jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) = 0; + virtual jlong memory_and_swap_limit_in_bytes(julong upper_mem_bound, julong upper_swap_bound) = 0; + virtual jlong memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound) = 0; virtual jlong memory_soft_limit_in_bytes(julong upper_bound) = 0; virtual jlong memory_throttle_limit_in_bytes() = 0; virtual jlong memory_max_usage_in_bytes() = 0; virtual jlong rss_usage_in_bytes() = 0; virtual jlong cache_usage_in_bytes() = 0; - virtual void print_version_specific_info(outputStream* st, julong host_mem) = 0; + virtual void print_version_specific_info(outputStream* st, julong upper_mem_bound) = 0; virtual bool needs_hierarchy_adjustment() = 0; virtual bool is_read_only() = 0; virtual const char* subsystem_path() = 0; @@ -251,7 +251,7 @@ class CgroupMemoryController: public CHeapObj { class CgroupSubsystem: public CHeapObj { public: - jlong memory_limit_in_bytes(); + jlong memory_limit_in_bytes(julong upper_bound); int active_processor_count(); virtual jlong pids_max() = 0; @@ -272,14 +272,14 @@ class CgroupSubsystem: public CHeapObj { jlong cpu_usage_in_micros(); jlong memory_usage_in_bytes(); - jlong memory_and_swap_limit_in_bytes(); - jlong memory_and_swap_usage_in_bytes(); - jlong memory_soft_limit_in_bytes(); + jlong memory_and_swap_limit_in_bytes(julong upper_mem_bound, julong upper_swap_bound); + jlong memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound); + jlong memory_soft_limit_in_bytes(julong upper_bound); jlong memory_throttle_limit_in_bytes(); jlong memory_max_usage_in_bytes(); jlong rss_usage_in_bytes(); jlong cache_usage_in_bytes(); - void print_version_specific_info(outputStream* st); + void print_version_specific_info(outputStream* st, julong upper_mem_bound); }; // Utility class for storing info retrieved from /proc/cgroups, diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index 64cb53eda28..90f01565b84 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -136,35 +136,35 @@ bool CgroupV1Controller::needs_hierarchy_adjustment() { } static inline -void verbose_log(julong read_mem_limit, julong host_mem) { +void verbose_log(julong read_mem_limit, julong upper_mem_bound) { if (log_is_enabled(Debug, os, container)) { jlong mem_limit = (jlong)read_mem_limit; // account for negative values - if (mem_limit < 0 || read_mem_limit >= host_mem) { + if (mem_limit < 0 || read_mem_limit >= upper_mem_bound) { const char *reason; if (mem_limit == OSCONTAINER_ERROR) { reason = "failed"; } else if (mem_limit == -1) { reason = "unlimited"; } else { - assert(read_mem_limit >= host_mem, "Expected read value exceeding host_mem"); + assert(read_mem_limit >= upper_mem_bound, "Expected read value exceeding upper memory bound"); // Exceeding physical memory is treated as unlimited. This implementation // caps it at host_mem since Cg v1 has no value to represent 'max'. reason = "ignored"; } - log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT, - reason, mem_limit, host_mem); + log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", upper bound is " JLONG_FORMAT, + reason, mem_limit, upper_mem_bound); } } } -jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong phys_mem) { +jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong upper_bound) { julong memlimit; CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.limit_in_bytes", "Memory Limit", memlimit); - if (memlimit >= phys_mem) { - verbose_log(memlimit, phys_mem); + if (memlimit >= upper_bound) { + verbose_log(memlimit, upper_bound); return (jlong)-1; } else { - verbose_log(memlimit, phys_mem); + verbose_log(memlimit, upper_bound); return (jlong)memlimit; } } @@ -181,10 +181,10 @@ jlong CgroupV1MemoryController::read_memory_limit_in_bytes(julong phys_mem) { * * -1 if there isn't any limit in place (note: includes values which exceed a physical * upper bound) */ -jlong CgroupV1MemoryController::read_mem_swap(julong host_total_memsw) { +jlong CgroupV1MemoryController::read_mem_swap(julong upper_memsw_bound) { julong memswlimit; CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.memsw.limit_in_bytes", "Memory and Swap Limit", memswlimit); - if (memswlimit >= host_total_memsw) { + if (memswlimit >= upper_memsw_bound) { log_trace(os, container)("Memory and Swap Limit is: Unlimited"); return (jlong)-1; } else { @@ -192,8 +192,8 @@ jlong CgroupV1MemoryController::read_mem_swap(julong host_total_memsw) { } } -jlong CgroupV1MemoryController::memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) { - jlong memory_swap = read_mem_swap(host_mem + host_swap); +jlong CgroupV1MemoryController::memory_and_swap_limit_in_bytes(julong upper_mem_bound, julong upper_swap_bound) { + jlong memory_swap = read_mem_swap(upper_mem_bound + upper_swap_bound); if (memory_swap == -1) { return memory_swap; } @@ -202,7 +202,7 @@ jlong CgroupV1MemoryController::memory_and_swap_limit_in_bytes(julong host_mem, // supported. jlong swappiness = read_mem_swappiness(); if (swappiness == 0 || memory_swap == OSCONTAINER_ERROR) { - jlong memlimit = read_memory_limit_in_bytes(host_mem); + jlong memlimit = read_memory_limit_in_bytes(upper_mem_bound); if (memory_swap == OSCONTAINER_ERROR) { log_trace(os, container)("Memory and Swap Limit has been reset to " JLONG_FORMAT " because swap is not supported", memlimit); } else { @@ -220,9 +220,9 @@ jlong memory_swap_usage_impl(CgroupController* ctrl) { return (jlong)memory_swap_usage; } -jlong CgroupV1MemoryController::memory_and_swap_usage_in_bytes(julong phys_mem, julong host_swap) { - jlong memory_sw_limit = memory_and_swap_limit_in_bytes(phys_mem, host_swap); - jlong memory_limit = read_memory_limit_in_bytes(phys_mem); +jlong CgroupV1MemoryController::memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound) { + jlong memory_sw_limit = memory_and_swap_limit_in_bytes(upper_mem_bound, upper_swap_bound); + jlong memory_limit = read_memory_limit_in_bytes(upper_mem_bound); if (memory_sw_limit > 0 && memory_limit > 0) { jlong delta_swap = memory_sw_limit - memory_limit; if (delta_swap > 0) { @@ -238,10 +238,10 @@ jlong CgroupV1MemoryController::read_mem_swappiness() { return (jlong)swappiness; } -jlong CgroupV1MemoryController::memory_soft_limit_in_bytes(julong phys_mem) { +jlong CgroupV1MemoryController::memory_soft_limit_in_bytes(julong upper_bound) { julong memsoftlimit; CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.soft_limit_in_bytes", "Memory Soft Limit", memsoftlimit); - if (memsoftlimit >= phys_mem) { + if (memsoftlimit >= upper_bound) { log_trace(os, container)("Memory Soft Limit is: Unlimited"); return (jlong)-1; } else { @@ -336,10 +336,10 @@ jlong CgroupV1MemoryController::kernel_memory_usage_in_bytes() { return (jlong)kmem_usage; } -jlong CgroupV1MemoryController::kernel_memory_limit_in_bytes(julong phys_mem) { +jlong CgroupV1MemoryController::kernel_memory_limit_in_bytes(julong upper_bound) { julong kmem_limit; CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.kmem.limit_in_bytes", "Kernel Memory Limit", kmem_limit); - if (kmem_limit >= phys_mem) { + if (kmem_limit >= upper_bound) { return (jlong)-1; } return (jlong)kmem_limit; @@ -351,9 +351,9 @@ jlong CgroupV1MemoryController::kernel_memory_max_usage_in_bytes() { return (jlong)kmem_max_usage; } -void CgroupV1MemoryController::print_version_specific_info(outputStream* st, julong phys_mem) { +void CgroupV1MemoryController::print_version_specific_info(outputStream* st, julong mem_bound) { jlong kmem_usage = kernel_memory_usage_in_bytes(); - jlong kmem_limit = kernel_memory_limit_in_bytes(phys_mem); + jlong kmem_limit = kernel_memory_limit_in_bytes(mem_bound); jlong kmem_max_usage = kernel_memory_max_usage_in_bytes(); OSContainer::print_container_helper(st, kmem_limit, "kernel_memory_limit_in_bytes"); diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index 33bf2ed6e55..02b2c6a9fce 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -79,17 +79,17 @@ class CgroupV1MemoryController final : public CgroupMemoryController { } jlong read_memory_limit_in_bytes(julong upper_bound) override; jlong memory_usage_in_bytes() override; - jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) override; - jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) override; + jlong memory_and_swap_limit_in_bytes(julong upper_mem_bound, julong upper_swap_bound) override; + jlong memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound) override; jlong memory_soft_limit_in_bytes(julong upper_bound) override; jlong memory_throttle_limit_in_bytes() override; jlong memory_max_usage_in_bytes() override; jlong rss_usage_in_bytes() override; jlong cache_usage_in_bytes() override; jlong kernel_memory_usage_in_bytes(); - jlong kernel_memory_limit_in_bytes(julong host_mem); + jlong kernel_memory_limit_in_bytes(julong upper_bound); jlong kernel_memory_max_usage_in_bytes(); - void print_version_specific_info(outputStream* st, julong host_mem) override; + void print_version_specific_info(outputStream* st, julong upper_mem_bound) override; bool needs_hierarchy_adjustment() override { return reader()->needs_hierarchy_adjustment(); } @@ -101,7 +101,7 @@ class CgroupV1MemoryController final : public CgroupMemoryController { const char* cgroup_path() override { return reader()->cgroup_path(); } private: jlong read_mem_swappiness(); - jlong read_mem_swap(julong host_total_memsw); + jlong read_mem_swap(julong upper_memsw_bound); public: CgroupV1MemoryController(const CgroupV1Controller& reader) diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index 661f7e909b5..38258a1f049 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -181,7 +181,7 @@ jlong CgroupV2MemoryController::memory_usage_in_bytes() { return (jlong)memusage; } -jlong CgroupV2MemoryController::memory_soft_limit_in_bytes(julong phys_mem) { +jlong CgroupV2MemoryController::memory_soft_limit_in_bytes(julong upper_bound) { jlong mem_soft_limit; CONTAINER_READ_NUMBER_CHECKED_MAX(reader(), "/memory.low", "Memory Soft Limit", mem_soft_limit); return mem_soft_limit; @@ -224,19 +224,19 @@ jlong CgroupV2MemoryController::cache_usage_in_bytes() { // respectively. In order to properly report a cgroup v1 like // compound value we need to sum the two values. Setting a swap limit // without also setting a memory limit is not allowed. -jlong CgroupV2MemoryController::memory_and_swap_limit_in_bytes(julong phys_mem, - julong host_swap /* unused in cg v2 */) { +jlong CgroupV2MemoryController::memory_and_swap_limit_in_bytes(julong upper_mem_bound, + julong upper_swap_bound /* unused in cg v2 */) { jlong swap_limit; bool is_ok = reader()->read_number_handle_max("/memory.swap.max", &swap_limit); if (!is_ok) { // Some container tests rely on this trace logging to happen. log_trace(os, container)("Swap Limit failed: %d", OSCONTAINER_ERROR); // swap disabled at kernel level, treat it as no swap - return read_memory_limit_in_bytes(phys_mem); + return read_memory_limit_in_bytes(upper_mem_bound); } log_trace(os, container)("Swap Limit is: " JLONG_FORMAT, swap_limit); if (swap_limit >= 0) { - jlong memory_limit = read_memory_limit_in_bytes(phys_mem); + jlong memory_limit = read_memory_limit_in_bytes(upper_mem_bound); assert(memory_limit >= 0, "swap limit without memory limit?"); return memory_limit + swap_limit; } @@ -252,7 +252,7 @@ jlong memory_swap_current_value(CgroupV2Controller* ctrl) { return (jlong)swap_current; } -jlong CgroupV2MemoryController::memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) { +jlong CgroupV2MemoryController::memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound) { jlong memory_usage = memory_usage_in_bytes(); if (memory_usage >= 0) { jlong swap_current = memory_swap_current_value(reader()); @@ -276,7 +276,7 @@ jlong memory_limit_value(CgroupV2Controller* ctrl) { * memory limit in bytes or * -1 for unlimited, OSCONTAINER_ERROR for an error */ -jlong CgroupV2MemoryController::read_memory_limit_in_bytes(julong phys_mem) { +jlong CgroupV2MemoryController::read_memory_limit_in_bytes(julong upper_bound) { jlong limit = memory_limit_value(reader()); if (log_is_enabled(Trace, os, container)) { if (limit == -1) { @@ -287,18 +287,18 @@ jlong CgroupV2MemoryController::read_memory_limit_in_bytes(julong phys_mem) { } if (log_is_enabled(Debug, os, container)) { julong read_limit = (julong)limit; // avoid signed/unsigned compare - if (limit < 0 || read_limit >= phys_mem) { + if (limit < 0 || read_limit >= upper_bound) { const char* reason; if (limit == -1) { reason = "unlimited"; } else if (limit == OSCONTAINER_ERROR) { reason = "failed"; } else { - assert(read_limit >= phys_mem, "Expected mem limit to exceed host memory"); + assert(read_limit >= upper_bound, "Expected mem limit to exceed upper memory bound"); reason = "ignored"; } - log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value " JLONG_FORMAT, - reason, limit, phys_mem); + log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", upper bound is " JLONG_FORMAT, + reason, limit, upper_bound); } } return limit; @@ -327,7 +327,7 @@ bool CgroupV2Controller::needs_hierarchy_adjustment() { return strcmp(_cgroup_path, "/") != 0; } -void CgroupV2MemoryController::print_version_specific_info(outputStream* st, julong phys_mem) { +void CgroupV2MemoryController::print_version_specific_info(outputStream* st, julong upper_mem_bound) { jlong swap_current = memory_swap_current_value(reader()); jlong swap_limit = memory_swap_limit_value(reader()); diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index e26f37925ca..07db126ce90 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -115,15 +115,15 @@ class CgroupV2MemoryController final: public CgroupMemoryController { } jlong read_memory_limit_in_bytes(julong upper_bound) override; - jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swp) override; - jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swp) override; + jlong memory_and_swap_limit_in_bytes(julong upper_mem_bound, julong upper_swap_bound) override; + jlong memory_and_swap_usage_in_bytes(julong upper_mem_bound, julong upper_swap_bound) override; jlong memory_soft_limit_in_bytes(julong upper_bound) override; jlong memory_throttle_limit_in_bytes() override; jlong memory_usage_in_bytes() override; jlong memory_max_usage_in_bytes() override; jlong rss_usage_in_bytes() override; jlong cache_usage_in_bytes() override; - void print_version_specific_info(outputStream* st, julong host_mem) override; + void print_version_specific_info(outputStream* st, julong upper_mem_bound) override; bool is_read_only() override { return reader()->is_read_only(); } diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp index 899e7535fde..561f2d4926c 100644 --- a/src/hotspot/os/linux/osContainer_linux.cpp +++ b/src/hotspot/os/linux/osContainer_linux.cpp @@ -84,8 +84,8 @@ void OSContainer::init() { // We can be in one of two cases: // 1.) On a physical Linux system without any limit // 2.) On a physical Linux system with a limit enforced by other means (like systemd slice) - any_mem_cpu_limit_present = cgroup_subsystem->memory_limit_in_bytes() > 0 || - os::Linux::active_processor_count() != cgroup_subsystem->active_processor_count(); + any_mem_cpu_limit_present = memory_limit_in_bytes() > 0 || + os::Linux::active_processor_count() != active_processor_count(); if (any_mem_cpu_limit_present) { reason = " because either a cpu or a memory limit is present"; } else { @@ -103,24 +103,47 @@ const char * OSContainer::container_type() { return cgroup_subsystem->container_type(); } +bool OSContainer::available_memory_in_container(julong& value) { + jlong mem_limit = memory_limit_in_bytes(); + jlong mem_usage = memory_usage_in_bytes(); + + if (mem_limit > 0 && mem_usage <= 0) { + log_debug(os, container)("container memory usage failed: " JLONG_FORMAT, mem_usage); + } + + if (mem_limit <= 0 || mem_usage <= 0) { + return false; + } + + value = mem_limit > mem_usage ? static_cast(mem_limit - mem_usage) : 0; + + return true; +} + jlong OSContainer::memory_limit_in_bytes() { assert(cgroup_subsystem != nullptr, "cgroup subsystem not available"); - return cgroup_subsystem->memory_limit_in_bytes(); + julong phys_mem = static_cast(os::Linux::physical_memory()); + return cgroup_subsystem->memory_limit_in_bytes(phys_mem); } jlong OSContainer::memory_and_swap_limit_in_bytes() { assert(cgroup_subsystem != nullptr, "cgroup subsystem not available"); - return cgroup_subsystem->memory_and_swap_limit_in_bytes(); + julong phys_mem = static_cast(os::Linux::physical_memory()); + julong host_swap = os::Linux::host_swap(); + return cgroup_subsystem->memory_and_swap_limit_in_bytes(phys_mem, host_swap); } jlong OSContainer::memory_and_swap_usage_in_bytes() { assert(cgroup_subsystem != nullptr, "cgroup subsystem not available"); - return cgroup_subsystem->memory_and_swap_usage_in_bytes(); + julong phys_mem = static_cast(os::Linux::physical_memory()); + julong host_swap = os::Linux::host_swap(); + return cgroup_subsystem->memory_and_swap_usage_in_bytes(phys_mem, host_swap); } jlong OSContainer::memory_soft_limit_in_bytes() { assert(cgroup_subsystem != nullptr, "cgroup subsystem not available"); - return cgroup_subsystem->memory_soft_limit_in_bytes(); + julong phys_mem = static_cast(os::Linux::physical_memory()); + return cgroup_subsystem->memory_soft_limit_in_bytes(phys_mem); } jlong OSContainer::memory_throttle_limit_in_bytes() { @@ -150,7 +173,8 @@ jlong OSContainer::cache_usage_in_bytes() { void OSContainer::print_version_specific_info(outputStream* st) { assert(cgroup_subsystem != nullptr, "cgroup subsystem not available"); - cgroup_subsystem->print_version_specific_info(st); + julong phys_mem = static_cast(os::Linux::physical_memory()); + cgroup_subsystem->print_version_specific_info(st, phys_mem); } char * OSContainer::cpu_cpuset_cpus() { diff --git a/src/hotspot/os/linux/osContainer_linux.hpp b/src/hotspot/os/linux/osContainer_linux.hpp index d9b024dbbb5..6258714c48b 100644 --- a/src/hotspot/os/linux/osContainer_linux.hpp +++ b/src/hotspot/os/linux/osContainer_linux.hpp @@ -50,6 +50,7 @@ class OSContainer: AllStatic { static inline bool is_containerized(); static const char * container_type(); + static bool available_memory_in_container(julong& value); static jlong memory_limit_in_bytes(); static jlong memory_and_swap_limit_in_bytes(); static jlong memory_and_swap_usage_in_bytes(); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 3d44d839735..772b170d11c 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -154,13 +154,12 @@ enum CoredumpFilterBit { //////////////////////////////////////////////////////////////////////////////// // global variables -size_t os::Linux::_physical_memory = 0; +physical_memory_size_type os::Linux::_physical_memory = 0; address os::Linux::_initial_thread_stack_bottom = nullptr; uintptr_t os::Linux::_initial_thread_stack_size = 0; int (*os::Linux::_pthread_getcpuclockid)(pthread_t, clockid_t *) = nullptr; -int (*os::Linux::_pthread_setname_np)(pthread_t, const char*) = nullptr; pthread_t os::Linux::_main_thread; bool os::Linux::_supports_fast_thread_cpu_time = false; const char * os::Linux::_libc_version = nullptr; @@ -214,32 +213,19 @@ static bool suppress_primordial_thread_resolution = false; // utility functions -julong os::Linux::available_memory_in_container() { - julong avail_mem = static_cast(-1L); - if (OSContainer::is_containerized()) { - jlong mem_limit = OSContainer::memory_limit_in_bytes(); - jlong mem_usage; - if (mem_limit > 0 && (mem_usage = OSContainer::memory_usage_in_bytes()) < 1) { - log_debug(os, container)("container memory usage failed: " JLONG_FORMAT ", using host value", mem_usage); - } - if (mem_limit > 0 && mem_usage > 0) { - avail_mem = mem_limit > mem_usage ? (julong)mem_limit - (julong)mem_usage : 0; - } +bool os::available_memory(physical_memory_size_type& value) { + julong avail_mem = 0; + if (OSContainer::is_containerized() && OSContainer::available_memory_in_container(avail_mem)) { + log_trace(os)("available container memory: " JULONG_FORMAT, avail_mem); + value = static_cast(avail_mem); + return true; } - return avail_mem; -} -bool os::available_memory(size_t& value) { return Linux::available_memory(value); } -bool os::Linux::available_memory(size_t& value) { - julong avail_mem = available_memory_in_container(); - if (avail_mem != static_cast(-1L)) { - log_trace(os)("available container memory: " JULONG_FORMAT, avail_mem); - value = static_cast(avail_mem); - return true; - } +bool os::Linux::available_memory(physical_memory_size_type& value) { + julong avail_mem = static_cast(-1L); FILE *fp = os::fopen("/proc/meminfo", "r"); if (fp != nullptr) { @@ -253,47 +239,48 @@ bool os::Linux::available_memory(size_t& value) { fclose(fp); } if (avail_mem == static_cast(-1L)) { - size_t free_mem = 0; + physical_memory_size_type free_mem = 0; if (!free_memory(free_mem)) { return false; } avail_mem = static_cast(free_mem); } log_trace(os)("available memory: " JULONG_FORMAT, avail_mem); - value = static_cast(avail_mem); + value = static_cast(avail_mem); return true; } -bool os::free_memory(size_t& value) { +bool os::free_memory(physical_memory_size_type& value) { + julong free_mem = 0; + if (OSContainer::is_containerized() && OSContainer::available_memory_in_container(free_mem)) { + log_trace(os)("free container memory: " JULONG_FORMAT, free_mem); + value = static_cast(free_mem); + return true; + } + return Linux::free_memory(value); } -bool os::Linux::free_memory(size_t& value) { +bool os::Linux::free_memory(physical_memory_size_type& value) { // values in struct sysinfo are "unsigned long" struct sysinfo si; - julong free_mem = available_memory_in_container(); - if (free_mem != static_cast(-1L)) { - log_trace(os)("free container memory: " JULONG_FORMAT, free_mem); - value = static_cast(free_mem); - return true; - } int ret = sysinfo(&si); if (ret != 0) { return false; } - free_mem = (julong)si.freeram * si.mem_unit; + julong free_mem = (julong)si.freeram * si.mem_unit; log_trace(os)("free memory: " JULONG_FORMAT, free_mem); - value = static_cast(free_mem); + value = static_cast(free_mem); return true; } -bool os::total_swap_space(size_t& value) { +bool os::total_swap_space(physical_memory_size_type& value) { if (OSContainer::is_containerized()) { jlong memory_and_swap_limit_in_bytes = OSContainer::memory_and_swap_limit_in_bytes(); jlong memory_limit_in_bytes = OSContainer::memory_limit_in_bytes(); if (memory_limit_in_bytes > 0 && memory_and_swap_limit_in_bytes > 0) { - value = static_cast(memory_and_swap_limit_in_bytes - memory_limit_in_bytes); + value = static_cast(memory_and_swap_limit_in_bytes - memory_limit_in_bytes); return true; } } // fallback to the host swap space if the container did return the unbound value of -1 @@ -303,30 +290,30 @@ bool os::total_swap_space(size_t& value) { assert(false, "sysinfo failed in total_swap_space(): %s", os::strerror(errno)); return false; } - value = static_cast(si.totalswap * si.mem_unit); + value = static_cast(si.totalswap) * si.mem_unit; return true; } -static bool host_free_swap_f(size_t& value) { +static bool host_free_swap_f(physical_memory_size_type& value) { struct sysinfo si; int ret = sysinfo(&si); if (ret != 0) { assert(false, "sysinfo failed in host_free_swap_f(): %s", os::strerror(errno)); return false; } - value = static_cast(si.freeswap * si.mem_unit); + value = static_cast(si.freeswap) * si.mem_unit; return true; } -bool os::free_swap_space(size_t& value) { +bool os::free_swap_space(physical_memory_size_type& value) { // os::total_swap_space() might return the containerized limit which might be // less than host_free_swap(). The upper bound of free swap needs to be the lower of the two. - size_t total_swap_space = 0; - size_t host_free_swap = 0; + physical_memory_size_type total_swap_space = 0; + physical_memory_size_type host_free_swap = 0; if (!os::total_swap_space(total_swap_space) || !host_free_swap_f(host_free_swap)) { return false; } - size_t host_free_swap_val = MIN2(total_swap_space, host_free_swap); + physical_memory_size_type host_free_swap_val = MIN2(total_swap_space, host_free_swap); if (OSContainer::is_containerized()) { jlong mem_swap_limit = OSContainer::memory_and_swap_limit_in_bytes(); jlong mem_limit = OSContainer::memory_limit_in_bytes(); @@ -342,31 +329,31 @@ bool os::free_swap_space(size_t& value) { jlong delta_usage = mem_swap_usage - mem_usage; if (delta_usage >= 0) { jlong free_swap = delta_limit - delta_usage; - value = free_swap >= 0 ? static_cast(free_swap) : 0; + value = free_swap >= 0 ? static_cast(free_swap) : 0; return true; } } } // unlimited or not supported. Fall through to return host value log_trace(os,container)("os::free_swap_space: container_swap_limit=" JLONG_FORMAT - " container_mem_limit=" JLONG_FORMAT " returning host value: %zu", + " container_mem_limit=" JLONG_FORMAT " returning host value: " PHYS_MEM_TYPE_FORMAT, mem_swap_limit, mem_limit, host_free_swap_val); } value = host_free_swap_val; return true; } -size_t os::physical_memory() { +physical_memory_size_type os::physical_memory() { if (OSContainer::is_containerized()) { jlong mem_limit; if ((mem_limit = OSContainer::memory_limit_in_bytes()) > 0) { log_trace(os)("total container memory: " JLONG_FORMAT, mem_limit); - return static_cast(mem_limit); + return static_cast(mem_limit); } } - size_t phys_mem = Linux::physical_memory(); - log_trace(os)("total system memory: %zu", phys_mem); + physical_memory_size_type phys_mem = Linux::physical_memory(); + log_trace(os)("total system memory: " PHYS_MEM_TYPE_FORMAT, phys_mem); return phys_mem; } @@ -550,7 +537,7 @@ void os::Linux::initialize_system_info() { fclose(fp); } } - _physical_memory = static_cast(sysconf(_SC_PHYS_PAGES)) * static_cast(sysconf(_SC_PAGESIZE)); + _physical_memory = static_cast(sysconf(_SC_PHYS_PAGES)) * static_cast(sysconf(_SC_PAGESIZE)); assert(processor_count() > 0, "linux error"); } @@ -860,11 +847,9 @@ static void *thread_native_entry(Thread *thread) { osthread->set_thread_id(checked_cast(os::current_thread_id())); if (UseNUMA) { - int lgrp_id = os::numa_get_group_id(); - if (lgrp_id != -1) { - thread->set_lgrp_id(lgrp_id); - } + thread->update_lgrp_id(); } + // initialize signal mask for this thread PosixSignals::hotspot_sigmask(thread); @@ -1191,10 +1176,7 @@ bool os::create_attached_thread(JavaThread* thread) { thread->set_osthread(osthread); if (UseNUMA) { - int lgrp_id = os::numa_get_group_id(); - if (lgrp_id != -1) { - thread->set_lgrp_id(lgrp_id); - } + thread->update_lgrp_id(); } if (os::is_primordial_thread()) { @@ -2609,12 +2591,12 @@ void os::print_memory_info(outputStream* st) { // values in struct sysinfo are "unsigned long" struct sysinfo si; sysinfo(&si); - size_t phys_mem = physical_memory(); - st->print(", physical %zuk", + physical_memory_size_type phys_mem = physical_memory(); + st->print(", physical " PHYS_MEM_TYPE_FORMAT "k", phys_mem >> 10); - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; (void)os::available_memory(avail_mem); - st->print("(%zuk free)", + st->print("(" PHYS_MEM_TYPE_FORMAT "k free)", avail_mem >> 10); st->print(", swap " UINT64_FORMAT "k", ((jlong)si.totalswap * si.mem_unit) >> 10); @@ -4376,10 +4358,6 @@ void os::init(void) { // _main_thread points to the thread that created/loaded the JVM. Linux::_main_thread = pthread_self(); - // retrieve entry point for pthread_setname_np - Linux::_pthread_setname_np = - (int(*)(pthread_t, const char*))dlsym(RTLD_DEFAULT, "pthread_setname_np"); - check_pax(); // Check the availability of MADV_POPULATE_WRITE. @@ -4856,14 +4834,24 @@ uint os::processor_id() { } void os::set_native_thread_name(const char *name) { - if (Linux::_pthread_setname_np) { - char buf [16]; // according to glibc manpage, 16 chars incl. '/0' - (void) os::snprintf(buf, sizeof(buf), "%s", name); - buf[sizeof(buf) - 1] = '\0'; - const int rc = Linux::_pthread_setname_np(pthread_self(), buf); - // ERANGE should not happen; all other errors should just be ignored. - assert(rc != ERANGE, "pthread_setname_np failed"); - } + char buf[16]; // according to glibc manpage, 16 chars incl. '/0' + // We may need to truncate the thread name. Since a common pattern + // for thread names is to be both longer than 15 chars and have a + // trailing number ("DispatcherWorkerThread21", "C2 CompilerThread#54" etc), + // we preserve the end of the thread name by truncating the middle + // (e.g. "Dispatc..read21"). + const size_t len = strlen(name); + if (len < sizeof(buf)) { + strcpy(buf, name); + } else { + (void) os::snprintf(buf, sizeof(buf), "%.7s..%.6s", name, name + len - 6); + } + // Note: we use the system call here instead of calling pthread_setname_np + // since this is the only way to make ASAN aware of our thread names. Even + // though ASAN intercepts both prctl and pthread_setname_np, it only processes + // the thread name given to the former. + int rc = prctl(PR_SET_NAME, buf); + assert(rc == 0, "prctl(PR_SET_NAME) failed"); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index 497d383200d..b77cd9f3c81 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -33,7 +33,6 @@ class os::Linux { friend class os; static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *); - static int (*_pthread_setname_np)(pthread_t, const char*); static address _initial_thread_stack_bottom; static uintptr_t _initial_thread_stack_size; @@ -50,11 +49,11 @@ class os::Linux { protected: - static size_t _physical_memory; + static physical_memory_size_type _physical_memory; static pthread_t _main_thread; - static bool available_memory(size_t& value); - static bool free_memory(size_t& value); + static bool available_memory(physical_memory_size_type& value); + static bool free_memory(physical_memory_size_type& value); static void initialize_system_info(); @@ -117,7 +116,7 @@ class os::Linux { static address initial_thread_stack_bottom(void) { return _initial_thread_stack_bottom; } static uintptr_t initial_thread_stack_size(void) { return _initial_thread_stack_size; } - static size_t physical_memory() { return _physical_memory; } + static physical_memory_size_type physical_memory() { return _physical_memory; } static julong host_swap(); static intptr_t* ucontext_get_sp(const ucontext_t* uc); diff --git a/src/hotspot/os/posix/os_posix.inline.hpp b/src/hotspot/os/posix/os_posix.inline.hpp index 67be82e4d63..f1ec9411f2a 100644 --- a/src/hotspot/os/posix/os_posix.inline.hpp +++ b/src/hotspot/os/posix/os_posix.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,9 +34,6 @@ #include #include -// Aix does not have NUMA support but need these for compilation. -inline bool os::numa_has_group_homing() { AIX_ONLY(ShouldNotReachHere();) return false; } - // Platform Mutex/Monitor implementation inline void PlatformMutex::lock() { diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 886bd453415..714eac12d22 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -621,9 +621,7 @@ int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info, if (cb != nullptr && cb->is_nmethod()) { nmethod* nm = cb->as_nmethod(); assert(nm->insts_contains_inclusive(pc), ""); - address deopt = nm->is_method_handle_return(pc) ? - nm->deopt_mh_handler_begin() : - nm->deopt_handler_begin(); + address deopt = nm->deopt_handler_begin(); assert(deopt != nullptr, ""); frame fr = os::fetch_frame_from_context(uc); diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 8d4c93f3080..c9ef08e3510 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -534,13 +534,6 @@ static unsigned thread_native_entry(void* t) { OSThread* osthr = thread->osthread(); assert(osthr->get_state() == RUNNABLE, "invalid os thread state"); - if (UseNUMA) { - int lgrp_id = os::numa_get_group_id(); - if (lgrp_id != -1) { - thread->set_lgrp_id(lgrp_id); - } - } - // Diagnostic code to investigate JDK-6573254 int res = 30115; // non-java thread if (thread->is_Java_thread()) { @@ -598,13 +591,6 @@ static OSThread* create_os_thread(Thread* thread, HANDLE thread_handle, osthread->set_thread_handle(thread_handle); osthread->set_thread_id(thread_id); - if (UseNUMA) { - int lgrp_id = os::numa_get_group_id(); - if (lgrp_id != -1) { - thread->set_lgrp_id(lgrp_id); - } - } - // Initial thread state is INITIALIZED, not SUSPENDED osthread->set_state(INITIALIZED); @@ -848,22 +834,22 @@ jlong os::elapsed_frequency() { } -bool os::available_memory(size_t& value) { +bool os::available_memory(physical_memory_size_type& value) { return win32::available_memory(value); } -bool os::free_memory(size_t& value) { +bool os::free_memory(physical_memory_size_type& value) { return win32::available_memory(value); } -bool os::win32::available_memory(size_t& value) { +bool os::win32::available_memory(physical_memory_size_type& value) { // Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect // value if total memory is larger than 4GB MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); BOOL res = GlobalMemoryStatusEx(&ms); if (res == TRUE) { - value = static_cast(ms.ullAvailPhys); + value = static_cast(ms.ullAvailPhys); return true; } else { assert(false, "GlobalMemoryStatusEx failed in os::win32::available_memory(): %lu", ::GetLastError()); @@ -871,12 +857,12 @@ bool os::win32::available_memory(size_t& value) { } } -bool os::total_swap_space(size_t& value) { +bool os::total_swap_space(physical_memory_size_type& value) { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); BOOL res = GlobalMemoryStatusEx(&ms); if (res == TRUE) { - value = static_cast(ms.ullTotalPageFile); + value = static_cast(ms.ullTotalPageFile); return true; } else { assert(false, "GlobalMemoryStatusEx failed in os::total_swap_space(): %lu", ::GetLastError()); @@ -884,12 +870,12 @@ bool os::total_swap_space(size_t& value) { } } -bool os::free_swap_space(size_t& value) { +bool os::free_swap_space(physical_memory_size_type& value) { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); BOOL res = GlobalMemoryStatusEx(&ms); if (res == TRUE) { - value = static_cast(ms.ullAvailPageFile); + value = static_cast(ms.ullAvailPageFile); return true; } else { assert(false, "GlobalMemoryStatusEx failed in os::free_swap_space(): %lu", ::GetLastError()); @@ -897,7 +883,7 @@ bool os::free_swap_space(size_t& value) { } } -size_t os::physical_memory() { +physical_memory_size_type os::physical_memory() { return win32::physical_memory(); } @@ -2811,9 +2797,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { if (cb != nullptr && cb->is_nmethod()) { nmethod* nm = cb->as_nmethod(); frame fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord); - address deopt = nm->is_method_handle_return(pc) ? - nm->deopt_mh_handler_begin() : - nm->deopt_handler_begin(); + address deopt = nm->deopt_handler_begin(); assert(nm->insts_contains_inclusive(pc), ""); nm->set_original_pc(&fr, pc); // Set pc to handler @@ -3961,25 +3945,25 @@ int os::current_process_id() { return (_initial_pid ? _initial_pid : _getpid()); } -int os::win32::_processor_type = 0; +int os::win32::_processor_type = 0; // Processor level is not available on non-NT systems, use vm_version instead -int os::win32::_processor_level = 0; -size_t os::win32::_physical_memory = 0; +int os::win32::_processor_level = 0; +physical_memory_size_type os::win32::_physical_memory = 0; -bool os::win32::_is_windows_server = false; +bool os::win32::_is_windows_server = false; // 6573254 // Currently, the bug is observed across all the supported Windows releases, // including the latest one (as of this writing - Windows Server 2012 R2) -bool os::win32::_has_exit_bug = true; +bool os::win32::_has_exit_bug = true; -int os::win32::_major_version = 0; -int os::win32::_minor_version = 0; -int os::win32::_build_number = 0; -int os::win32::_build_minor = 0; +int os::win32::_major_version = 0; +int os::win32::_minor_version = 0; +int os::win32::_build_number = 0; +int os::win32::_build_minor = 0; -bool os::win32::_processor_group_warning_displayed = false; -bool os::win32::_job_object_processor_group_warning_displayed = false; +bool os::win32::_processor_group_warning_displayed = false; +bool os::win32::_job_object_processor_group_warning_displayed = false; void getWindowsInstallationType(char* buffer, int bufferSize) { HKEY hKey; @@ -4198,7 +4182,7 @@ void os::win32::initialize_system_info() { if (res != TRUE) { assert(false, "GlobalMemoryStatusEx failed in os::win32::initialize_system_info(): %lu", ::GetLastError()); } - _physical_memory = static_cast(ms.ullTotalPhys); + _physical_memory = static_cast(ms.ullTotalPhys); if (FLAG_IS_DEFAULT(MaxRAM)) { // Adjust MaxRAM according to the maximum virtual address space available. diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp index 1426dc8be93..efb7b414989 100644 --- a/src/hotspot/os/windows/os_windows.hpp +++ b/src/hotspot/os/windows/os_windows.hpp @@ -38,18 +38,18 @@ class os::win32 { friend class os; protected: - static int _processor_type; - static int _processor_level; - static size_t _physical_memory; - static bool _is_windows_server; - static bool _has_exit_bug; - static bool _processor_group_warning_displayed; - static bool _job_object_processor_group_warning_displayed; - - static int _major_version; - static int _minor_version; - static int _build_number; - static int _build_minor; + static int _processor_type; + static int _processor_level; + static physical_memory_size_type _physical_memory; + static bool _is_windows_server; + static bool _has_exit_bug; + static bool _processor_group_warning_displayed; + static bool _job_object_processor_group_warning_displayed; + + static int _major_version; + static int _minor_version; + static int _build_number; + static int _build_minor; static void print_windows_version(outputStream* st); static void print_uptime_info(outputStream* st); @@ -102,9 +102,9 @@ class os::win32 { static int processor_level() { return _processor_level; } - static bool available_memory(size_t& value); - static bool free_memory(size_t& value); - static size_t physical_memory() { return _physical_memory; } + static bool available_memory(physical_memory_size_type& value); + static bool free_memory(physical_memory_size_type& value); + static physical_memory_size_type physical_memory() { return _physical_memory; } // load dll from Windows system directory or Windows directory static HINSTANCE load_Windows_dll(const char* name, char *ebuf, int ebuflen); diff --git a/src/hotspot/os/windows/os_windows.inline.hpp b/src/hotspot/os/windows/os_windows.inline.hpp index 41471224b6c..9eebbee2d8b 100644 --- a/src/hotspot/os/windows/os_windows.inline.hpp +++ b/src/hotspot/os/windows/os_windows.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,8 +62,6 @@ inline void os::map_stack_shadow_pages(address sp) { state->set_shadow_zone_growth_watermark(original_sp); } -inline bool os::numa_has_group_homing() { return false; } - // Platform Mutex/Monitor implementation inline void PlatformMutex::lock() { diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index 3e5fb4610de..a95bfb4ff96 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -89,7 +89,24 @@ #define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) #define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) -#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 +#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 + +#define RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS 7 + +#define RISCV_HWPROBE_KEY_TIME_CSR_FREQ 8 + +#define RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF 9 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED 1 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED 4 + +#define RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF 10 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED 4 #ifndef NR_riscv_hwprobe #ifndef NR_arch_specific_syscall @@ -117,7 +134,11 @@ static struct riscv_hwprobe query[] = {{RISCV_HWPROBE_KEY_MVENDORID, 0}, {RISCV_HWPROBE_KEY_BASE_BEHAVIOR, 0}, {RISCV_HWPROBE_KEY_IMA_EXT_0, 0}, {RISCV_HWPROBE_KEY_CPUPERF_0, 0}, - {RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE, 0}}; + {RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE, 0}, + {RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS, 0}, + {RISCV_HWPROBE_KEY_TIME_CSR_FREQ, 0}, + {RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF, 0}, + {RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF, 0}}; bool RiscvHwprobe::probe_features() { assert(!rw_hwprobe_completed, "Called twice."); @@ -246,9 +267,20 @@ void RiscvHwprobe::add_features_from_query_result() { VM_Version::ext_Zicond.enable_feature(); } #endif + // RISCV_HWPROBE_KEY_CPUPERF_0 is deprecated and returns similar values + // to RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF. Keep it there for backward + // compatibility with old kernels. if (is_valid(RISCV_HWPROBE_KEY_CPUPERF_0)) { - VM_Version::unaligned_access.enable_feature( + VM_Version::unaligned_scalar.enable_feature( query[RISCV_HWPROBE_KEY_CPUPERF_0].value & RISCV_HWPROBE_MISALIGNED_MASK); + } else if (is_valid(RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF)) { + VM_Version::unaligned_scalar.enable_feature( + query[RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF].value); + } + + if (is_valid(RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF)) { + VM_Version::unaligned_vector.enable_feature( + query[RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF].value); } if (is_valid(RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE)) { VM_Version::zicboz_block_size.enable_feature(query[RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE].value); diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index cf9429b6bea..67d405f0656 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -100,7 +100,6 @@ #endif uint32_t VM_Version::cpu_vector_length() { - assert(ext_V.enabled(), "should not call this"); return (uint32_t)read_csr(CSR_VLENB); } @@ -303,7 +302,7 @@ void VM_Version::rivos_features() { ext_Zvfh.enable_feature(); - unaligned_access.enable_feature(MISALIGNED_FAST); + unaligned_scalar.enable_feature(MISALIGNED_SCALAR_FAST); satp_mode.enable_feature(VM_SV48); // Features dependent on march/mimpid. diff --git a/src/hotspot/share/adlc/output_h.cpp b/src/hotspot/share/adlc/output_h.cpp index 8a5ad72137a..6cb82f4df7f 100644 --- a/src/hotspot/share/adlc/output_h.cpp +++ b/src/hotspot/share/adlc/output_h.cpp @@ -759,20 +759,15 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { if (_pipeline->_maxcycleused <= 32) { fprintf(fp_hpp, "protected:\n"); - fprintf(fp_hpp, " %s _mask;\n\n", _pipeline->_maxcycleused <= 32 ? "uint" : "uint64_t" ); + fprintf(fp_hpp, " uint32_t _mask;\n\n"); fprintf(fp_hpp, "public:\n"); fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask() : _mask(0) {}\n\n"); - if (_pipeline->_maxcycleused <= 32) - fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint mask) : _mask(mask) {}\n\n"); - else { - fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint mask1, uint mask2) : _mask((((uint64_t)mask1) << 32) | mask2) {}\n\n"); - fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint64_t mask) : _mask(mask) {}\n\n"); - } + fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint32_t mask) : _mask(mask) {}\n\n"); fprintf(fp_hpp, " bool overlaps(const Pipeline_Use_Cycle_Mask &in2) const {\n"); fprintf(fp_hpp, " return ((_mask & in2._mask) != 0);\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask& operator<<=(int n) {\n"); - fprintf(fp_hpp, " _mask <<= n;\n"); + fprintf(fp_hpp, " _mask <<= (n < 32) ? n : 31;\n"); fprintf(fp_hpp, " return *this;\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " void Or(const Pipeline_Use_Cycle_Mask &in2) {\n"); @@ -785,7 +780,7 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, "protected:\n"); uint masklen = (_pipeline->_maxcycleused + 31) >> 5; uint l; - fprintf(fp_hpp, " uint "); + fprintf(fp_hpp, " uint32_t "); for (l = 1; l <= masklen; l++) fprintf(fp_hpp, "_mask%d%s", l, l < masklen ? ", " : ";\n\n"); fprintf(fp_hpp, "public:\n"); @@ -794,7 +789,7 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, "_mask%d(0)%s", l, l < masklen ? ", " : " {}\n\n"); fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask("); for (l = 1; l <= masklen; l++) - fprintf(fp_hpp, "uint mask%d%s", l, l < masklen ? ", " : ") : "); + fprintf(fp_hpp, "uint32_t mask%d%s", l, l < masklen ? ", " : ") : "); for (l = 1; l <= masklen; l++) fprintf(fp_hpp, "_mask%d(mask%d)%s", l, l, l < masklen ? ", " : " {}\n\n"); @@ -805,10 +800,10 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " return out;\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " bool overlaps(const Pipeline_Use_Cycle_Mask &in2) const {\n"); - fprintf(fp_hpp, " return ("); + fprintf(fp_hpp, " return "); for (l = 1; l <= masklen; l++) fprintf(fp_hpp, "((_mask%d & in2._mask%d) != 0)%s", l, l, l < masklen ? " || " : ""); - fprintf(fp_hpp, ") ? true : false;\n"); + fprintf(fp_hpp, ";\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask& operator<<=(int n) {\n"); fprintf(fp_hpp, " if (n >= 32)\n"); @@ -819,10 +814,10 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " } while ((n -= 32) >= 32);\n\n"); fprintf(fp_hpp, " if (n > 0) {\n"); fprintf(fp_hpp, " uint m = 32 - n;\n"); - fprintf(fp_hpp, " uint mask = (1 << n) - 1;\n"); - fprintf(fp_hpp, " uint temp%d = mask & (_mask%d >> m); _mask%d <<= n;\n", 2, 1, 1); + fprintf(fp_hpp, " uint32_t mask = (1 << n) - 1;\n"); + fprintf(fp_hpp, " uint32_t temp%d = mask & (_mask%d >> m); _mask%d <<= n;\n", 2, 1, 1); for (l = 2; l < masklen; l++) { - fprintf(fp_hpp, " uint temp%d = mask & (_mask%d >> m); _mask%d <<= n; _mask%d |= temp%d;\n", l+1, l, l, l, l); + fprintf(fp_hpp, " uint32_t temp%d = mask & (_mask%d >> m); _mask%d <<= n; _mask%d |= temp%d;\n", l+1, l, l, l, l); } fprintf(fp_hpp, " _mask%d <<= n; _mask%d |= temp%d;\n", masklen, masklen, masklen); fprintf(fp_hpp, " }\n"); @@ -872,8 +867,7 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " void step(uint cycles) {\n"); fprintf(fp_hpp, " _used = 0;\n"); - fprintf(fp_hpp, " uint max_shift = 8 * sizeof(_mask) - 1;\n"); - fprintf(fp_hpp, " _mask <<= (cycles < max_shift) ? cycles : max_shift;\n"); + fprintf(fp_hpp, " _mask <<= cycles;\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " friend class Pipeline_Use;\n"); fprintf(fp_hpp, "};\n\n"); diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 35bbd2f657f..430d4949467 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -57,7 +57,6 @@ class CodeOffsets: public StackObj { OSR_Entry, Exceptions, // Offset where exception handler lives Deopt, // Offset where deopt handler lives - DeoptMH, // Offset where MethodHandle deopt handler lives UnwindHandler, // Offset to default unwind handler max_Entries }; @@ -77,7 +76,6 @@ class CodeOffsets: public StackObj { _values[OSR_Entry ] = 0; _values[Exceptions ] = -1; _values[Deopt ] = -1; - _values[DeoptMH ] = -1; _values[UnwindHandler ] = -1; } diff --git a/src/hotspot/share/c1/c1_CodeStubs.hpp b/src/hotspot/share/c1/c1_CodeStubs.hpp index 5d1c51bdbbf..a02368487c5 100644 --- a/src/hotspot/share/c1/c1_CodeStubs.hpp +++ b/src/hotspot/share/c1/c1_CodeStubs.hpp @@ -371,21 +371,16 @@ class MonitorEnterStub: public MonitorAccessStub { class MonitorExitStub: public MonitorAccessStub { private: - bool _compute_lock; int _monitor_ix; public: - MonitorExitStub(LIR_Opr lock_reg, bool compute_lock, int monitor_ix) + MonitorExitStub(LIR_Opr lock_reg, int monitor_ix) : MonitorAccessStub(LIR_OprFact::illegalOpr, lock_reg), - _compute_lock(compute_lock), _monitor_ix(monitor_ix) { } + _monitor_ix(monitor_ix) { } virtual void emit_code(LIR_Assembler* e); virtual void visit(LIR_OpVisitState* visitor) { assert(_obj_reg->is_illegal(), "unused"); - if (_compute_lock) { - visitor->do_temp(_lock_reg); - } else { - visitor->do_input(_lock_reg); - } + visitor->do_temp(_lock_reg); } #ifndef PRODUCT virtual void print_name(outputStream* out) const { out->print("MonitorExitStub"); } diff --git a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp index bb5ceb0106b..368cf604eeb 100644 --- a/src/hotspot/share/c1/c1_Compilation.cpp +++ b/src/hotspot/share/c1/c1_Compilation.cpp @@ -310,14 +310,6 @@ void Compilation::emit_code_epilog(LIR_Assembler* assembler) { code_offsets->set_value(CodeOffsets::Deopt, assembler->emit_deopt_handler()); CHECK_BAILOUT(); - // Emit the MethodHandle deopt handler code (if required). - if (has_method_handle_invokes()) { - // We can use the same code as for the normal deopt handler, we - // just need a different entry point address. - code_offsets->set_value(CodeOffsets::DeoptMH, assembler->emit_deopt_handler()); - CHECK_BAILOUT(); - } - // Emit the handler to remove the activation from the stack and // dispatch to the caller. offsets()->set_value(CodeOffsets::UnwindHandler, assembler->emit_unwind_handler()); @@ -574,7 +566,6 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho , _has_unsafe_access(false) , _has_irreducible_loops(false) , _would_profile(false) -, _has_method_handle_invokes(false) , _has_reserved_stack_access(method->has_reserved_stack_access()) , _has_monitors(method->is_synchronized() || method->has_monitor_bytecodes()) , _has_scoped_access(method->is_scoped()) diff --git a/src/hotspot/share/c1/c1_Compilation.hpp b/src/hotspot/share/c1/c1_Compilation.hpp index 0c6b95e66c5..5125e0bbe0a 100644 --- a/src/hotspot/share/c1/c1_Compilation.hpp +++ b/src/hotspot/share/c1/c1_Compilation.hpp @@ -79,7 +79,6 @@ class Compilation: public StackObj { bool _has_unsafe_access; bool _has_irreducible_loops; bool _would_profile; - bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. bool _has_reserved_stack_access; bool _has_monitors; // Fastpath monitors detection for Continuations bool _has_scoped_access; // For shared scope closure @@ -180,10 +179,6 @@ class Compilation: public StackObj { // Statistics gathering void notice_inlined_method(ciMethod* method); - // JSR 292 - bool has_method_handle_invokes() const { return _has_method_handle_invokes; } - void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } - bool has_reserved_stack_access() const { return _has_reserved_stack_access; } void set_has_reserved_stack_access(bool z) { _has_reserved_stack_access = z; } diff --git a/src/hotspot/share/c1/c1_FrameMap.hpp b/src/hotspot/share/c1/c1_FrameMap.hpp index f10c4d3f226..67ae92e9875 100644 --- a/src/hotspot/share/c1/c1_FrameMap.hpp +++ b/src/hotspot/share/c1/c1_FrameMap.hpp @@ -155,9 +155,6 @@ class FrameMap : public CompilationResourceObj { // Opr representing the stack_pointer on this platform static LIR_Opr stack_pointer(); - // JSR 292 - static LIR_Opr method_handle_invoke_SP_save_opr(); - static BasicTypeArray* signature_type_array_for(const ciMethod* method); // for outgoing calls, these also update the reserved area to diff --git a/src/hotspot/share/c1/c1_IR.cpp b/src/hotspot/share/c1/c1_IR.cpp index ae8332116b3..238a9bdda0d 100644 --- a/src/hotspot/share/c1/c1_IR.cpp +++ b/src/hotspot/share/c1/c1_IR.cpp @@ -190,7 +190,6 @@ CodeEmitInfo::CodeEmitInfo(ValueStack* stack, XHandlers* exception_handlers, boo , _exception_handlers(exception_handlers) , _oop_map(nullptr) , _stack(stack) - , _is_method_handle_invoke(false) , _deoptimize_on_exception(deoptimize_on_exception) , _force_reexecute(false) { assert(_stack != nullptr, "must be non null"); @@ -203,7 +202,6 @@ CodeEmitInfo::CodeEmitInfo(CodeEmitInfo* info, ValueStack* stack) , _exception_handlers(nullptr) , _oop_map(nullptr) , _stack(stack == nullptr ? info->_stack : stack) - , _is_method_handle_invoke(info->_is_method_handle_invoke) , _deoptimize_on_exception(info->_deoptimize_on_exception) , _force_reexecute(info->_force_reexecute) { @@ -218,7 +216,7 @@ void CodeEmitInfo::record_debug_info(DebugInformationRecorder* recorder, int pc_ // record the safepoint before recording the debug info for enclosing scopes recorder->add_safepoint(pc_offset, _oop_map->deep_copy()); bool reexecute = _force_reexecute || _scope_debug_info->should_reexecute(); - _scope_debug_info->record_debug_info(recorder, pc_offset, reexecute, _is_method_handle_invoke); + _scope_debug_info->record_debug_info(recorder, pc_offset, reexecute); recorder->end_safepoint(pc_offset); } diff --git a/src/hotspot/share/c1/c1_IR.hpp b/src/hotspot/share/c1/c1_IR.hpp index a9a7a026390..d6a4cddb9d7 100644 --- a/src/hotspot/share/c1/c1_IR.hpp +++ b/src/hotspot/share/c1/c1_IR.hpp @@ -234,7 +234,7 @@ class IRScopeDebugInfo: public CompilationResourceObj { //Whether we should reexecute this bytecode for deopt bool should_reexecute(); - void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool reexecute, bool is_method_handle_invoke = false) { + void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool reexecute) { if (caller() != nullptr) { // Order is significant: Must record caller first. caller()->record_debug_info(recorder, pc_offset, false/*reexecute*/); @@ -248,7 +248,7 @@ class IRScopeDebugInfo: public CompilationResourceObj { bool has_ea_local_in_scope = false; bool arg_escape = false; recorder->describe_scope(pc_offset, methodHandle(), scope()->method(), bci(), - reexecute, rethrow_exception, is_method_handle_invoke, return_oop, + reexecute, rethrow_exception, return_oop, has_ea_local_in_scope, arg_escape, locvals, expvals, monvals); } }; @@ -262,7 +262,6 @@ class CodeEmitInfo: public CompilationResourceObj { XHandlers* _exception_handlers; OopMap* _oop_map; ValueStack* _stack; // used by deoptimization (contains also monitors - bool _is_method_handle_invoke; // true if the associated call site is a MethodHandle call site. bool _deoptimize_on_exception; bool _force_reexecute; // force the reexecute flag on, used for patching stub @@ -288,9 +287,6 @@ class CodeEmitInfo: public CompilationResourceObj { void add_register_oop(LIR_Opr opr); void record_debug_info(DebugInformationRecorder* recorder, int pc_offset); - bool is_method_handle_invoke() const { return _is_method_handle_invoke; } - void set_is_method_handle_invoke(bool x) { _is_method_handle_invoke = x; } - bool force_reexecute() const { return _force_reexecute; } void set_force_reexecute() { _force_reexecute = true; } diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp index f11e178bd55..012c0f92f25 100644 --- a/src/hotspot/share/c1/c1_LIR.cpp +++ b/src/hotspot/share/c1/c1_LIR.cpp @@ -709,11 +709,6 @@ void LIR_OpVisitState::visit(LIR_Op* op) { } if (opJavaCall->_info) do_info(opJavaCall->_info); - if (FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr && - opJavaCall->is_method_handle_invoke()) { - opJavaCall->_method_handle_invoke_SP_save_opr = FrameMap::method_handle_invoke_SP_save_opr(); - do_temp(opJavaCall->_method_handle_invoke_SP_save_opr); - } do_call(); if (opJavaCall->_result->is_valid()) do_output(opJavaCall->_result); diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp index 0427c868e6f..847184731ce 100644 --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -1176,7 +1176,6 @@ class LIR_OpJavaCall: public LIR_OpCall { private: ciMethod* _method; LIR_Opr _receiver; - LIR_Opr _method_handle_invoke_SP_save_opr; // Used in LIR_OpVisitState::visit to store the reference to FrameMap::method_handle_invoke_SP_save_opr. public: LIR_OpJavaCall(LIR_Code code, ciMethod* method, @@ -1186,7 +1185,6 @@ class LIR_OpJavaCall: public LIR_OpCall { : LIR_OpCall(code, addr, result, arguments, info) , _method(method) , _receiver(receiver) - , _method_handle_invoke_SP_save_opr(LIR_OprFact::illegalOpr) { assert(is_in_range(code, begin_opJavaCall, end_opJavaCall), "code check"); } LIR_OpJavaCall(LIR_Code code, ciMethod* method, @@ -1195,7 +1193,6 @@ class LIR_OpJavaCall: public LIR_OpCall { : LIR_OpCall(code, (address)vtable_offset, result, arguments, info) , _method(method) , _receiver(receiver) - , _method_handle_invoke_SP_save_opr(LIR_OprFact::illegalOpr) { assert(is_in_range(code, begin_opJavaCall, end_opJavaCall), "code check"); } LIR_Opr receiver() const { return _receiver; } diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp index 6dbd35f054f..e6963c00c6a 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.cpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp @@ -478,12 +478,6 @@ void LIR_Assembler::emit_call(LIR_OpJavaCall* op) { fatal("unexpected op code: %s", op->name()); break; } - - // JSR 292 - // Record if this method has MethodHandle invokes. - if (op->is_method_handle_invoke()) { - compilation()->set_has_method_handle_invokes(true); - } } diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index b30667dcac3..f6807abcd7a 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -635,7 +635,7 @@ void LIRGenerator::monitor_exit(LIR_Opr object, LIR_Opr lock, LIR_Opr new_hdr, L // setup registers LIR_Opr hdr = lock; lock = new_hdr; - CodeStub* slow_path = new MonitorExitStub(lock, true, monitor_no); + CodeStub* slow_path = new MonitorExitStub(lock, monitor_no); __ load_stack_address_monitor(monitor_no, lock); __ unlock_object(hdr, object, lock, scratch, slow_path); } @@ -2712,19 +2712,7 @@ void LIRGenerator::do_Invoke(Invoke* x) { // emit invoke code assert(receiver->is_illegal() || receiver->is_equal(LIR_Assembler::receiverOpr()), "must match"); - // JSR 292 - // Preserve the SP over MethodHandle call sites, if needed. ciMethod* target = x->target(); - bool is_method_handle_invoke = (// %%% FIXME: Are both of these relevant? - target->is_method_handle_intrinsic() || - target->is_compiled_lambda_form()); - if (is_method_handle_invoke) { - info->set_is_method_handle_invoke(true); - if(FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr) { - __ move(FrameMap::stack_pointer(), FrameMap::method_handle_invoke_SP_save_opr()); - } - } - switch (x->code()) { case Bytecodes::_invokestatic: __ call_static(target, result_register, @@ -2757,13 +2745,6 @@ void LIRGenerator::do_Invoke(Invoke* x) { break; } - // JSR 292 - // Restore the SP after MethodHandle call sites, if needed. - if (is_method_handle_invoke - && FrameMap::method_handle_invoke_SP_save_opr() != LIR_OprFact::illegalOpr) { - __ move(FrameMap::method_handle_invoke_SP_save_opr(), FrameMap::stack_pointer()); - } - if (result_register->is_valid()) { LIR_Opr result = rlock_result(x); __ move(result_register, result); diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 637c7c46ef4..a4c956ff5be 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -541,9 +541,6 @@ extern void vm_exit(int code); // unpack_with_exception entry instead. This makes life for the exception blob easier // because making that same check and diverting is painful from assembly language. JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* current, oopDesc* ex, address pc, nmethod*& nm)) - // Reset method handle flag. - current->set_is_method_handle_return(false); - Handle exception(current, ex); // This function is called when we are about to throw an exception. Therefore, @@ -622,8 +619,6 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c if (guard_pages_enabled) { address fast_continuation = nm->handler_for_exception_and_pc(exception, pc); if (fast_continuation != nullptr) { - // Set flag if return address is a method handle call site. - current->set_is_method_handle_return(nm->is_method_handle_return(pc)); return fast_continuation; } } @@ -660,8 +655,6 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c } current->set_vm_result_oop(exception()); - // Set flag if return address is a method handle call site. - current->set_is_method_handle_return(nm->is_method_handle_return(pc)); if (log_is_enabled(Info, exceptions)) { ResourceMark rm; diff --git a/src/hotspot/share/cds/aotMapLogger.cpp b/src/hotspot/share/cds/aotMapLogger.cpp index a15d7f670d4..ded3f05a9b8 100644 --- a/src/hotspot/share/cds/aotMapLogger.cpp +++ b/src/hotspot/share/cds/aotMapLogger.cpp @@ -33,6 +33,8 @@ #include "memory/metaspaceClosure.hpp" #include "memory/resourceArea.hpp" #include "oops/method.hpp" +#include "oops/methodCounters.hpp" +#include "oops/methodData.hpp" #include "oops/oop.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/globals_extension.hpp" @@ -348,6 +350,12 @@ void AOTMapLogger::log_metaspace_objects_impl(address region_base, address regio case MetaspaceObj::MethodType: log_method((Method*)src, requested_addr, type_name, bytes, current); break; + case MetaspaceObj::MethodCountersType: + log_method_counters((MethodCounters*)src, requested_addr, type_name, bytes, current); + break; + case MetaspaceObj::MethodDataType: + log_method_data((MethodData*)src, requested_addr, type_name, bytes, current); + break; case MetaspaceObj::SymbolType: log_symbol((Symbol*)src, requested_addr, type_name, bytes, current); break; @@ -389,6 +397,18 @@ void AOTMapLogger::log_const_method(ConstMethod* cm, address requested_addr, con log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, cm->method()->external_name()); } +void AOTMapLogger::log_method_counters(MethodCounters* mc, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, mc->method()->external_name()); +} + +void AOTMapLogger::log_method_data(MethodData* md, address requested_addr, const char* type_name, + int bytes, Thread* current) { + ResourceMark rm(current); + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, md->method()->external_name()); +} + void AOTMapLogger::log_klass(Klass* k, address requested_addr, const char* type_name, int bytes, Thread* current) { ResourceMark rm(current); diff --git a/src/hotspot/share/cds/aotMapLogger.hpp b/src/hotspot/share/cds/aotMapLogger.hpp index 9cd67fb7ff6..f2ca4c407e3 100644 --- a/src/hotspot/share/cds/aotMapLogger.hpp +++ b/src/hotspot/share/cds/aotMapLogger.hpp @@ -98,6 +98,10 @@ class AOTMapLogger : AllStatic { static void log_constant_pool_cache(ConstantPoolCache* cpc, address requested_addr, const char* type_name, int bytes, Thread* current); static void log_const_method(ConstMethod* cm, address requested_addr, const char* type_name, int bytes, Thread* current); + static void log_method_counters(MethodCounters* mc, address requested_addr, const char* type_name, int bytes, + Thread* current); + static void log_method_data(MethodData* md, address requested_addr, const char* type_name, int bytes, + Thread* current); static void log_klass(Klass* k, address requested_addr, const char* type_name, int bytes, Thread* current); static void log_method(Method* m, address requested_addr, const char* type_name, int bytes, Thread* current); static void log_symbol(Symbol* s, address requested_addr, const char* type_name, int bytes, Thread* current); diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp index 90f35c61de1..2d0953288b0 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp @@ -1,4 +1,3 @@ - /* * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -53,7 +52,7 @@ void DumpTimeSharedClassTable::iterate_all_live_classes(Function function) const assert(k->is_loader_alive(), "must not change"); } else { if (!SystemDictionaryShared::is_excluded_class(k)) { - SystemDictionaryShared::warn_excluded(k, "Class loader not alive"); + SystemDictionaryShared::log_exclusion(k, "Class loader not alive"); SystemDictionaryShared::set_excluded_locked(k); } } diff --git a/src/hotspot/share/ci/ciObjectFactory.hpp b/src/hotspot/share/ci/ciObjectFactory.hpp index 15ff2e48eb6..fd7ca6bb801 100644 --- a/src/hotspot/share/ci/ciObjectFactory.hpp +++ b/src/hotspot/share/ci/ciObjectFactory.hpp @@ -37,7 +37,6 @@ // which ensures that for each oop, at most one ciObject is created. // This invariant allows efficient implementation of ciObject. class ciObjectFactory : public ArenaObj { - friend class VMStructs; friend class ciEnv; private: diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 52bbab01d61..87f2da91288 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -2445,7 +2445,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, cfs->skip_u2_fast(method_parameters_length); cfs->skip_u2_fast(method_parameters_length); // ignore this attribute if it cannot be reflected - if (!vmClasses::Parameter_klass_loaded()) + if (!vmClasses::reflect_Parameter_klass_is_loaded()) method_parameters_length = -1; } else if (method_attribute_name == vmSymbols::tag_synthetic()) { if (method_attribute_length != 0) { @@ -3979,7 +3979,7 @@ void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) { #endif // Check if this klass supports the java.lang.Cloneable interface - if (vmClasses::Cloneable_klass_loaded()) { + if (vmClasses::Cloneable_klass_is_loaded()) { if (ik->is_subtype_of(vmClasses::Cloneable_klass())) { ik->set_is_cloneable(); } @@ -4678,11 +4678,15 @@ const char* ClassFileParser::skip_over_field_signature(const char* signature, return signature + 1; case JVM_SIGNATURE_CLASS: { if (_major_version < JAVA_1_5_VERSION) { + signature++; + length--; // Skip over the class name if one is there - const char* const p = skip_over_field_name(signature + 1, true, --length); - + const char* const p = skip_over_field_name(signature, true, length); + assert(p == nullptr || p > signature, "must parse one character at least"); // The next character better be a semicolon - if (p && (p - signature) > 1 && p[0] == JVM_SIGNATURE_ENDCLASS) { + if (p != nullptr && // Parse of field name succeeded. + p - signature < static_cast(length) && // There is at least one character left to parse. + p[0] == JVM_SIGNATURE_ENDCLASS) { return p + 1; } } diff --git a/src/hotspot/share/classfile/classLoaderData.hpp b/src/hotspot/share/classfile/classLoaderData.hpp index da49a9326e3..64fcfb7519f 100644 --- a/src/hotspot/share/classfile/classLoaderData.hpp +++ b/src/hotspot/share/classfile/classLoaderData.hpp @@ -97,7 +97,7 @@ class ClassLoaderData : public CHeapObj { }; friend class ClassLoaderDataGraph; - friend class ClassLoaderDataGraphKlassIteratorAtomic; + friend class ClassLoaderDataGraphIteratorAtomic; friend class Klass; friend class MetaDataFactory; friend class Method; diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.cpp b/src/hotspot/share/classfile/classLoaderDataGraph.cpp index 4d3d6a951c5..61404fdf9db 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp @@ -489,62 +489,25 @@ void ClassLoaderDataGraph::purge(bool at_safepoint) { } } -ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic() - : _next_klass(nullptr) { +ClassLoaderDataGraphIteratorAtomic::ClassLoaderDataGraphIteratorAtomic() + : _cld(nullptr) { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); - ClassLoaderData* cld = ClassLoaderDataGraph::_head; - Klass* klass = nullptr; - - // Find the first klass in the CLDG. - while (cld != nullptr) { - assert_locked_or_safepoint(cld->metaspace_lock()); - klass = cld->_klasses; - if (klass != nullptr) { - _next_klass = klass; - return; - } - cld = cld->next(); - } + _cld = AtomicAccess::load_acquire(&ClassLoaderDataGraph::_head); } -Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass_in_cldg(Klass* klass) { - Klass* next = klass->next_link(); - if (next != nullptr) { - return next; - } - - // No more klasses in the current CLD. Time to find a new CLD. - ClassLoaderData* cld = klass->class_loader_data(); - assert_locked_or_safepoint(cld->metaspace_lock()); - while (next == nullptr) { - cld = cld->next(); - if (cld == nullptr) { - break; +ClassLoaderData* ClassLoaderDataGraphIteratorAtomic::next() { + ClassLoaderData* cur = AtomicAccess::load(&_cld); + for (;;) { + if (cur == nullptr) { + return nullptr; } - next = cld->_klasses; - } - - return next; -} - -Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() { - Klass* head = _next_klass; - - while (head != nullptr) { - Klass* next = next_klass_in_cldg(head); - - Klass* old_head = AtomicAccess::cmpxchg(&_next_klass, head, next); - - if (old_head == head) { - return head; // Won the CAS. + ClassLoaderData* next = cur->next(); + ClassLoaderData* old; + if ((old = AtomicAccess::cmpxchg(&_cld, cur, next)) == cur) { + return cur; } - - head = old_head; + cur = old; } - - // Nothing more for the iterator to hand out. - assert(head == nullptr, "head is " PTR_FORMAT ", expected not null:", p2i(head)); - return nullptr; } void ClassLoaderDataGraph::verify() { diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.hpp b/src/hotspot/share/classfile/classLoaderDataGraph.hpp index 1dcca4d1069..803f227dcf3 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.hpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.hpp @@ -34,7 +34,7 @@ class ClassLoaderDataGraph : public AllStatic { friend class ClassLoaderData; - friend class ClassLoaderDataGraphKlassIteratorAtomic; + friend class ClassLoaderDataGraphIteratorAtomic; friend class VMStructs; private: class ClassLoaderDataGraphIterator; @@ -140,14 +140,14 @@ class LockedClassesDo : public KlassClosure { } }; -// An iterator that distributes Klasses to parallel worker threads. -class ClassLoaderDataGraphKlassIteratorAtomic : public StackObj { - Klass* volatile _next_klass; - public: - ClassLoaderDataGraphKlassIteratorAtomic(); - Klass* next_klass(); - private: - static Klass* next_klass_in_cldg(Klass* klass); +// An iterator that distributes Klasses to parallel worker threads based on CLDs. +class ClassLoaderDataGraphIteratorAtomic : public StackObj { + ClassLoaderData* volatile _cld; + +public: + ClassLoaderDataGraphIteratorAtomic(); + + ClassLoaderData* next(); }; #endif // SHARE_CLASSFILE_CLASSLOADERDATAGRAPH_HPP diff --git a/src/hotspot/share/classfile/compactHashtable.cpp b/src/hotspot/share/classfile/compactHashtable.cpp index 9f7ec6bd118..6808ae7bb8f 100644 --- a/src/hotspot/share/classfile/compactHashtable.cpp +++ b/src/hotspot/share/classfile/compactHashtable.cpp @@ -72,10 +72,10 @@ CompactHashtableWriter::~CompactHashtableWriter() { FREE_C_HEAP_ARRAY(GrowableArray*, _buckets); } -// Add a symbol entry to the temporary hash table -void CompactHashtableWriter::add(unsigned int hash, u4 value) { +// Add an entry to the temporary hash table +void CompactHashtableWriter::add(unsigned int hash, u4 encoded_value) { int index = hash % _num_buckets; - _buckets[index]->append_if_missing(Entry(hash, value)); + _buckets[index]->append_if_missing(Entry(hash, encoded_value)); _num_entries_written++; } @@ -107,27 +107,28 @@ void CompactHashtableWriter::allocate_table() { SharedSpaceObjectAlignment); } -// Write the compact table's buckets +// Write the compact table's buckets and entries void CompactHashtableWriter::dump_table(NumberSeq* summary) { u4 offset = 0; for (int index = 0; index < _num_buckets; index++) { GrowableArray* bucket = _buckets[index]; int bucket_size = bucket->length(); if (bucket_size == 1) { - // bucket with one entry is compacted and only has the symbol offset _compact_buckets->at_put(index, BUCKET_INFO(offset, VALUE_ONLY_BUCKET_TYPE)); Entry ent = bucket->at(0); - _compact_entries->at_put(offset++, ent.value()); + // bucket with one entry is value_only and only has the encoded_value + _compact_entries->at_put(offset++, ent.encoded_value()); _num_value_only_buckets++; } else { - // regular bucket, each entry is a symbol (hash, offset) pair + // regular bucket, it could contain zero or more than one entry, + // each entry is a pair _compact_buckets->at_put(index, BUCKET_INFO(offset, REGULAR_BUCKET_TYPE)); for (int i=0; iat(i); - _compact_entries->at_put(offset++, u4(ent.hash())); // write entry hash - _compact_entries->at_put(offset++, ent.value()); + _compact_entries->at_put(offset++, u4(ent.hash())); // write entry hash + _compact_entries->at_put(offset++, ent.encoded_value()); // write entry encoded_value } if (bucket_size == 0) { _num_empty_buckets++; @@ -189,15 +190,7 @@ void SimpleCompactHashtable::init(address base_address, u4 entry_count, u4 bucke _entries = entries; } -size_t SimpleCompactHashtable::calculate_header_size() { - // We have 5 fields. Each takes up sizeof(intptr_t). See WriteClosure::do_u4 - size_t bytes = sizeof(intptr_t) * 5; - return bytes; -} - void SimpleCompactHashtable::serialize_header(SerializeClosure* soc) { - // NOTE: if you change this function, you MUST change the number 5 in - // calculate_header_size() accordingly. soc->do_u4(&_entry_count); soc->do_u4(&_bucket_count); soc->do_ptr(&_buckets); diff --git a/src/hotspot/share/classfile/compactHashtable.hpp b/src/hotspot/share/classfile/compactHashtable.hpp index 83299eda8c7..402c8f197fa 100644 --- a/src/hotspot/share/classfile/compactHashtable.hpp +++ b/src/hotspot/share/classfile/compactHashtable.hpp @@ -35,7 +35,7 @@ template < typename K, typename V, - V (*DECODE)(address base_address, u4 offset), + V (*DECODE)(address base_address, u4 encoded_value), bool (*EQUALS)(V value, K key, int len) > class CompactHashtable; @@ -62,8 +62,9 @@ class CompactHashtableStats { // The compact hash table writer. Used at dump time for writing out // the compact table to the shared archive. // -// At dump time, the CompactHashtableWriter obtains all entries from the -// symbol/string table and adds them to a new temporary hash table. The hash +// At dump time, the CompactHashtableWriter obtains all entries from +// a table (the table could be in any form of a collection of pair) +// and adds them to a new temporary hash table (_buckets). The hash // table size (number of buckets) is calculated using // '(num_entries + bucket_size - 1) / bucket_size'. The default bucket // size is 4 and can be changed by -XX:SharedSymbolTableBucketSize option. @@ -76,10 +77,10 @@ class CompactHashtableStats { // above the CompactHashtable class for the table layout detail. The bucket // offsets are written to the archive as part of the compact table. The // bucket offset is encoded in the low 30-bit (0-29) and the bucket type -// (regular or compact) are encoded in bit[31, 30]. For buckets with more -// than one entry, both hash and entry offset are written to the -// table. For buckets with only one entry, only the entry offset is written -// to the table and the buckets are tagged as compact in their type bits. +// (regular or value_only) are encoded in bit[31, 30]. For buckets with more +// than one entry, both hash and encoded_value are written to the +// table. For buckets with only one entry, only the encoded_value is written +// to the table and the buckets are tagged as value_only in their type bits. // Buckets without entry are skipped from the table. Their offsets are // still written out for faster lookup. // @@ -87,21 +88,21 @@ class CompactHashtableWriter: public StackObj { public: class Entry { unsigned int _hash; - u4 _value; + u4 _encoded_value; public: Entry() {} - Entry(unsigned int hash, u4 val) : _hash(hash), _value(val) {} + Entry(unsigned int hash, u4 encoded_value) : _hash(hash), _encoded_value(encoded_value) {} - u4 value() { - return _value; + u4 encoded_value() { + return _encoded_value; } unsigned int hash() { return _hash; } bool operator==(const CompactHashtableWriter::Entry& other) { - return (_value == other._value && _hash == other._hash); + return (_encoded_value == other._encoded_value && _hash == other._hash); } }; // class CompactHashtableWriter::Entry @@ -121,7 +122,8 @@ class CompactHashtableWriter: public StackObj { CompactHashtableWriter(int num_entries, CompactHashtableStats* stats); ~CompactHashtableWriter(); - void add(unsigned int hash, u4 value); + void add(unsigned int hash, u4 encoded_value); + void dump(SimpleCompactHashtable *cht, const char* table_name); private: void allocate_table(); @@ -131,9 +133,6 @@ class CompactHashtableWriter: public StackObj { // calculation of num_buckets can result in zero buckets, we need at least one return (num_buckets < 1) ? 1 : num_buckets; } - -public: - void dump(SimpleCompactHashtable *cht, const char* table_name); }; #endif // INCLUDE_CDS @@ -148,7 +147,8 @@ class CompactHashtableWriter: public StackObj { ///////////////////////////////////////////////////////////////////////////// // -// CompactHashtable is used to store the CDS archive's symbol/string tables. +// CompactHashtable is used to store the CDS archive's tables. +// A table could be in any form of a collection of pair. // // Because these tables are read-only (no entries can be added/deleted) at run-time // and tend to have large number of entries, we try to minimize the footprint @@ -162,32 +162,47 @@ class CompactHashtableWriter: public StackObj { // The size of buckets[] is 'num_buckets + 1'. Each entry of // buckets[] is a 32-bit encoding of the bucket type and bucket offset, // with the type in the left-most 2-bit and offset in the remaining 30-bit. -// The last entry is a special type. It contains the end of the last -// bucket. // -// There are two types of buckets, regular buckets and value_only buckets. The -// value_only buckets have '01' in their highest 2-bit, and regular buckets have -// '00' in their highest 2-bit. +// There are three types of buckets: regular, value_only, and table_end. +// . The regular buckets have '00' in their highest 2-bit. +// . The value_only buckets have '01' in their highest 2-bit. +// . There is only a single table_end bucket that marks the end of buckets[]. +// It has '11' in its highest 2-bit. // -// For normal buckets, each entry is 8 bytes in the entries[]: -// u4 hash; /* symbol/string hash */ -// union { -// u4 offset; /* Symbol* sym = (Symbol*)(base_address + offset) */ -// narrowOop str; /* String narrowOop encoding */ -// } +// For regular buckets, each entry is 8 bytes in the entries[]: +// u4 hash; // entry hash +// u4 encoded_value; // A 32-bit encoding of the template type V. The template parameter DECODE +// // converts this to type V. Many CompactHashtables encode a pointer as a 32-bit offset, where +// // V entry = (V)(base_address + offset) +// // see StringTable, SymbolTable and AdapterHandlerLibrary for examples // +// For value_only buckets, each entry has only the 4-byte 'encoded_value' in the entries[]. // -// For value_only buckets, each entry has only the 4-byte 'offset' in the entries[]. +// The single table_end bucket has no corresponding entry. // -// Example -- note that the second bucket is a VALUE_ONLY_BUCKET_TYPE so the hash code -// is skipped. -// buckets[0, 4, 5, ....] -// | | | -// | | +---+ -// | | | -// | +----+ | -// v v v -// entries[H,O,H,O,O,H,O,H,O.....] +// The number of entries in bucket can be calculated like this: +// my_offset = _buckets[i] & 0x3fffffff; // mask off top 2-bit +// next_offset = _buckets[i+1] & 0x3fffffff +// For REGULAR_BUCKET_TYPE +// num_entries = (next_offset - my_offset) / 8; +// For VALUE_ONLY_BUCKET_TYPE +// num_entries = (next_offset - my_offset) / 4; +// +// If bucket is empty, we have my_offset == next_offset. Empty buckets are +// always encoded as regular buckets. +// +// In the following example: +// - Bucket #0 is a REGULAR_BUCKET_TYPE with two entries +// - Bucket #1 is a VALUE_ONLY_BUCKET_TYPE with one entry. +// - Bucket #2 is a REGULAR_BUCKET_TYPE with zero entries. +// +// buckets[0, 4, 5(empty), 5, ...., N(table_end)] +// | | | | | +// | | +---+-----+ | +// | | | | +// | +----+ + | +// v v v v +// entries[H,O,H,O,O,H,O,H,O........] // // See CompactHashtable::lookup() for how the table is searched at runtime. // See CompactHashtableWriter::dump() for how the table is written at CDS @@ -230,21 +245,18 @@ class SimpleCompactHashtable { inline size_t entry_count() const { return _entry_count; } - - static size_t calculate_header_size(); }; template < typename K, typename V, - V (*DECODE)(address base_address, u4 offset), + V (*DECODE)(address base_address, u4 encoded_value), bool (*EQUALS)(V value, K key, int len) > class CompactHashtable : public SimpleCompactHashtable { - friend class VMStructs; - V decode(u4 offset) const { - return DECODE(_base_address, offset); + V decode(u4 encoded_value) const { + return DECODE(_base_address, encoded_value); } public: @@ -264,7 +276,7 @@ class CompactHashtable : public SimpleCompactHashtable { } } else { // This is a regular bucket, which has more than one - // entries. Each entry is a pair of entry (hash, offset). + // entries. Each entry is a (hash, value) pair. // Seek until the end of the bucket. u4* entry_max = _entries + BUCKET_OFFSET(_buckets[index + 1]); while (entry < entry_max) { diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 75f54bfa549..cfe55bf7f76 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1150,7 +1150,7 @@ void java_lang_Class::create_mirror(Klass* k, Handle class_loader, // Class_klass has to be loaded because it is used to allocate // the mirror. - if (vmClasses::Class_klass_loaded()) { + if (vmClasses::Class_klass_is_loaded()) { Handle mirror; Handle comp_mirror; @@ -1223,7 +1223,7 @@ bool java_lang_Class::restore_archived_mirror(Klass *k, Handle protection_domain, TRAPS) { // Postpone restoring archived mirror until java.lang.Class is loaded. Please // see more details in vmClasses::resolve_all(). - if (!vmClasses::Class_klass_loaded() && !CDSConfig::is_using_aot_linked_classes()) { + if (!vmClasses::Class_klass_is_loaded() && !CDSConfig::is_using_aot_linked_classes()) { assert(fixup_mirror_list() != nullptr, "fixup_mirror_list not initialized"); fixup_mirror_list()->push(k); return true; diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 04c2d7ffb84..b092e71f4e7 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -174,7 +174,6 @@ InstanceKlass* SystemDictionaryShared::acquire_class_for_current_thread( // No longer holding SharedDictionary_lock // No need to lock, as can be held only by a single thread. - loader_data->add_class(ik); // Get the package entry. PackageEntry* pkg_entry = CDSProtectionDomain::get_package_entry_from_class(ik, class_loader); @@ -354,11 +353,13 @@ void SystemDictionaryShared::check_exclusion_for_self_and_dependencies(InstanceK }); } -// Returns true so the caller can do: return warn_excluded("....."); -bool SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) { +void SystemDictionaryShared::log_exclusion(InstanceKlass* k, const char* reason, bool is_warning) { ResourceMark rm; - aot_log_warning(aot)("Skipping %s: %s", k->name()->as_C_string(), reason); - return true; + if (is_warning) { + aot_log_warning(aot)("Skipping %s: %s", k->name()->as_C_string(), reason); + } else { + aot_log_info(aot)("Skipping %s: %s", k->name()->as_C_string(), reason); + } } bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) { @@ -377,23 +378,35 @@ bool SystemDictionaryShared::is_early_klass(InstanceKlass* ik) { } bool SystemDictionaryShared::check_self_exclusion(InstanceKlass* k) { + bool log_warning = false; + const char* error = check_self_exclusion_helper(k, log_warning); + if (error != nullptr) { + log_exclusion(k, error, log_warning); + return true; // Should be excluded + } else { + return false; // Should not be excluded + } +} + +const char* SystemDictionaryShared::check_self_exclusion_helper(InstanceKlass* k, bool& log_warning) { assert_lock_strong(DumpTimeTable_lock); if (CDSConfig::is_dumping_final_static_archive() && k->defined_by_other_loaders() && k->in_aot_cache()) { - return false; // Do not exclude: unregistered classes are passed from preimage to final image. + return nullptr; // Do not exclude: unregistered classes are passed from preimage to final image. } if (k->is_in_error_state()) { - return warn_excluded(k, "In error state"); + log_warning = true; + return "In error state"; } if (k->is_scratch_class()) { - return warn_excluded(k, "A scratch class"); + return "A scratch class"; } if (!k->is_loaded()) { - return warn_excluded(k, "Not in loaded state"); + return "Not in loaded state"; } if (has_been_redefined(k)) { - return warn_excluded(k, "Has been redefined"); + return "Has been redefined"; } if (!k->is_hidden() && k->shared_classpath_index() < 0 && is_builtin(k)) { if (k->name()->starts_with("java/lang/invoke/BoundMethodHandle$Species_")) { @@ -401,43 +414,42 @@ bool SystemDictionaryShared::check_self_exclusion(InstanceKlass* k) { if (CDSConfig::is_dumping_method_handles()) { k->set_shared_classpath_index(0); } else { - ResourceMark rm; - aot_log_info(aot)("Skipping %s because it is dynamically generated", k->name()->as_C_string()); - return true; // exclude without warning + return "dynamically generated"; } } else { // These are classes loaded from unsupported locations (such as those loaded by JVMTI native // agent during dump time). - return warn_excluded(k, "Unsupported location"); + return "Unsupported location"; } } if (k->signers() != nullptr) { // We cannot include signed classes in the archive because the certificates // used during dump time may be different than those used during // runtime (due to expiration, etc). - return warn_excluded(k, "Signed JAR"); + return "Signed JAR"; } if (is_jfr_event_class(k)) { // We cannot include JFR event classes because they need runtime-specific // instrumentation in order to work with -XX:FlightRecorderOptions:retransform=false. // There are only a small number of these classes, so it's not worthwhile to // support them and make CDS more complicated. - return warn_excluded(k, "JFR event class"); + return "JFR event class"; } if (!k->is_linked()) { if (has_class_failed_verification(k)) { - return warn_excluded(k, "Failed verification"); + log_warning = true; + return "Failed verification"; } else if (CDSConfig::is_dumping_aot_linked_classes()) { // Most loaded classes should have been speculatively linked by AOTMetaspace::link_class_for_cds(). // Old classes may not be linked if CDSConfig::is_preserving_verification_constraints()==false. // An unlinked class may fail to verify in AOTLinkedClassBulkLoader::init_required_classes_for_loader(), // causing the JVM to fail at bootstrap. - return warn_excluded(k, "Unlinked class not supported by AOTClassLinking"); + return "Unlinked class not supported by AOTClassLinking"; } else if (CDSConfig::is_dumping_preimage_static_archive()) { // When dumping the final static archive, we will unconditionally load and link all // classes from the preimage. We don't want to get a VerifyError when linking this class. - return warn_excluded(k, "Unlinked class not supported by AOTConfiguration"); + return "Unlinked class not supported by AOTConfiguration"; } } else { if (!k->can_be_verified_at_dumptime()) { @@ -447,17 +459,15 @@ bool SystemDictionaryShared::check_self_exclusion(InstanceKlass* k) { // won't work at runtime. // As a result, we cannot store this class. It must be loaded and fully verified // at runtime. - return warn_excluded(k, "Old class has been linked"); + return "Old class has been linked"; } } if (UnregisteredClasses::check_for_exclusion(k)) { - ResourceMark rm; - aot_log_info(aot)("Skipping %s: used only when dumping CDS archive", k->name()->as_C_string()); - return true; + return "used only when dumping CDS archive"; } - return false; + return nullptr; } // Returns true if DumpTimeClassInfo::is_excluded() is true for at least one of k's exclusion dependencies. @@ -511,7 +521,7 @@ bool SystemDictionaryShared::is_dependency_excluded(InstanceKlass* k, InstanceKl DumpTimeClassInfo* dependency_info = get_info_locked(dependency); if (dependency_info->is_excluded()) { ResourceMark rm; - aot_log_warning(aot)("Skipping %s: %s %s is excluded", k->name()->as_C_string(), type, dependency->name()->as_C_string()); + aot_log_info(aot)("Skipping %s: %s %s is excluded", k->name()->as_C_string(), type, dependency->name()->as_C_string()); return true; } return false; @@ -838,7 +848,7 @@ class UnregisteredClassesDuplicationChecker : StackObj { InstanceKlass* k = _list.at(i); bool i_am_first = SystemDictionaryShared::add_unregistered_class(_thread, k); if (!i_am_first) { - SystemDictionaryShared::warn_excluded(k, "Duplicated unregistered class"); + SystemDictionaryShared::log_exclusion(k, "Duplicated unregistered class"); SystemDictionaryShared::set_excluded_locked(k); } } @@ -967,7 +977,7 @@ bool SystemDictionaryShared::has_class_failed_verification(InstanceKlass* ik) { } void SystemDictionaryShared::set_from_class_file_load_hook(InstanceKlass* ik) { - warn_excluded(ik, "From ClassFileLoadHook"); + log_exclusion(ik, "From ClassFileLoadHook"); set_excluded(ik); } diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index baad020cb61..5ff57653dd0 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -180,6 +180,7 @@ class SystemDictionaryShared: public SystemDictionary { // exclusion checks static void check_exclusion_for_self_and_dependencies(InstanceKlass *k); static bool check_self_exclusion(InstanceKlass* k); + static const char* check_self_exclusion_helper(InstanceKlass* k, bool& log_warning); static bool check_dependencies_exclusion(InstanceKlass* k, DumpTimeClassInfo* info); static bool check_verification_constraint_exclusion(InstanceKlass* k, Symbol* constraint_class_name); static bool is_dependency_excluded(InstanceKlass* k, InstanceKlass* dependency, const char* type); @@ -277,7 +278,7 @@ class SystemDictionaryShared: public SystemDictionary { static void set_excluded(InstanceKlass* k); static void set_excluded_locked(InstanceKlass* k); static void set_from_class_file_load_hook(InstanceKlass* k) NOT_CDS_RETURN; - static bool warn_excluded(InstanceKlass* k, const char* reason); + static void log_exclusion(InstanceKlass* k, const char* reason, bool is_warning = false); static void dumptime_classes_do(class MetaspaceClosure* it); static void write_to_archive(bool is_static_archive = true); static void serialize_dictionary_headers(class SerializeClosure* soc, diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index f6f5aa70fbd..bc278f3d158 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -237,7 +237,7 @@ bool Verifier::verify(InstanceKlass* klass, bool should_verify_class, TRAPS) { // Exclude any classes that are verified with the old verifier, as the old verifier // doesn't call SystemDictionaryShared::add_verification_constraint() if (CDSConfig::is_dumping_archive()) { - SystemDictionaryShared::warn_excluded(klass, "Verified with old verifier"); + SystemDictionaryShared::log_exclusion(klass, "Verified with old verifier"); SystemDictionaryShared::set_excluded(klass); } #endif diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index e337d5569bc..478f40ff05b 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -113,7 +113,7 @@ void vmClasses::resolve_until(vmClassID limit_id, vmClassID &start_id, TRAPS) { } void vmClasses::resolve_all(TRAPS) { - assert(!Object_klass_loaded(), "well-known classes should only be initialized once"); + assert(!Object_klass_is_loaded(), "well-known classes should only be initialized once"); // Create the ModuleEntry for java.base. This call needs to be done here, // after vmSymbols::initialize() is called but before any classes are pre-loaded. diff --git a/src/hotspot/share/classfile/vmClasses.hpp b/src/hotspot/share/classfile/vmClasses.hpp index 4fa078c50cd..caa54590eb2 100644 --- a/src/hotspot/share/classfile/vmClasses.hpp +++ b/src/hotspot/share/classfile/vmClasses.hpp @@ -102,12 +102,6 @@ class vmClasses : AllStatic { assert((uint)t < T_VOID+1, "range check"); return check_klass(_box_klasses[t]); } - - static bool Object_klass_loaded() { return is_loaded(VM_CLASS_AT(Object_klass)); } - static bool Class_klass_loaded() { return is_loaded(VM_CLASS_AT(Class_klass)); } - static bool Cloneable_klass_loaded() { return is_loaded(VM_CLASS_AT(Cloneable_klass)); } - static bool Parameter_klass_loaded() { return is_loaded(VM_CLASS_AT(reflect_Parameter_klass)); } - static bool ClassLoader_klass_loaded() { return is_loaded(VM_CLASS_AT(ClassLoader_klass)); } }; #endif // SHARE_CLASSFILE_VMCLASSES_HPP diff --git a/src/hotspot/share/code/codeBehaviours.cpp b/src/hotspot/share/code/codeBehaviours.cpp index 1f9eb0e2914..bc5a81c95b3 100644 --- a/src/hotspot/share/code/codeBehaviours.cpp +++ b/src/hotspot/share/code/codeBehaviours.cpp @@ -23,23 +23,24 @@ */ #include "code/codeBehaviours.hpp" +#include "code/nmethod.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" CompiledICProtectionBehaviour* CompiledICProtectionBehaviour::_current = nullptr; -bool DefaultICProtectionBehaviour::lock(nmethod* method) { - if (is_safe(method)) { +bool DefaultICProtectionBehaviour::lock(nmethod* nm) { + if (is_safe(nm)) { return false; } CompiledIC_lock->lock_without_safepoint_check(); return true; } -void DefaultICProtectionBehaviour::unlock(nmethod* method) { +void DefaultICProtectionBehaviour::unlock(nmethod* nm) { CompiledIC_lock->unlock(); } -bool DefaultICProtectionBehaviour::is_safe(nmethod* method) { - return SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->owned_by_self(); +bool DefaultICProtectionBehaviour::is_safe(nmethod* nm) { + return SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->owned_by_self() || (NMethodState_lock->owned_by_self() && nm->is_not_installed()); } diff --git a/src/hotspot/share/code/codeBehaviours.hpp b/src/hotspot/share/code/codeBehaviours.hpp index 0350f5752f6..96a38fffc30 100644 --- a/src/hotspot/share/code/codeBehaviours.hpp +++ b/src/hotspot/share/code/codeBehaviours.hpp @@ -33,18 +33,18 @@ class CompiledICProtectionBehaviour { static CompiledICProtectionBehaviour* _current; public: - virtual bool lock(nmethod* method) = 0; - virtual void unlock(nmethod* method) = 0; - virtual bool is_safe(nmethod* method) = 0; + virtual bool lock(nmethod* nm) = 0; + virtual void unlock(nmethod* nm) = 0; + virtual bool is_safe(nmethod* nm) = 0; static CompiledICProtectionBehaviour* current() { return _current; } static void set_current(CompiledICProtectionBehaviour* current) { _current = current; } }; class DefaultICProtectionBehaviour: public CompiledICProtectionBehaviour, public CHeapObj { - virtual bool lock(nmethod* method); - virtual void unlock(nmethod* method); - virtual bool is_safe(nmethod* method); + virtual bool lock(nmethod* nm); + virtual void unlock(nmethod* nm); + virtual bool is_safe(nmethod* nm); }; #endif // SHARE_CODE_CODEBEHAVIOURS_HPP diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 0b4760e7e1e..0469b6c71b1 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -325,7 +325,6 @@ class CodeBlob { // RuntimeBlob: used for non-compiled method code (adapters, stubs, blobs) class RuntimeBlob : public CodeBlob { - friend class VMStructs; public: // Creation @@ -634,7 +633,6 @@ class DeoptimizationBlob: public SingletonBlob { #ifdef COMPILER2 class UncommonTrapBlob: public SingletonBlob { - friend class VMStructs; private: // Creation support UncommonTrapBlob( @@ -658,7 +656,6 @@ class UncommonTrapBlob: public SingletonBlob { // ExceptionBlob: used for exception unwinding in compiled code (currently only used by Compiler 2) class ExceptionBlob: public SingletonBlob { - friend class VMStructs; private: // Creation support ExceptionBlob( @@ -695,7 +692,6 @@ class ExceptionBlob: public SingletonBlob { // SafepointBlob: handles illegal_instruction exceptions during a safepoint class SafepointBlob: public SingletonBlob { - friend class VMStructs; private: // Creation support SafepointBlob( diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 3e446ab8430..dc9e5d7dc20 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -259,7 +259,7 @@ class CodeCache : AllStatic { static bool heap_available(CodeBlobType code_blob_type); // Returns the CodeBlobType for the given nmethod - static CodeBlobType get_code_blob_type(nmethod* nm) { + static CodeBlobType get_code_blob_type(const nmethod* nm) { return get_code_heap(nm)->code_blob_type(); } diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index 03d9adc8e24..5f5c9711441 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.cpp @@ -55,8 +55,8 @@ CompiledICLocker::~CompiledICLocker() { } } -bool CompiledICLocker::is_safe(nmethod* method) { - return CompiledICProtectionBehaviour::current()->is_safe(method); +bool CompiledICLocker::is_safe(nmethod* nm) { + return CompiledICProtectionBehaviour::current()->is_safe(nm); } bool CompiledICLocker::is_safe(address code) { diff --git a/src/hotspot/share/code/compiledIC.hpp b/src/hotspot/share/code/compiledIC.hpp index 624c1b428de..db8a0860b39 100644 --- a/src/hotspot/share/code/compiledIC.hpp +++ b/src/hotspot/share/code/compiledIC.hpp @@ -50,7 +50,7 @@ class CompiledICLocker: public StackObj { public: CompiledICLocker(nmethod* method); ~CompiledICLocker(); - static bool is_safe(nmethod* method); + static bool is_safe(nmethod* nm); static bool is_safe(address code); }; diff --git a/src/hotspot/share/code/debugInfoRec.cpp b/src/hotspot/share/code/debugInfoRec.cpp index 8449f5d6929..41d944ec76f 100644 --- a/src/hotspot/share/code/debugInfoRec.cpp +++ b/src/hotspot/share/code/debugInfoRec.cpp @@ -283,7 +283,6 @@ void DebugInformationRecorder::describe_scope(int pc_offset, int bci, bool reexecute, bool rethrow_exception, - bool is_method_handle_invoke, bool return_oop, bool has_ea_local_in_scope, bool arg_escape, @@ -301,7 +300,6 @@ void DebugInformationRecorder::describe_scope(int pc_offset, // Record flags into pcDesc. last_pd->set_should_reexecute(reexecute); last_pd->set_rethrow_exception(rethrow_exception); - last_pd->set_is_method_handle_invoke(is_method_handle_invoke); last_pd->set_return_oop(return_oop); last_pd->set_has_ea_local_in_scope(has_ea_local_in_scope); last_pd->set_arg_escape(arg_escape); diff --git a/src/hotspot/share/code/debugInfoRec.hpp b/src/hotspot/share/code/debugInfoRec.hpp index f6d7cf6d278..d18208e17c4 100644 --- a/src/hotspot/share/code/debugInfoRec.hpp +++ b/src/hotspot/share/code/debugInfoRec.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, 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 @@ -105,7 +105,6 @@ class DebugInformationRecorder: public ResourceObj { int bci, bool reexecute, bool rethrow_exception = false, - bool is_method_handle_invoke = false, bool return_oop = false, bool has_ea_local_in_scope = false, bool arg_escape = false, diff --git a/src/hotspot/share/code/dependencyContext.hpp b/src/hotspot/share/code/dependencyContext.hpp index 7e8f7163509..b08300ec645 100644 --- a/src/hotspot/share/code/dependencyContext.hpp +++ b/src/hotspot/share/code/dependencyContext.hpp @@ -42,7 +42,6 @@ class DepChange; // finding nmethods which might need to be deoptimized. // class nmethodBucket: public CHeapObj { - friend class VMStructs; private: nmethod* _nmethod; nmethodBucket* volatile _next; @@ -68,7 +67,6 @@ class nmethodBucket: public CHeapObj { // and uint64_t integer recording the safepoint counter at the last cleanup. // class DependencyContext : public StackObj { - friend class VMStructs; friend class TestDependencyContext; private: nmethodBucket* volatile* _dependency_context_addr; diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index fbd9f5030c8..7274b627f3e 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -465,14 +465,6 @@ static int adjust_pcs_size(int pcs_size) { return nsize; } -bool nmethod::is_method_handle_return(address return_pc) { - if (!has_method_handle_invokes()) return false; - PcDesc* pd = pc_desc_at(return_pc); - if (pd == nullptr) - return false; - return pd->is_method_handle_invoke(); -} - // Returns a string version of the method state. const char* nmethod::state() const { int state = get_state(); @@ -762,7 +754,7 @@ Method* nmethod::attached_method_before_pc(address pc) { } void nmethod::clear_inline_caches() { - assert(SafepointSynchronize::is_at_safepoint(), "clearing of IC's only allowed at safepoint"); + assert(SafepointSynchronize::is_at_safepoint() || (NMethodState_lock->owned_by_self() && is_not_installed()), "clearing of IC's only allowed at safepoint or when not installed"); RelocIterator iter(this); while (iter.next()) { iter.reloc()->clear_inline_cache(); @@ -791,15 +783,9 @@ class CheckClass : public MetadataClosure { }; #endif // ASSERT - -static void clean_ic_if_metadata_is_dead(CompiledIC *ic) { - ic->clean_metadata(); -} - // Clean references to unloaded nmethods at addr from this one, which is not unloaded. template -static void clean_if_nmethod_is_unloaded(CallsiteT* callsite, nmethod* from, - bool clean_all) { +static void clean_if_nmethod_is_unloaded(CallsiteT* callsite, bool clean_all) { CodeBlob* cb = CodeCache::find_blob(callsite->destination()); if (!cb->is_nmethod()) { return; @@ -874,15 +860,15 @@ void nmethod::cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all if (unloading_occurred) { // If class unloading occurred we first clear ICs where the cached metadata // is referring to an unloaded klass or method. - clean_ic_if_metadata_is_dead(CompiledIC_at(&iter)); + CompiledIC_at(&iter)->clean_metadata(); } - clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this, clean_all); + clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), clean_all); break; case relocInfo::opt_virtual_call_type: case relocInfo::static_call_type: - clean_if_nmethod_is_unloaded(CompiledDirectCall::at(iter.reloc()), this, clean_all); + clean_if_nmethod_is_unloaded(CompiledDirectCall::at(iter.reloc()), clean_all); break; case relocInfo::static_stub_type: { @@ -1160,7 +1146,8 @@ nmethod* nmethod::new_nmethod(const methodHandle& method, #if INCLUDE_JVMCI + align_up(speculations_len , oopSize) #endif - + align_up(debug_info->data_size() , oopSize); + + align_up(debug_info->data_size() , oopSize) + + align_up(ImmutableDataReferencesCounterSize, oopSize); // First, allocate space for immutable data in C heap. address immutable_data = nullptr; @@ -1237,7 +1224,6 @@ void nmethod::init_defaults(CodeBuffer *code_buffer, CodeOffsets* offsets) { _state = not_installed; _has_unsafe_access = 0; - _has_method_handle_invokes = 0; _has_wide_vectors = 0; _has_monitors = 0; _has_scoped_access = 0; @@ -1316,7 +1302,6 @@ nmethod::nmethod( // Native wrappers do not have deopt handlers. Make the values // something that will never match a pc like the nmethod vtable entry _deopt_handler_offset = 0; - _deopt_mh_handler_offset = 0; _unwind_handler_offset = 0; CHECKED_CAST(_oops_size, uint16_t, align_up(code_buffer->total_oop_size(), oopSize)); @@ -1387,10 +1372,266 @@ nmethod::nmethod( } } + +nmethod::nmethod(const nmethod &nm) : CodeBlob(nm._name, nm._kind, nm._size, nm._header_size) +{ + + if (nm._oop_maps != nullptr) { + _oop_maps = nm._oop_maps->clone(); + } else { + _oop_maps = nullptr; + } + + _size = nm._size; + _relocation_size = nm._relocation_size; + _content_offset = nm._content_offset; + _code_offset = nm._code_offset; + _data_offset = nm._data_offset; + _frame_size = nm._frame_size; + + S390_ONLY( _ctable_offset = nm._ctable_offset; ) + + _header_size = nm._header_size; + _frame_complete_offset = nm._frame_complete_offset; + + _kind = nm._kind; + + _caller_must_gc_arguments = nm._caller_must_gc_arguments; + +#ifndef PRODUCT + _asm_remarks.share(nm._asm_remarks); + _dbg_strings.share(nm._dbg_strings); +#endif + + // Allocate memory and copy mutable data to C heap + _mutable_data_size = nm._mutable_data_size; + if (_mutable_data_size > 0) { + _mutable_data = (address)os::malloc(_mutable_data_size, mtCode); + if (_mutable_data == nullptr) { + vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "nmethod: no space for mutable data"); + } + memcpy(mutable_data_begin(), nm.mutable_data_begin(), nm.mutable_data_size()); + } else { + _mutable_data = nullptr; + } + + _deoptimization_generation = 0; + _gc_epoch = CodeCache::gc_epoch(); + _method = nm._method; + _osr_link = nullptr; + + // Increment number of references to immutable data to share it between nmethods + _immutable_data_size = nm._immutable_data_size; + if (_immutable_data_size > 0) { + _immutable_data = nm._immutable_data; + set_immutable_data_references_counter(get_immutable_data_references_counter() + 1); + } else { + _immutable_data = blob_end(); + } + + _exception_cache = nullptr; + _gc_data = nullptr; + _oops_do_mark_nmethods = nullptr; + _oops_do_mark_link = nullptr; + _compiled_ic_data = nullptr; + + if (nm._osr_entry_point != nullptr) { + _osr_entry_point = (nm._osr_entry_point - (address) &nm) + (address) this; + } else { + _osr_entry_point = nullptr; + } + + _entry_offset = nm._entry_offset; + _verified_entry_offset = nm._verified_entry_offset; + _entry_bci = nm._entry_bci; + + _skipped_instructions_size = nm._skipped_instructions_size; + _stub_offset = nm._stub_offset; + _exception_offset = nm._exception_offset; + _deopt_handler_offset = nm._deopt_handler_offset; + _unwind_handler_offset = nm._unwind_handler_offset; + _num_stack_arg_slots = nm._num_stack_arg_slots; + _oops_size = nm._oops_size; +#if INCLUDE_JVMCI + _metadata_size = nm._metadata_size; +#endif + _nul_chk_table_offset = nm._nul_chk_table_offset; + _handler_table_offset = nm._handler_table_offset; + _scopes_pcs_offset = nm._scopes_pcs_offset; + _scopes_data_offset = nm._scopes_data_offset; +#if INCLUDE_JVMCI + _speculations_offset = nm._speculations_offset; +#endif + + _orig_pc_offset = nm._orig_pc_offset; + _compile_id = nm._compile_id; + _comp_level = nm._comp_level; + _compiler_type = nm._compiler_type; + _is_unloading_state = nm._is_unloading_state; + _state = not_installed; + + _has_unsafe_access = nm._has_unsafe_access; + _has_wide_vectors = nm._has_wide_vectors; + _has_monitors = nm._has_monitors; + _has_scoped_access = nm._has_scoped_access; + _has_flushed_dependencies = nm._has_flushed_dependencies; + _is_unlinked = nm._is_unlinked; + _load_reported = nm._load_reported; + + _deoptimization_status = nm._deoptimization_status; + + if (nm._pc_desc_container != nullptr) { + _pc_desc_container = new PcDescContainer(scopes_pcs_begin()); + } else { + _pc_desc_container = nullptr; + } + + // Copy nmethod contents excluding header + // - Constant part (doubles, longs and floats used in nmethod) + // - Code part: + // - Code body + // - Exception handler + // - Stub code + // - OOP table + memcpy(consts_begin(), nm.consts_begin(), nm.data_end() - nm.consts_begin()); + + post_init(); +} + +nmethod* nmethod::relocate(CodeBlobType code_blob_type) { + assert(NMethodRelocation, "must enable use of function"); + + // Locks required to be held by caller to ensure the nmethod + // is not modified or purged from code cache during relocation + assert_lock_strong(CodeCache_lock); + assert_lock_strong(Compile_lock); + assert(CompiledICLocker::is_safe(this), "mt unsafe call"); + + if (!is_relocatable()) { + return nullptr; + } + + run_nmethod_entry_barrier(); + nmethod* nm_copy = new (size(), code_blob_type) nmethod(*this); + + if (nm_copy == nullptr) { + 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 + // class hierarchy above the loaded class, checking only nmethods + // which are dependent on those classes. The slow way is to + // check every nmethod for dependencies which makes it linear in + // the number of methods compiled. For applications with a lot + // classes the slow way is too slow. + for (Dependencies::DepStream deps(nm_copy); deps.next(); ) { + if (deps.type() == Dependencies::call_site_target_value) { + // CallSite dependencies are managed on per-CallSite instance basis. + oop call_site = deps.argument_oop(0); + MethodHandles::add_dependent_nmethod(call_site, nm_copy); + } else { + InstanceKlass* ik = deps.context_type(); + if (ik == nullptr) { + continue; // ignore things like evol_method + } + // record this nmethod as dependent on this klass + ik->add_dependent_nmethod(nm_copy); + } + } + + MutexLocker ml_NMethodState_lock(NMethodState_lock, Mutex::_no_safepoint_check_flag); + + // Verify the nm we copied from is still valid + 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()); + + methodHandle mh(Thread::current(), nm_copy->method()); + nm_copy->method()->set_code(mh, nm_copy); + + make_not_used(); + + nm_copy->post_compiled_method_load_event(); + + nm_copy->log_relocated_nmethod(this); + + return nm_copy; + } + } + + nm_copy->make_not_used(); + + return nullptr; +} + +bool nmethod::is_relocatable() { + if (!is_java_method()) { + return false; + } + + if (!is_in_use()) { + return false; + } + + if (is_osr_method()) { + return false; + } + + if (is_marked_for_deoptimization()) { + return false; + } + +#if INCLUDE_JVMCI + if (jvmci_nmethod_data() != nullptr && jvmci_nmethod_data()->has_mirror()) { + return false; + } +#endif + + if (is_unloading()) { + return false; + } + + if (has_evol_metadata()) { + return false; + } + + return true; +} + void* nmethod::operator new(size_t size, int nmethod_size, int comp_level) throw () { return CodeCache::allocate(nmethod_size, CodeCache::get_code_blob_type(comp_level)); } +void* nmethod::operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw () { + return CodeCache::allocate(nmethod_size, code_blob_type); +} + void* nmethod::operator new(size_t size, int nmethod_size, bool allow_NonNMethod_space) throw () { // Try MethodNonProfiled and MethodProfiled. void* return_value = CodeCache::allocate(nmethod_size, CodeBlobType::MethodNonProfiled); @@ -1464,11 +1705,6 @@ nmethod::nmethod( } else { _deopt_handler_offset = -1; } - if (offsets->value(CodeOffsets::DeoptMH) != -1) { - _deopt_mh_handler_offset = code_offset() + offsets->value(CodeOffsets::DeoptMH); - } else { - _deopt_mh_handler_offset = -1; - } } else #endif { @@ -1478,11 +1714,6 @@ nmethod::nmethod( _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions); _deopt_handler_offset = _stub_offset + offsets->value(CodeOffsets::Deopt); - if (offsets->value(CodeOffsets::DeoptMH) != -1) { - _deopt_mh_handler_offset = _stub_offset + offsets->value(CodeOffsets::DeoptMH); - } else { - _deopt_mh_handler_offset = -1; - } } if (offsets->value(CodeOffsets::UnwindHandler) != -1) { // C1 generates UnwindHandler at the end of instructions section. @@ -1520,9 +1751,9 @@ nmethod::nmethod( #if INCLUDE_JVMCI _speculations_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); - DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _speculations_offset + align_up(speculations_len, oopSize) + align_up(ImmutableDataReferencesCounterSize, oopSize); ) #else - DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize); ) + DEBUG_ONLY( int immutable_data_end_offset = _scopes_data_offset + align_up(debug_info->data_size(), oopSize) + align_up(ImmutableDataReferencesCounterSize, oopSize); ) #endif assert(immutable_data_end_offset <= immutable_data_size, "wrong read-only data size: %d > %d", immutable_data_end_offset, immutable_data_size); @@ -1555,6 +1786,7 @@ nmethod::nmethod( memcpy(speculations_begin(), speculations, speculations_len); } #endif + set_immutable_data_references_counter(1); post_init(); @@ -1621,6 +1853,40 @@ void nmethod::log_new_nmethod() const { } } + +void nmethod::log_relocated_nmethod(nmethod* original) const { + if (LogCompilation && xtty != nullptr) { + ttyLocker ttyl; + xtty->begin_elem("relocated nmethod"); + log_identity(xtty); + xtty->print(" entry='" INTPTR_FORMAT "' size='%d'", p2i(code_begin()), size()); + + const char* original_code_heap_name = CodeCache::get_code_heap_name(CodeCache::get_code_blob_type(original)); + xtty->print(" original_address='" INTPTR_FORMAT "'", p2i(original)); + xtty->print(" original_code_heap='%s'", original_code_heap_name); + + const char* new_code_heap_name = CodeCache::get_code_heap_name(CodeCache::get_code_blob_type(this)); + xtty->print(" new_address='" INTPTR_FORMAT "'", p2i(this)); + xtty->print(" new_code_heap='%s'", new_code_heap_name); + + LOG_OFFSET(xtty, relocation); + LOG_OFFSET(xtty, consts); + LOG_OFFSET(xtty, insts); + LOG_OFFSET(xtty, stub); + LOG_OFFSET(xtty, scopes_data); + LOG_OFFSET(xtty, scopes_pcs); + LOG_OFFSET(xtty, dependencies); + LOG_OFFSET(xtty, handler_table); + LOG_OFFSET(xtty, nul_chk_table); + LOG_OFFSET(xtty, oops); + LOG_OFFSET(xtty, metadata); + + xtty->method(method()); + xtty->stamp(); + xtty->end_elem(); + } +} + #undef LOG_OFFSET @@ -2153,9 +2419,18 @@ void nmethod::purge(bool unregister_nmethod) { delete[] _compiled_ic_data; if (_immutable_data != blob_end()) { - os::free(_immutable_data); + int reference_count = get_immutable_data_references_counter(); + assert(reference_count > 0, "immutable data has no references"); + + set_immutable_data_references_counter(reference_count - 1); + // Free memory if this is the last nmethod referencing immutable data + if (reference_count == 0) { + os::free(_immutable_data); + } + _immutable_data = blob_end(); // Valid not null address } + if (unregister_nmethod) { Universe::heap()->unregister_nmethod(this); } @@ -2699,15 +2974,6 @@ void nmethod::copy_scopes_pcs(PcDesc* pcs, int count) { "must end with a sentinel"); #endif //ASSERT - // Search for MethodHandle invokes and tag the nmethod. - for (int i = 0; i < count; i++) { - if (pcs[i].is_method_handle_invoke()) { - set_has_method_handle_invokes(true); - break; - } - } - assert(has_method_handle_invokes() == (_deopt_mh_handler_offset != -1), "must have deopt mh handler"); - int size = count * sizeof(PcDesc); assert(scopes_pcs_size() >= size, "oob"); memcpy(scopes_pcs_begin(), pcs, size); @@ -3717,7 +3983,6 @@ const char* nmethod::nmethod_section_label(address pos) const { if (pos == code_begin()) label = "[Instructions begin]"; if (pos == entry_point()) label = "[Entry Point]"; if (pos == verified_entry_point()) label = "[Verified Entry Point]"; - if (has_method_handle_invokes() && (pos == deopt_mh_handler_begin())) label = "[Deopt MH Handler Code]"; if (pos == consts_begin() && pos != insts_begin()) label = "[Constants]"; // Check stub_code before checking exception_handler or deopt_handler. if (pos == this->stub_begin()) label = "[Stub Code]"; diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 3abda6010b7..2332766a47c 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -90,7 +90,6 @@ class ExceptionCache : public CHeapObj { // cache pc descs found in earlier inquiries class PcDescCache { - friend class VMStructs; private: enum { cache_size = 4 }; // The array elements MUST be volatile! Several threads may modify @@ -155,6 +154,7 @@ class PcDescContainer : public CHeapObj { // - Scopes data array // - Scopes pcs array // - JVMCI speculations array +// - Nmethod reference counter #if INCLUDE_JVMCI class FailedSpeculation; @@ -168,6 +168,8 @@ class nmethod : public CodeBlob { friend class JVMCINMethodData; friend class DeoptimizationScope; + #define ImmutableDataReferencesCounterSize ((int)sizeof(int)) + private: // Used to track in which deoptimize handshake this method will be deoptimized. @@ -227,9 +229,6 @@ class nmethod : public CodeBlob { // All deoptee's will resume execution at this location described by // this offset. int _deopt_handler_offset; - // All deoptee's at a MethodHandle call site will resume execution - // at this location described by this offset. - int _deopt_mh_handler_offset; // Offset (from insts_end) of the unwind handler if it exists int16_t _unwind_handler_offset; // Number of arguments passed on the stack @@ -268,7 +267,6 @@ class nmethod : public CodeBlob { // set during construction uint8_t _has_unsafe_access:1, // May fault due to unsafe access. - _has_method_handle_invokes:1,// Has this method MethodHandle invokes? _has_wide_vectors:1, // Preserve wide vectors at safepoints _has_monitors:1, // Fastpath monitor detection for continuations _has_scoped_access:1, // used by for shared scope closure (scopedMemoryAccess.cpp) @@ -335,8 +333,11 @@ class nmethod : public CodeBlob { #endif ); + nmethod(const nmethod &nm); + // helper methods void* operator new(size_t size, int nmethod_size, int comp_level) throw(); + void* operator new(size_t size, int nmethod_size, CodeBlobType code_blob_type) throw(); // For method handle intrinsics: Try MethodNonProfiled, MethodProfiled and NonNMethod. // Attention: Only allow NonNMethod space for special nmethods which don't need to be @@ -569,6 +570,12 @@ class nmethod : public CodeBlob { #endif ); + // Relocate the nmethod to the code heap identified by code_blob_type. + // Returns nullptr if the code heap does not have enough space, the + // nmethod is unrelocatable, or the nmethod is invalidated during relocation, + // otherwise the relocated nmethod. The original nmethod will be marked not entrant. + nmethod* relocate(CodeBlobType code_blob_type); + static nmethod* new_native_nmethod(const methodHandle& method, int compile_id, CodeBuffer *code_buffer, @@ -585,6 +592,8 @@ class nmethod : public CodeBlob { bool is_java_method () const { return _method != nullptr && !_method->is_native(); } bool is_osr_method () const { return _entry_bci != InvocationEntryBci; } + bool is_relocatable(); + // Compiler task identification. Note that all OSR methods // are numbered in an independent sequence if CICountOSR is true, // and native method wrappers are also numbered independently if @@ -607,7 +616,6 @@ class nmethod : public CodeBlob { address stub_end () const { return code_end() ; } address exception_begin () const { return header_begin() + _exception_offset ; } address deopt_handler_begin () const { return header_begin() + _deopt_handler_offset ; } - address deopt_mh_handler_begin() const { return header_begin() + _deopt_mh_handler_offset ; } address unwind_handler_begin () const { return _unwind_handler_offset != -1 ? (insts_end() - _unwind_handler_offset) : nullptr; } oop* oops_begin () const { return (oop*) data_begin(); } oop* oops_end () const { return (oop*) data_end(); } @@ -638,11 +646,13 @@ class nmethod : public CodeBlob { #if INCLUDE_JVMCI address scopes_data_end () const { return _immutable_data + _speculations_offset ; } address speculations_begin () const { return _immutable_data + _speculations_offset ; } - address speculations_end () const { return immutable_data_end(); } + address speculations_end () const { return immutable_data_end() - ImmutableDataReferencesCounterSize ; } #else - address scopes_data_end () const { return immutable_data_end(); } + address scopes_data_end () const { return immutable_data_end() - ImmutableDataReferencesCounterSize ; } #endif + address immutable_data_references_counter_begin () const { return immutable_data_end() - ImmutableDataReferencesCounterSize ; } + // Sizes int immutable_data_size() const { return _immutable_data_size; } int consts_size () const { return int( consts_end () - consts_begin ()); } @@ -746,9 +756,6 @@ class nmethod : public CodeBlob { bool has_scoped_access() const { return _has_scoped_access; } void set_has_scoped_access(bool z) { _has_scoped_access = z; } - bool has_method_handle_invokes() const { return _has_method_handle_invokes; } - void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } - bool has_wide_vectors() const { return _has_wide_vectors; } void set_has_wide_vectors(bool z) { _has_wide_vectors = z; } @@ -819,12 +826,9 @@ class nmethod : public CodeBlob { ExceptionCache* exception_cache_entry_for_exception(Handle exception); - // MethodHandle - bool is_method_handle_return(address return_pc); // Deopt // Return true is the PC is one would expect if the frame is being deopted. inline bool is_deopt_pc(address pc); - inline bool is_deopt_mh_entry(address pc); inline bool is_deopt_entry(address pc); // Accessor/mutator for the original pc of a frame before a frame was deopted. @@ -958,6 +962,9 @@ class nmethod : public CodeBlob { bool load_reported() const { return _load_reported; } void set_load_reported() { _load_reported = true; } + inline int get_immutable_data_references_counter() { return *((int*)immutable_data_references_counter_begin()); } + inline void set_immutable_data_references_counter(int count) { *((int*)immutable_data_references_counter_begin()) = count; } + public: // ScopeDesc retrieval operation PcDesc* pc_desc_at(address pc) { return find_pc_desc(pc, false); } @@ -1026,6 +1033,7 @@ class nmethod : public CodeBlob { // Logging void log_identity(xmlStream* log) const; void log_new_nmethod() const; + void log_relocated_nmethod(nmethod* original) const; void log_state_change(InvalidationReason invalidation_reason) const; // Prints block-level comments, including nmethod specific block labels: @@ -1080,4 +1088,13 @@ class nmethod : public CodeBlob { static const Vptr _vpntr; }; +struct NMethodMarkingScope : StackObj { + NMethodMarkingScope() { + nmethod::oops_do_marking_prologue(); + } + ~NMethodMarkingScope() { + nmethod::oops_do_marking_epilogue(); + } +}; + #endif // SHARE_CODE_NMETHOD_HPP diff --git a/src/hotspot/share/code/nmethod.inline.hpp b/src/hotspot/share/code/nmethod.inline.hpp index 62c8eb723ea..44331db669c 100644 --- a/src/hotspot/share/code/nmethod.inline.hpp +++ b/src/hotspot/share/code/nmethod.inline.hpp @@ -31,16 +31,12 @@ #include "runtime/atomicAccess.hpp" #include "runtime/frame.hpp" -inline bool nmethod::is_deopt_pc(address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); } +inline bool nmethod::is_deopt_pc(address pc) { return is_deopt_entry(pc); } inline bool nmethod::is_deopt_entry(address pc) { return pc == deopt_handler_begin(); } -inline bool nmethod::is_deopt_mh_entry(address pc) { - return pc == deopt_mh_handler_begin(); -} - // class ExceptionCache methods inline int ExceptionCache::count() { return AtomicAccess::load_acquire(&_count); } diff --git a/src/hotspot/share/code/pcDesc.hpp b/src/hotspot/share/code/pcDesc.hpp index 8048c3909c7..d8abe19ad35 100644 --- a/src/hotspot/share/code/pcDesc.hpp +++ b/src/hotspot/share/code/pcDesc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,11 +40,10 @@ class PcDesc { enum { PCDESC_reexecute = 1 << 0, - PCDESC_is_method_handle_invoke = 1 << 1, - PCDESC_return_oop = 1 << 2, - PCDESC_rethrow_exception = 1 << 3, - PCDESC_has_ea_local_in_scope = 1 << 4, - PCDESC_arg_escape = 1 << 5 + PCDESC_return_oop = 1 << 1, + PCDESC_rethrow_exception = 1 << 2, + PCDESC_has_ea_local_in_scope = 1 << 3, + PCDESC_arg_escape = 1 << 4 }; int _flags; @@ -85,9 +84,6 @@ class PcDesc { _flags == pd->_flags; } - bool is_method_handle_invoke() const { return (_flags & PCDESC_is_method_handle_invoke) != 0; } - void set_is_method_handle_invoke(bool z) { set_flag(PCDESC_is_method_handle_invoke, z); } - bool return_oop() const { return (_flags & PCDESC_return_oop) != 0; } void set_return_oop(bool z) { set_flag(PCDESC_return_oop, z); } diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 8fc22596d01..02a1e5faf16 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -406,11 +406,12 @@ void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer pd_set_call_destination(callee); } - #ifdef USE_TRAMPOLINE_STUB_FIX_OWNER void trampoline_stub_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { // Finalize owner destination only for nmethods if (dest->blob() != nullptr) return; + // We either relocate a nmethod residing in CodeCache or just generated code from CodeBuffer + assert(src->blob() == nullptr || nativeCall_at(owner())->raw_destination() == owner(), "destination should be empty"); pd_fix_owner_after_move(); } #endif diff --git a/src/hotspot/share/compiler/abstractCompiler.hpp b/src/hotspot/share/compiler/abstractCompiler.hpp index d61ae639c3f..adc85efbed5 100644 --- a/src/hotspot/share/compiler/abstractCompiler.hpp +++ b/src/hotspot/share/compiler/abstractCompiler.hpp @@ -33,8 +33,6 @@ typedef void (*initializer)(void); // Per-compiler statistics class CompilerStatistics { - friend class VMStructs; - class Data { friend class VMStructs; public: diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 226a6d3ad5c..574f4d6543b 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -1064,7 +1064,7 @@ void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) { if (new_c2_count <= old_c2_count && new_c1_count <= old_c1_count) return; // Now, we do the more expensive operations. - size_t free_memory = 0; + physical_memory_size_type free_memory = 0; // Return value ignored - defaulting to 0 on failure. (void)os::free_memory(free_memory); // If SegmentedCodeCache is off, both values refer to the single heap (with type CodeBlobType::All). diff --git a/src/hotspot/share/compiler/oopMap.cpp b/src/hotspot/share/compiler/oopMap.cpp index aa010872975..87467d06400 100644 --- a/src/hotspot/share/compiler/oopMap.cpp +++ b/src/hotspot/share/compiler/oopMap.cpp @@ -862,6 +862,12 @@ ImmutableOopMapSet* ImmutableOopMapSet::build_from(const OopMapSet* oopmap_set) return builder.build(); } +ImmutableOopMapSet* ImmutableOopMapSet::clone() const { + address buffer = NEW_C_HEAP_ARRAY(unsigned char, _size, mtCode); + memcpy(buffer, (address)this, _size); + return (ImmutableOopMapSet*)buffer; +} + void ImmutableOopMapSet::operator delete(void* p) { FREE_C_HEAP_ARRAY(unsigned char, p); } diff --git a/src/hotspot/share/compiler/oopMap.hpp b/src/hotspot/share/compiler/oopMap.hpp index 4b962444738..f7a8cd8496c 100644 --- a/src/hotspot/share/compiler/oopMap.hpp +++ b/src/hotspot/share/compiler/oopMap.hpp @@ -348,6 +348,8 @@ class ImmutableOopMapSet { static ImmutableOopMapSet* build_from(const OopMapSet* oopmap_set); + ImmutableOopMapSet* clone() const; + int find_slot_for_offset(int pc_offset) const; const ImmutableOopMap* find_map_at_offset(int pc_offset) const; const ImmutableOopMap* find_map_at_slot(int slot, int pc_offset) const; @@ -479,7 +481,6 @@ class OopMapDo { // pointers are updated based on their base pointers new value and an offset. #if COMPILER2_OR_JVMCI class DerivedPointerTable : public AllStatic { - friend class VMStructs; private: class Entry; static bool _active; // do not record pointers for verify pass etc. diff --git a/src/hotspot/share/gc/epsilon/epsilonBarrierSet.hpp b/src/hotspot/share/gc/epsilon/epsilonBarrierSet.hpp index 7a8083df6bb..c146ff39680 100644 --- a/src/hotspot/share/gc/epsilon/epsilonBarrierSet.hpp +++ b/src/hotspot/share/gc/epsilon/epsilonBarrierSet.hpp @@ -30,8 +30,6 @@ // No interaction with application is required for Epsilon, and therefore // the barrier set is empty. class EpsilonBarrierSet: public BarrierSet { - friend class VMStructs; - public: EpsilonBarrierSet(); diff --git a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp index 33a2690f777..51d0a8356d2 100644 --- a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp @@ -32,8 +32,6 @@ #include "services/memoryService.hpp" class EpsilonSpaceCounters: public CHeapObj { - friend class VMStructs; - private: PerfVariable* _capacity; PerfVariable* _used; diff --git a/src/hotspot/share/gc/g1/g1Allocator.hpp b/src/hotspot/share/gc/g1/g1Allocator.hpp index 8c382824b27..19b19c06e92 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.hpp +++ b/src/hotspot/share/gc/g1/g1Allocator.hpp @@ -37,8 +37,6 @@ class G1NUMA; // some accessors (e.g. allocating into them, or getting their occupancy). // Also keeps track of retained regions across GCs. class G1Allocator : public CHeapObj { - friend class VMStructs; - private: G1CollectedHeap* _g1h; G1NUMA* _numa; diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.hpp b/src/hotspot/share/gc/g1/g1BarrierSet.hpp index 40e87c373b7..20642cfc7e6 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSet.hpp +++ b/src/hotspot/share/gc/g1/g1BarrierSet.hpp @@ -62,7 +62,6 @@ class Thread; // cards. // class G1BarrierSet: public CardTableBarrierSet { - friend class VMStructs; private: BufferNode::Allocator _satb_mark_queue_buffer_allocator; G1SATBMarkQueueSet _satb_mark_queue_set; diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp index 59d5c4efcef..3b97efc4f0f 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp @@ -35,9 +35,7 @@ // into "N"-word subregions (where "N" = 2^"LogN". An array with an entry // for each such subregion indicates how far back one must go to find the // start of the chunk that includes the first word of the subregion. -class G1BlockOffsetTable: public CHeapObj { - friend class VMStructs; - +class G1BlockOffsetTable : public CHeapObj { private: // The reserved region covered by the table. MemRegion _reserved; diff --git a/src/hotspot/share/gc/g1/g1CardTable.hpp b/src/hotspot/share/gc/g1/g1CardTable.hpp index 060e5459778..ddbfa841c24 100644 --- a/src/hotspot/share/gc/g1/g1CardTable.hpp +++ b/src/hotspot/share/gc/g1/g1CardTable.hpp @@ -45,7 +45,6 @@ class G1CardTableChangedListener : public G1MappingChangedListener { }; class G1CardTable : public CardTable { - friend class VMStructs; friend class G1CardTableChangedListener; G1CardTableChangedListener _listener; diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 2368b5b4fc4..42122f42afb 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -64,7 +64,6 @@ #include "gc/g1/g1RemSet.hpp" #include "gc/g1/g1ReviseYoungLengthTask.hpp" #include "gc/g1/g1RootClosures.hpp" -#include "gc/g1/g1RootProcessor.hpp" #include "gc/g1/g1SATBMarkQueueSet.hpp" #include "gc/g1/g1ServiceThread.hpp" #include "gc/g1/g1ThreadLocalData.hpp" @@ -2669,8 +2668,7 @@ void G1CollectedHeap::do_collection_pause_at_safepoint_helper(size_t allocation_ } void G1CollectedHeap::complete_cleaning(bool class_unloading_occurred) { - uint num_workers = workers()->active_workers(); - G1ParallelCleaningTask unlink_task(num_workers, class_unloading_occurred); + G1ParallelCleaningTask unlink_task(class_unloading_occurred); workers()->run_task(&unlink_task); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.hpp index 5f9ec4ef404..22be7d9ffbb 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.hpp @@ -33,8 +33,6 @@ class G1Policy; // The concurrent mark thread triggers the various steps of the concurrent marking // cycle, including various marking cleanup. class G1ConcurrentMarkThread: public ConcurrentGCThread { - friend class VMStructs; - G1ConcurrentMark* _cm; enum ServiceState : uint { diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.hpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.hpp index 8e635247cd3..7cdc001d348 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.hpp @@ -36,7 +36,6 @@ class G1ConcurrentRefine; // Concurrent refinement control thread watching card mark accrual on the card table // and starting refinement work. class G1ConcurrentRefineThread: public ConcurrentGCThread { - friend class VMStructs; friend class G1CollectedHeap; Monitor _notifier; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index 023216f989d..0f78e0d6271 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -40,8 +40,6 @@ class G1CSetCandidateGroup; class outputStream; class G1HeapRegionRemSet : public CHeapObj { - friend class VMStructs; - // A set of nmethods whose code contains pointers into // the region that owns this RSet. G1CodeRootSet _code_roots; diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index 21b3545f7e0..a64989e3755 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -343,7 +343,7 @@ void G1HeapVerifier::verify(VerifyOption vo) { G1VerifyCodeRootNMethodClosure blobsCl(&codeRootsCl); { - G1RootProcessor root_processor(_g1h, 1); + G1RootProcessor root_processor(_g1h, false /* is_parallel */); root_processor.process_all_roots(&rootsCl, &cldCl, &blobsCl); } diff --git a/src/hotspot/share/gc/g1/g1NUMA.cpp b/src/hotspot/share/gc/g1/g1NUMA.cpp index cd7dc55d0fe..778ed31d7b5 100644 --- a/src/hotspot/share/gc/g1/g1NUMA.cpp +++ b/src/hotspot/share/gc/g1/g1NUMA.cpp @@ -203,9 +203,7 @@ uint G1NUMA::index_for_region(G1HeapRegion* hr) const { // * G1HeapRegion #: |-#0-||-#1-||-#2-||-#3-||-#4-||-#5-||-#6-||-#7-||-#8-||-#9-||#10-||#11-||#12-||#13-||#14-||#15-| // * NUMA node #: |----#0----||----#1----||----#2----||----#3----||----#0----||----#1----||----#2----||----#3----| void G1NUMA::request_memory_on_node(void* aligned_address, size_t size_in_bytes, uint region_index) { - if (!is_enabled()) { - return; - } + assert(is_enabled(), "must be, check before"); if (size_in_bytes == 0) { return; diff --git a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.hpp b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.hpp index 303acf62d0b..15155c1d668 100644 --- a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.hpp +++ b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.hpp @@ -45,7 +45,6 @@ class WorkerThreads; // The implementation gives an error when trying to commit or uncommit pages that // have already been committed or uncommitted. class G1PageBasedVirtualSpace { - friend class VMStructs; private: // Reserved area addresses. char* _low_boundary; diff --git a/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp b/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp index 884a2b2ca55..8d5e2a3239c 100644 --- a/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp +++ b/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp @@ -50,11 +50,10 @@ void JVMCICleaningTask::work(bool unloading_occurred) { } #endif // INCLUDE_JVMCI -G1ParallelCleaningTask::G1ParallelCleaningTask(uint num_workers, - bool unloading_occurred) : +G1ParallelCleaningTask::G1ParallelCleaningTask(bool unloading_occurred) : WorkerTask("G1 Parallel Cleaning"), _unloading_occurred(unloading_occurred), - _code_cache_task(num_workers, unloading_occurred), + _code_cache_task(unloading_occurred), JVMCI_ONLY(_jvmci_cleaning_task() COMMA) _klass_cleaning_task() { } diff --git a/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp b/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp index df9b1dddf6c..1a4e4601827 100644 --- a/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp +++ b/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp @@ -54,8 +54,7 @@ class G1ParallelCleaningTask : public WorkerTask { public: // The constructor is run in the VMThread. - G1ParallelCleaningTask(uint num_workers, - bool unloading_occurred); + G1ParallelCleaningTask(bool unloading_occurred); void work(uint worker_id); }; diff --git a/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp b/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp index afbd0f35ce6..0a7367fcab5 100644 --- a/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp +++ b/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp @@ -54,11 +54,17 @@ bool G1PeriodicGCTask::should_start_periodic_gc(G1CollectedHeap* g1h, // Check if load is lower than max. double recent_load; - if ((G1PeriodicGCSystemLoadThreshold > 0.0f) && - (os::loadavg(&recent_load, 1) == -1 || recent_load > G1PeriodicGCSystemLoadThreshold)) { - log_debug(gc, periodic)("Load %1.2f is higher than threshold %1.2f. Skipping.", - recent_load, G1PeriodicGCSystemLoadThreshold); - return false; + if (G1PeriodicGCSystemLoadThreshold > 0.0) { + if (os::loadavg(&recent_load, 1) == -1) { + G1PeriodicGCSystemLoadThreshold = 0.0; + log_warning(gc, periodic)("System loadavg() call failed, " + "disabling G1PeriodicGCSystemLoadThreshold check."); + // Fall through and start the periodic GC. + } else if (recent_load > G1PeriodicGCSystemLoadThreshold) { + log_debug(gc, periodic)("Load %1.2f is higher than threshold %1.2f. Skipping.", + recent_load, G1PeriodicGCSystemLoadThreshold); + return false; + } } // Record counters with GC safepoints blocked, to get a consistent snapshot. diff --git a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp index 1710ceaf73a..5e37c7fa5a1 100644 --- a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp +++ b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp @@ -96,13 +96,15 @@ class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper { const size_t start_page = (size_t)start_idx * _pages_per_region; const size_t size_in_pages = num_regions * _pages_per_region; bool zero_filled = _storage.commit(start_page, size_in_pages); - if (_memory_tag == mtJavaHeap) { + + if (should_distribute_across_numa_nodes()) { for (uint region_index = start_idx; region_index < start_idx + num_regions; region_index++ ) { void* address = _storage.page_start(region_index * _pages_per_region); size_t size_in_bytes = _storage.page_size() * _pages_per_region; G1NUMA::numa()->request_memory_on_node(address, size_in_bytes, region_index); } } + if (AlwaysPreTouch) { _storage.pretouch(start_page, size_in_pages, pretouch_workers); } @@ -122,7 +124,7 @@ class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper { // G1RegionToSpaceMapper implementation where the region granularity is smaller // than the commit granularity. -// Basically, the contents of one OS page span several regions. +// Basically, the contents of one OS page spans several regions. class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { size_t _regions_per_page; // Lock to prevent bitmap updates and the actual underlying @@ -148,13 +150,18 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { return _region_commit_map.find_first_set_bit(region, region_limit) != region_limit; } - void numa_request_on_node(size_t page_idx) { - if (_memory_tag == mtJavaHeap) { - uint region = (uint)(page_idx * _regions_per_page); - void* address = _storage.page_start(page_idx); - size_t size_in_bytes = _storage.page_size(); - G1NUMA::numa()->request_memory_on_node(address, size_in_bytes, region); + bool commit_pages(size_t start_page, size_t size_in_pages) { + bool result = _storage.commit(start_page, size_in_pages); + + if (should_distribute_across_numa_nodes()) { + for (size_t page = start_page; page < start_page + size_in_pages; page++) { + uint region = checked_cast(page * _regions_per_page); + void* address = _storage.page_start(page); + size_t size_in_bytes = _storage.page_size(); + G1NUMA::numa()->request_memory_on_node(address, size_in_bytes, region); + } } + return result; } public: @@ -171,6 +178,21 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { guarantee((page_size * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); } + size_t find_first_uncommitted(size_t page, size_t end) { + assert(page < end, "must be"); + while (page < end && is_page_committed(page)) { + page++; + } + return page; + } + + size_t find_first_committed(size_t page, size_t end) { + while (page < end && !is_page_committed(page)) { + page++; + } + return MIN2(page, end); + } + virtual void commit_regions(uint start_idx, size_t num_regions, WorkerThreads* pretouch_workers) { uint region_limit = (uint)(start_idx + num_regions); assert(num_regions > 0, "Must commit at least one region"); @@ -179,11 +201,11 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { size_t const NoPage = SIZE_MAX; - size_t first_committed = NoPage; - size_t num_committed = 0; + size_t first_newly_committed = NoPage; + size_t num_committed_pages = 0; - size_t start_page = region_idx_to_page_idx(start_idx); - size_t end_page = region_idx_to_page_idx(region_limit - 1); + size_t const start_page = region_idx_to_page_idx(start_idx); + size_t const end_page = region_idx_to_page_idx(region_limit - 1) + 1; bool all_zero_filled = true; @@ -191,34 +213,27 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { // underlying OS page. See lock declaration for more details. { MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag); - for (size_t page = start_page; page <= end_page; page++) { - if (!is_page_committed(page)) { - // Page not committed. - if (num_committed == 0) { - first_committed = page; - } - num_committed++; - - if (!_storage.commit(page, 1)) { - // Found dirty region during commit. - all_zero_filled = false; - } - - // Move memory to correct NUMA node for the heap. - numa_request_on_node(page); - } else { - // Page already committed. - all_zero_filled = false; - } + + size_t uncommitted_l = find_first_uncommitted(start_page, end_page); + size_t uncommitted_r = find_first_committed(uncommitted_l + 1, end_page); + + first_newly_committed = uncommitted_l; + num_committed_pages = uncommitted_r - uncommitted_l; + + if (num_committed_pages > 0 && + !commit_pages(first_newly_committed, num_committed_pages)) { + all_zero_filled = false; } + all_zero_filled &= (uncommitted_l == start_page) && (uncommitted_r == end_page); + // Update the commit map for the given range. Not using the par_set_range // since updates to _region_commit_map for this mapper is protected by _lock. _region_commit_map.set_range(start_idx, region_limit, BitMap::unknown_range); } - if (AlwaysPreTouch && num_committed > 0) { - _storage.pretouch(first_committed, num_committed, pretouch_workers); + if (AlwaysPreTouch && num_committed_pages > 0) { + _storage.pretouch(first_newly_committed, num_committed_pages, pretouch_workers); } fire_on_commit(start_idx, num_regions, all_zero_filled); @@ -230,8 +245,8 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { assert(_region_commit_map.find_first_clear_bit(start_idx, region_limit) == region_limit, "Should only be committed regions in the range [%u, %u)", start_idx, region_limit); - size_t start_page = region_idx_to_page_idx(start_idx); - size_t end_page = region_idx_to_page_idx(region_limit - 1); + size_t const start_page = region_idx_to_page_idx(start_idx); + size_t const end_page = region_idx_to_page_idx(region_limit - 1) + 1; // Concurrent operations might operate on regions sharing the same // underlying OS page. See lock declaration for more details. @@ -240,13 +255,16 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { // updates to _region_commit_map for this mapper is protected by _lock. _region_commit_map.clear_range(start_idx, region_limit, BitMap::unknown_range); - for (size_t page = start_page; page <= end_page; page++) { - // We know all pages were committed before clearing the map. If the - // the page is still marked as committed after the clear we should - // not uncommit it. - if (!is_page_committed(page)) { - _storage.uncommit(page, 1); - } + // We know all pages were committed before clearing the map. If the + // the page is still marked as committed after the clear we should + // not uncommit it. + size_t uncommitted_l = find_first_uncommitted(start_page, end_page); + size_t uncommitted_r = find_first_committed(uncommitted_l + 1, end_page); + + size_t num_uncommitted_pages_found = uncommitted_r - uncommitted_l; + + if (num_uncommitted_pages_found > 0) { + _storage.uncommit(uncommitted_l, num_uncommitted_pages_found); } } }; @@ -257,6 +275,10 @@ void G1RegionToSpaceMapper::fire_on_commit(uint start_idx, size_t num_regions, b } } +bool G1RegionToSpaceMapper::should_distribute_across_numa_nodes() const { + return _memory_tag == mtJavaHeap && G1NUMA::numa()->is_enabled(); +} + G1RegionToSpaceMapper* G1RegionToSpaceMapper::create_mapper(ReservedSpace rs, size_t actual_size, size_t page_size, diff --git a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp index 823fa549f36..e2fc3d4fa04 100644 --- a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp +++ b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp @@ -58,6 +58,8 @@ class G1RegionToSpaceMapper : public CHeapObj { G1RegionToSpaceMapper(ReservedSpace rs, size_t used_size, size_t page_size, size_t region_granularity, size_t commit_factor, MemTag mem_tag); void fire_on_commit(uint start_idx, size_t num_regions, bool zero_filled); + + bool should_distribute_across_numa_nodes() const; public: MemRegion reserved() { return _storage.reserved(); } diff --git a/src/hotspot/share/gc/g1/g1RootProcessor.cpp b/src/hotspot/share/gc/g1/g1RootProcessor.cpp index cf28c53648d..dac237cb277 100644 --- a/src/hotspot/share/gc/g1/g1RootProcessor.cpp +++ b/src/hotspot/share/gc/g1/g1RootProcessor.cpp @@ -46,10 +46,12 @@ #include "utilities/enumIterator.hpp" #include "utilities/macros.hpp" -G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h, uint n_workers) : +G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h, bool is_parallel) : _g1h(g1h), _process_strong_tasks(G1RP_PS_NumElements), - _srs(n_workers) {} + _nmethod_marking_scope(), + _threads_claim_token_scope(), + _is_parallel(is_parallel) {} void G1RootProcessor::evacuate_roots(G1ParScanThreadState* pss, uint worker_id) { G1GCPhaseTimes* phase_times = _g1h->phase_times(); @@ -175,8 +177,7 @@ void G1RootProcessor::process_java_roots(G1RootClosures* closures, // oops_do_process_weak and oops_do_process_strong in nmethod.hpp { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ThreadRoots, worker_id); - bool is_par = n_workers() > 1; - Threads::possibly_parallel_oops_do(is_par, + Threads::possibly_parallel_oops_do(_is_parallel, closures->strong_oops(), closures->strong_nmethods()); } @@ -209,7 +210,3 @@ void G1RootProcessor::process_code_cache_roots(NMethodClosure* nmethod_closure, CodeCache::nmethods_do(nmethod_closure); } } - -uint G1RootProcessor::n_workers() const { - return _srs.n_threads(); -} diff --git a/src/hotspot/share/gc/g1/g1RootProcessor.hpp b/src/hotspot/share/gc/g1/g1RootProcessor.hpp index 2313fd62f20..27c92d730cf 100644 --- a/src/hotspot/share/gc/g1/g1RootProcessor.hpp +++ b/src/hotspot/share/gc/g1/g1RootProcessor.hpp @@ -25,10 +25,11 @@ #ifndef SHARE_GC_G1_G1ROOTPROCESSOR_HPP #define SHARE_GC_G1_G1ROOTPROCESSOR_HPP +#include "code/nmethod.hpp" #include "gc/shared/oopStorageSetParState.hpp" -#include "gc/shared/strongRootsScope.hpp" #include "memory/allocation.hpp" #include "runtime/mutex.hpp" +#include "runtime/threads.hpp" class CLDClosure; class G1CollectedHeap; @@ -48,7 +49,9 @@ class SubTasksDone; class G1RootProcessor : public StackObj { G1CollectedHeap* _g1h; SubTasksDone _process_strong_tasks; - StrongRootsScope _srs; + NMethodMarkingScope _nmethod_marking_scope; + ThreadsClaimTokenScope _threads_claim_token_scope; + bool _is_parallel; OopStorageSetStrongParState _oop_storage_set_strong_par_state; enum G1H_process_roots_tasks { @@ -72,7 +75,7 @@ class G1RootProcessor : public StackObj { uint worker_id); public: - G1RootProcessor(G1CollectedHeap* g1h, uint n_workers); + G1RootProcessor(G1CollectedHeap* g1h, bool is_parallel); // Apply correct closures from pss to the strongly and weakly reachable roots in the system // in a single pass. @@ -88,9 +91,6 @@ class G1RootProcessor : public StackObj { void process_all_roots(OopClosure* oops, CLDClosure* clds, NMethodClosure* nmethods); - - // Number of worker threads used by the root processor. - uint n_workers() const; }; #endif // SHARE_GC_G1_G1ROOTPROCESSOR_HPP diff --git a/src/hotspot/share/gc/g1/g1ThreadLocalData.hpp b/src/hotspot/share/gc/g1/g1ThreadLocalData.hpp index 858081b0581..07c8c569504 100644 --- a/src/hotspot/share/gc/g1/g1ThreadLocalData.hpp +++ b/src/hotspot/share/gc/g1/g1ThreadLocalData.hpp @@ -36,6 +36,15 @@ class G1ThreadLocalData { private: SATBMarkQueue _satb_mark_queue; + // The current base address of the card table. Accessed by the barrier to do + // the card mark. Changed as required by the refinement control thread to + // implement card table switching. + // + // Tests showed that embedding this value in the TLS block is the cheapest + // way for fast access to this value in the barrier. + // E.g. embedding an address to that value directly into the code stream and + // then loading from that was found to be slower on non-x64 architectures. + // Additionally it increases code size a lot. G1CardTable::CardValue* _byte_map_base; // Per-thread cache of pinned object count to reduce atomic operation traffic diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 6a7d4717a6f..54ff46cb259 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -52,6 +52,7 @@ #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/referenceProcessor.hpp" +#include "gc/shared/strongRootsScope.hpp" #include "gc/shared/weakProcessor.inline.hpp" #include "gc/shared/workerPolicy.hpp" #include "gc/shared/workerThread.hpp" @@ -750,7 +751,7 @@ void G1YoungCollector::evacuate_initial_collection_set(G1ParScanThreadStateSet* Ticks start_processing = Ticks::now(); { - G1RootProcessor root_processor(_g1h, num_workers); + G1RootProcessor root_processor(_g1h, num_workers > 1 /* is_parallel */); G1EvacuateRegionsTask g1_par_task(_g1h, per_thread_states, task_queues(), diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp index 08569fd5bd1..df4312ebd75 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp @@ -118,73 +118,30 @@ size_t MutableNUMASpace::free_in_words() const { return s; } -int MutableNUMASpace::lgrp_space_index(int lgrp_id) const { - return lgrp_spaces()->find_if([&](LGRPSpace* space) { - return space->lgrp_id() == checked_cast(lgrp_id); +MutableNUMASpace::LGRPSpace *MutableNUMASpace::lgrp_space_for_thread(Thread* thr) const { + guarantee(thr != nullptr, "No thread"); + + int lgrp_id = thr->lgrp_id(); + assert(lgrp_id != -1, "lgrp_id must be set during thread creation"); + + int lgrp_spaces_index = lgrp_spaces()->find_if([&](LGRPSpace* space) { + return space->lgrp_id() == (uint)lgrp_id; }); + + assert(lgrp_spaces_index != -1, "must have created spaces for all lgrp_ids"); + return lgrp_spaces()->at(lgrp_spaces_index); } size_t MutableNUMASpace::tlab_capacity(Thread *thr) const { - guarantee(thr != nullptr, "No thread"); - int lgrp_id = thr->lgrp_id(); - if (lgrp_id == -1) { - // This case can occur after the topology of the system has - // changed. Thread can change their location, the new home - // group will be determined during the first allocation - // attempt. For now we can safely assume that all spaces - // have equal size because the whole space will be reinitialized. - if (lgrp_spaces()->length() > 0) { - return capacity_in_bytes() / lgrp_spaces()->length(); - } else { - assert(false, "There should be at least one locality group"); - return 0; - } - } - // That's the normal case, where we know the locality group of the thread. - int i = lgrp_space_index(lgrp_id); - if (i == -1) { - return 0; - } - return lgrp_spaces()->at(i)->space()->capacity_in_bytes(); + return lgrp_space_for_thread(thr)->space()->capacity_in_bytes(); } size_t MutableNUMASpace::tlab_used(Thread *thr) const { - // Please see the comments for tlab_capacity(). - guarantee(thr != nullptr, "No thread"); - int lgrp_id = thr->lgrp_id(); - if (lgrp_id == -1) { - if (lgrp_spaces()->length() > 0) { - return (used_in_bytes()) / lgrp_spaces()->length(); - } else { - assert(false, "There should be at least one locality group"); - return 0; - } - } - int i = lgrp_space_index(lgrp_id); - if (i == -1) { - return 0; - } - return lgrp_spaces()->at(i)->space()->used_in_bytes(); + return lgrp_space_for_thread(thr)->space()->used_in_bytes(); } - size_t MutableNUMASpace::unsafe_max_tlab_alloc(Thread *thr) const { - // Please see the comments for tlab_capacity(). - guarantee(thr != nullptr, "No thread"); - int lgrp_id = thr->lgrp_id(); - if (lgrp_id == -1) { - if (lgrp_spaces()->length() > 0) { - return free_in_bytes() / lgrp_spaces()->length(); - } else { - assert(false, "There should be at least one locality group"); - return 0; - } - } - int i = lgrp_space_index(lgrp_id); - if (i == -1) { - return 0; - } - return lgrp_spaces()->at(i)->space()->free_in_bytes(); + return lgrp_space_for_thread(thr)->space()->free_in_bytes(); } // Bias region towards the first-touching lgrp. Set the right page sizes. @@ -528,32 +485,13 @@ void MutableNUMASpace::clear(bool mangle_space) { } } -/* - Linux supports static memory binding, therefore the most part of the - logic dealing with the possible invalid page allocation is effectively - disabled. Besides there is no notion of the home node in Linux. A - thread is allowed to migrate freely. Although the scheduler is rather - reluctant to move threads between the nodes. We check for the current - node every allocation. And with a high probability a thread stays on - the same node for some time allowing local access to recently allocated - objects. - */ - HeapWord* MutableNUMASpace::cas_allocate(size_t size) { - Thread* thr = Thread::current(); - int lgrp_id = thr->lgrp_id(); - if (lgrp_id == -1 || !os::numa_has_group_homing()) { - lgrp_id = os::numa_get_group_id(); - thr->set_lgrp_id(lgrp_id); - } + Thread *thr = Thread::current(); - int i = lgrp_space_index(lgrp_id); - // It is possible that a new CPU has been hotplugged and - // we haven't reshaped the space accordingly. - if (i == -1) { - i = os::random() % lgrp_spaces()->length(); - } - LGRPSpace *ls = lgrp_spaces()->at(i); + // Update the locality group to match where the thread actually is. + thr->update_lgrp_id(); + + LGRPSpace *ls = lgrp_space_for_thread(thr); MutableSpace *s = ls->space(); HeapWord *p = s->cas_allocate(size); if (p != nullptr) { diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp index abb4c77952a..dc37b10292a 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp @@ -60,8 +60,6 @@ */ class MutableNUMASpace : public MutableSpace { - friend class VMStructs; - class LGRPSpace : public CHeapObj { uint _lgrp_id; MutableSpace* _space; @@ -152,7 +150,7 @@ class MutableNUMASpace : public MutableSpace { void select_tails(MemRegion new_region, MemRegion intersection, MemRegion* bottom_region, MemRegion *top_region); - int lgrp_space_index(int lgrp_id) const; + LGRPSpace *lgrp_space_for_thread(Thread *thr) const; public: GrowableArray* lgrp_spaces() const { return _lgrp_spaces; } diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index f4383e573af..5affa1a3e35 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -28,6 +28,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" +#include "code/nmethod.hpp" #include "compiler/oopMap.hpp" #include "gc/parallel/objectStartArray.inline.hpp" #include "gc/parallel/parallelArguments.hpp" @@ -61,7 +62,6 @@ #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" #include "gc/shared/spaceDecorator.hpp" -#include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" #include "gc/shared/weakProcessor.inline.hpp" #include "gc/shared/workerPolicy.hpp" @@ -1053,24 +1053,19 @@ bool PSParallelCompact::invoke(bool clear_all_soft_refs, bool should_do_max_comp } class PCAddThreadRootsMarkingTaskClosure : public ThreadClosure { -private: - uint _worker_id; + ParCompactionManager* _cm; public: - PCAddThreadRootsMarkingTaskClosure(uint worker_id) : _worker_id(worker_id) { } + PCAddThreadRootsMarkingTaskClosure(ParCompactionManager* cm) : _cm(cm) { } void do_thread(Thread* thread) { - assert(ParallelScavengeHeap::heap()->is_stw_gc_active(), "called outside gc"); - ResourceMark rm; - ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(_worker_id); - - MarkingNMethodClosure mark_and_push_in_blobs(&cm->_mark_and_push_closure); + MarkingNMethodClosure mark_and_push_in_blobs(&_cm->_mark_and_push_closure); - thread->oops_do(&cm->_mark_and_push_closure, &mark_and_push_in_blobs); + thread->oops_do(&_cm->_mark_and_push_closure, &mark_and_push_in_blobs); // Do the real work - cm->follow_marking_stacks(); + _cm->follow_marking_stacks(); } }; @@ -1090,7 +1085,8 @@ void steal_marking_work(TaskTerminator& terminator, uint worker_id) { } class MarkFromRootsTask : public WorkerTask { - StrongRootsScope _strong_roots_scope; // needed for Threads::possibly_parallel_threads_do + NMethodMarkingScope _nmethod_marking_scope; + ThreadsClaimTokenScope _threads_claim_token_scope; OopStorageSetStrongParState _oop_storage_set_par_state; TaskTerminator _terminator; uint _active_workers; @@ -1098,7 +1094,8 @@ class MarkFromRootsTask : public WorkerTask { public: MarkFromRootsTask(uint active_workers) : WorkerTask("MarkFromRootsTask"), - _strong_roots_scope(active_workers), + _nmethod_marking_scope(), + _threads_claim_token_scope(), _terminator(active_workers, ParCompactionManager::marking_stacks()), _active_workers(active_workers) {} @@ -1114,7 +1111,7 @@ class MarkFromRootsTask : public WorkerTask { } { - PCAddThreadRootsMarkingTaskClosure closure(worker_id); + PCAddThreadRootsMarkingTaskClosure closure(cm); Threads::possibly_parallel_threads_do(_active_workers > 1 /* is_par */, &closure); } @@ -1660,21 +1657,19 @@ static void compaction_with_stealing_work(TaskTerminator* terminator, uint worke } class FillDensePrefixAndCompactionTask: public WorkerTask { - uint _num_workers; TaskTerminator _terminator; public: FillDensePrefixAndCompactionTask(uint active_workers) : WorkerTask("FillDensePrefixAndCompactionTask"), - _num_workers(active_workers), _terminator(active_workers, ParCompactionManager::region_task_queues()) { } virtual void work(uint worker_id) { - { + if (worker_id == 0) { auto start = Ticks::now(); - PSParallelCompact::fill_dead_objs_in_dense_prefix(worker_id, _num_workers); - log_trace(gc, phases)("Fill dense prefix by worker %u: %.3f ms", worker_id, (Ticks::now() - start).seconds() * 1000); + PSParallelCompact::fill_dead_objs_in_dense_prefix(); + log_trace(gc, phases)("Fill dense prefix by worker 0: %.3f ms", (Ticks::now() - start).seconds() * 1000); } compaction_with_stealing_work(&_terminator, worker_id); } @@ -1687,9 +1682,10 @@ void PSParallelCompact::fill_range_in_dense_prefix(HeapWord* start, HeapWord* en assert(mark_bitmap()->find_obj_beg(start, end) == end, "precondition"); HeapWord* bottom = _space_info[old_space_id].space()->bottom(); if (start != bottom) { + // The preceding live obj. HeapWord* obj_start = mark_bitmap()->find_obj_beg_reverse(bottom, start); - HeapWord* after_obj = obj_start + cast_to_oop(obj_start)->size(); - assert(after_obj == start, "precondition"); + HeapWord* obj_end = obj_start + cast_to_oop(obj_start)->size(); + assert(obj_end == start, "precondition"); } } #endif @@ -1703,58 +1699,51 @@ void PSParallelCompact::fill_range_in_dense_prefix(HeapWord* start, HeapWord* en } while (addr < end); } -void PSParallelCompact::fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers) { +void PSParallelCompact::fill_dead_objs_in_dense_prefix() { ParMarkBitMap* bitmap = mark_bitmap(); HeapWord* const bottom = _space_info[old_space_id].space()->bottom(); HeapWord* const prefix_end = dense_prefix(old_space_id); - if (bottom == prefix_end) { - return; - } - - size_t bottom_region = _summary_data.addr_to_region_idx(bottom); - size_t prefix_end_region = _summary_data.addr_to_region_idx(prefix_end); + const size_t region_size = ParallelCompactData::RegionSize; - size_t start_region; - size_t end_region; - split_regions_for_worker(bottom_region, prefix_end_region, - worker_id, num_workers, - &start_region, &end_region); + // Fill dead space in [start_addr, end_addr) + HeapWord* const start_addr = bottom; + HeapWord* const end_addr = prefix_end; - if (start_region == end_region) { - return; - } - - HeapWord* const start_addr = _summary_data.region_to_addr(start_region); - HeapWord* const end_addr = _summary_data.region_to_addr(end_region); + for (HeapWord* cur_addr = start_addr; cur_addr < end_addr; /* empty */) { + RegionData* cur_region_ptr = _summary_data.addr_to_region_ptr(cur_addr); + if (cur_region_ptr->data_size() == region_size) { + // Full; no dead space. Next region. + if (_summary_data.is_region_aligned(cur_addr)) { + cur_addr += region_size; + } else { + cur_addr = _summary_data.region_align_up(cur_addr); + } + continue; + } - // Skip live partial obj (if any) from previous region. - HeapWord* cur_addr; - RegionData* start_region_ptr = _summary_data.region(start_region); - if (start_region_ptr->partial_obj_size() != 0) { - HeapWord* partial_obj_start = start_region_ptr->partial_obj_addr(); - assert(bitmap->is_marked(partial_obj_start), "inv"); - cur_addr = partial_obj_start + cast_to_oop(partial_obj_start)->size(); - } else { - cur_addr = start_addr; - } + // Fill dead space inside cur_region. + if (_summary_data.is_region_aligned(cur_addr)) { + cur_addr += cur_region_ptr->partial_obj_size(); + } - // end_addr is inclusive to handle regions starting with dead space. - while (cur_addr <= end_addr) { - // Use prefix_end to handle trailing obj in each worker region-chunk. - HeapWord* live_start = bitmap->find_obj_beg(cur_addr, prefix_end); - if (cur_addr != live_start) { - // Only worker 0 handles proceeding dead space. - if (cur_addr != start_addr || worker_id == 0) { + HeapWord* region_end_addr = _summary_data.region_align_up(cur_addr + 1); + assert(region_end_addr <= end_addr, "inv"); + while (cur_addr < region_end_addr) { + // Use end_addr to allow filler-obj to cross region boundary. + HeapWord* live_start = bitmap->find_obj_beg(cur_addr, end_addr); + if (cur_addr != live_start) { + // Found dead space [cur_addr, live_start). fill_range_in_dense_prefix(cur_addr, live_start); } + if (live_start >= region_end_addr) { + cur_addr = live_start; + break; + } + assert(bitmap->is_marked(live_start), "inv"); + cur_addr = live_start + cast_to_oop(live_start)->size(); } - if (live_start >= end_addr) { - break; - } - assert(bitmap->is_marked(live_start), "inv"); - cur_addr = live_start + cast_to_oop(live_start)->size(); } } @@ -1787,15 +1776,38 @@ void PSParallelCompact::compact() { void PSParallelCompact::verify_filler_in_dense_prefix() { HeapWord* bottom = _space_info[old_space_id].space()->bottom(); HeapWord* dense_prefix_end = dense_prefix(old_space_id); - HeapWord* cur_addr = bottom; - while (cur_addr < dense_prefix_end) { - oop obj = cast_to_oop(cur_addr); - oopDesc::verify(obj); - if (!mark_bitmap()->is_marked(cur_addr)) { - Klass* k = cast_to_oop(cur_addr)->klass(); - assert(k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass(), "inv"); + + const size_t region_size = ParallelCompactData::RegionSize; + + for (HeapWord* cur_addr = bottom; cur_addr < dense_prefix_end; /* empty */) { + RegionData* cur_region_ptr = _summary_data.addr_to_region_ptr(cur_addr); + if (cur_region_ptr->data_size() == region_size) { + // Full; no dead space. Next region. + if (_summary_data.is_region_aligned(cur_addr)) { + cur_addr += region_size; + } else { + cur_addr = _summary_data.region_align_up(cur_addr); + } + continue; + } + + // This region contains filler objs. + if (_summary_data.is_region_aligned(cur_addr)) { + cur_addr += cur_region_ptr->partial_obj_size(); + } + + HeapWord* region_end_addr = _summary_data.region_align_up(cur_addr + 1); + assert(region_end_addr <= dense_prefix_end, "inv"); + + while (cur_addr < region_end_addr) { + oop obj = cast_to_oop(cur_addr); + oopDesc::verify(obj); + if (!mark_bitmap()->is_marked(cur_addr)) { + Klass* k = cast_to_oop(cur_addr)->klass(); + assert(k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass(), "inv"); + } + cur_addr += obj->size(); } - cur_addr += obj->size(); } } diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 4d212499b4c..2297d720b35 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -755,7 +755,7 @@ class PSParallelCompact : AllStatic { static void fill_range_in_dense_prefix(HeapWord* start, HeapWord* end); public: - static void fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers); + static void fill_dead_objs_in_dense_prefix(); // This method invokes a full collection. // clear_all_soft_refs controls whether soft-refs should be cleared or not. diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index 7d3a1682519..9808a55335d 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -102,8 +102,6 @@ class PSPromotionManager { void process_array_chunk(PartialArrayState* state, bool stolen); void push_objArray(oop old_obj, oop new_obj); - void push_depth(ScannerTask task); - inline void promotion_trace_event(oop new_obj, Klass* klass, size_t obj_size, uint age, bool tenured, const PSPromotionLAB* lab); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 4c12a4c357f..fb58c22cf29 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -50,10 +50,6 @@ inline PSPromotionManager* PSPromotionManager::manager_array(uint index) { return &_manager_array[index]; } -inline void PSPromotionManager::push_depth(ScannerTask task) { - claimed_stack_depth()->push(task); -} - template inline void PSPromotionManager::claim_or_forward_depth(T* p) { assert(ParallelScavengeHeap::heap()->is_in(p), "pointer outside heap"); @@ -62,7 +58,7 @@ inline void PSPromotionManager::claim_or_forward_depth(T* p) { oop obj = CompressedOops::decode_not_null(heap_oop); assert(!PSScavenge::is_obj_in_to_space(obj), "revisiting object?"); Prefetch::write(obj->base_addr(), oopDesc::mark_offset_in_bytes()); - push_depth(ScannerTask(p)); + claimed_stack_depth()->push(ScannerTask(p)); } } diff --git a/src/hotspot/share/gc/parallel/psYoungGen.cpp b/src/hotspot/share/gc/parallel/psYoungGen.cpp index 21d023f8207..c26fdf4740c 100644 --- a/src/hotspot/share/gc/parallel/psYoungGen.cpp +++ b/src/hotspot/share/gc/parallel/psYoungGen.cpp @@ -250,6 +250,12 @@ void PSYoungGen::space_invariants() { bool PSYoungGen::try_expand_to_hold(size_t word_size) { assert(eden_space()->free_in_words() < word_size, "precondition"); + if (UseNUMA && !_eden_space->is_empty()) { + // Eden expansion is not supported with NUMA, when eden is not empty. + // See also MutableNUMASpace::initialize. + return false; + } + // For logging purpose size_t original_committed_size = virtual_space()->committed_size(); @@ -314,7 +320,7 @@ HeapWord* PSYoungGen::expand_and_allocate(size_t word_size) { } HeapWord* result = eden_space()->cas_allocate(word_size); - assert(result, "inv"); + assert(result || UseNUMA, "inv"); return result; } diff --git a/src/hotspot/share/gc/serial/cSpaceCounters.hpp b/src/hotspot/share/gc/serial/cSpaceCounters.hpp index b378f379afe..14c68e2b397 100644 --- a/src/hotspot/share/gc/serial/cSpaceCounters.hpp +++ b/src/hotspot/share/gc/serial/cSpaceCounters.hpp @@ -33,8 +33,6 @@ // that track a space; class CSpaceCounters: public CHeapObj { - friend class VMStructs; - private: PerfVariable* _capacity; PerfVariable* _used; diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index bcd131a5fa2..42f8b191f5e 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -807,7 +807,7 @@ void DefNewGeneration::reset_scratch() { } } -void DefNewGeneration::gc_epilogue(bool full) { +void DefNewGeneration::gc_epilogue() { assert(!GCLocker::is_active(), "We should not be executing here"); // update the generation and space performance counters update_counters(); diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index 7f4077873b2..32b6b32f42f 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -187,7 +187,7 @@ class DefNewGeneration: public Generation { HeapWord* allocate(size_t word_size); HeapWord* par_allocate(size_t word_size); - void gc_epilogue(bool full); + void gc_epilogue(); // For Old collection (part of running Full GC), the DefNewGeneration can // contribute the free part of "to-space" as the scratch space. diff --git a/src/hotspot/share/gc/serial/serialFullGC.cpp b/src/hotspot/share/gc/serial/serialFullGC.cpp index d45454a768f..76a335d209f 100644 --- a/src/hotspot/share/gc/serial/serialFullGC.cpp +++ b/src/hotspot/share/gc/serial/serialFullGC.cpp @@ -54,7 +54,6 @@ #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" #include "gc/shared/space.hpp" -#include "gc/shared/strongRootsScope.hpp" #include "gc/shared/weakProcessor.hpp" #include "memory/iterator.inline.hpp" #include "memory/universe.hpp" @@ -483,9 +482,7 @@ void SerialFullGC::phase1_mark(bool clear_all_softrefs) { ref_processor()->start_discovery(clear_all_softrefs); { - StrongRootsScope srs(0); - - MarkingNMethodClosure mark_code_closure(&follow_root_closure); + GCTraceTime(Debug, gc, phases) tm_m("Marking From Roots", gc_timer()); // Start tracing from roots, there are 3 kinds of roots in full-gc. // @@ -494,8 +491,13 @@ void SerialFullGC::phase1_mark(bool clear_all_softrefs) { // strong CLDs. ClassLoaderDataGraph::always_strong_cld_do(&follow_cld_closure); - // 2. Threads stack frames and active nmethods in them. - Threads::oops_do(&follow_root_closure, &mark_code_closure); + { + // 2. Threads stack frames and active nmethods in them. + NMethodMarkingScope nmethod_marking_scope; + MarkingNMethodClosure mark_code_closure(&follow_root_closure); + + Threads::oops_do(&follow_root_closure, &mark_code_closure); + } // 3. VM internal roots. OopStorageSet::strong_oops_do(&follow_root_closure); diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 89218648fe0..dbd54c302ea 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -779,7 +779,7 @@ void SerialHeap::gc_epilogue(bool full) { resize_all_tlabs(); - _young_gen->gc_epilogue(full); + _young_gen->gc_epilogue(); _old_gen->gc_epilogue(); if (_is_heap_almost_full) { diff --git a/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp b/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp index ac640fb88d2..a31078f7e67 100644 --- a/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp +++ b/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp @@ -38,6 +38,16 @@ #define __ gen->lir()-> #endif +// Return true iff an access to bt is single-copy atomic. + +// The JMM requires atomicity for all accesses to fields of primitive +// types other than double and long. In practice, HotSpot assumes that +// on all processors, accesses to memory operands of wordSize and +// smaller are atomic. +static bool access_is_atomic(BasicType bt) { + return type2aelembytes(bt) <= wordSize; +} + LIR_Opr BarrierSetC1::resolve_address(LIRAccess& access, bool resolve_in_register) { DecoratorSet decorators = access.decorators(); bool is_array = (decorators & IS_ARRAY) != 0; @@ -140,7 +150,7 @@ LIR_Opr BarrierSetC1::atomic_add_at(LIRAccess& access, LIRItem& value) { void BarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) { DecoratorSet decorators = access.decorators(); bool is_volatile = (decorators & MO_SEQ_CST) != 0; - bool is_atomic = is_volatile || AlwaysAtomicAccesses; + bool needs_atomic = AlwaysAtomicAccesses && !access_is_atomic(value->type()); bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0; bool mask_boolean = (decorators & C1_MASK_BOOLEAN) != 0; LIRGenerator* gen = access.gen(); @@ -154,7 +164,7 @@ void BarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) { } LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none; - if (is_atomic && !needs_patching) { + if ((is_volatile || needs_atomic) && !needs_patching) { gen->volatile_field_store(value, access.resolved_addr()->as_address_ptr(), access.access_emit_info()); } else { __ store(value, access.resolved_addr()->as_address_ptr(), access.access_emit_info(), patch_code); @@ -169,7 +179,7 @@ void BarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { LIRGenerator *gen = access.gen(); DecoratorSet decorators = access.decorators(); bool is_volatile = (decorators & MO_SEQ_CST) != 0; - bool is_atomic = is_volatile || AlwaysAtomicAccesses; + bool needs_atomic = AlwaysAtomicAccesses && !access_is_atomic(result->type()); bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0; bool mask_boolean = (decorators & C1_MASK_BOOLEAN) != 0; bool in_native = (decorators & IN_NATIVE) != 0; @@ -181,7 +191,7 @@ void BarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none; if (in_native) { __ move_wide(access.resolved_addr()->as_address_ptr(), result); - } else if (is_atomic && !needs_patching) { + } else if ((is_volatile || needs_atomic) && !needs_patching) { gen->volatile_field_load(access.resolved_addr()->as_address_ptr(), result, access.access_emit_info()); } else { __ load(access.resolved_addr()->as_address_ptr(), result, access.access_emit_info(), patch_code); diff --git a/src/hotspot/share/gc/shared/cardTable.hpp b/src/hotspot/share/gc/shared/cardTable.hpp index 63dcfe7aecb..ab26055e522 100644 --- a/src/hotspot/share/gc/shared/cardTable.hpp +++ b/src/hotspot/share/gc/shared/cardTable.hpp @@ -61,6 +61,20 @@ class CardTable: public CHeapObj { inline size_t compute_byte_map_size(size_t num_bytes); + // We use 0x00 (zero) to represent Dirty and 0xFF to represent Clean because + // this choice reduces the barrier code by one instruction on architectures with + // a constant-zero register. On such architectures, the Dirty value (0x00) is + // directly accessible through the zero register, eliminating the need to load + // the value explicitly and thereby saving one instruction + // + // E.g. see + // Urs Hölzle. A fast write barrier for generational garbage collectors. + // In Eliot Moss, Paul R. Wilson, and Benjamin Zorn, editors, OOPSLA/ECOOP '93 + // Workshop on Garbage Collection in Object-Oriented Systems, October 1993 + // + // that shows this for SPARC (but aarch32/aarch64/RISC-V are similar in this + // respect). + // enum CardValues { clean_card = (CardValue)-1, diff --git a/src/hotspot/share/gc/shared/collectorCounters.hpp b/src/hotspot/share/gc/shared/collectorCounters.hpp index 64e59db86e4..273f8fb2a4e 100644 --- a/src/hotspot/share/gc/shared/collectorCounters.hpp +++ b/src/hotspot/share/gc/shared/collectorCounters.hpp @@ -31,8 +31,6 @@ // that track a collector class CollectorCounters: public CHeapObj { - friend class VMStructs; - private: PerfCounter* _invocations; PerfCounter* _time; diff --git a/src/hotspot/share/gc/shared/gcInitLogger.cpp b/src/hotspot/share/gc/shared/gcInitLogger.cpp index 763c265b65e..ba639945860 100644 --- a/src/hotspot/share/gc/shared/gcInitLogger.cpp +++ b/src/hotspot/share/gc/shared/gcInitLogger.cpp @@ -62,8 +62,9 @@ void GCInitLogger::print_cpu() { } void GCInitLogger::print_memory() { - size_t memory = os::physical_memory(); - log_info_p(gc, init)("Memory: " PROPERFMT, PROPERFMTARGS(memory)); + physical_memory_size_type memory = os::physical_memory(); + log_info_p(gc, init)("Memory: " PHYS_MEM_TYPE_FORMAT "%s", + byte_size_in_proper_unit(memory), proper_unit_for_byte_size(memory)); } void GCInitLogger::print_large_pages() { diff --git a/src/hotspot/share/gc/shared/gcPolicyCounters.hpp b/src/hotspot/share/gc/shared/gcPolicyCounters.hpp index 1f8026d21ac..e2ddb537f6e 100644 --- a/src/hotspot/share/gc/shared/gcPolicyCounters.hpp +++ b/src/hotspot/share/gc/shared/gcPolicyCounters.hpp @@ -31,8 +31,6 @@ // that track a generation class GCPolicyCounters: public CHeapObj { - friend class VMStructs; - // Constant PerfData types don't need to retain a reference. // However, it's a good idea to document them here. // PerfStringConstant* _name; diff --git a/src/hotspot/share/gc/shared/generationCounters.hpp b/src/hotspot/share/gc/shared/generationCounters.hpp index cb835b44e25..3985f40a3aa 100644 --- a/src/hotspot/share/gc/shared/generationCounters.hpp +++ b/src/hotspot/share/gc/shared/generationCounters.hpp @@ -32,8 +32,6 @@ // that track a generation class GenerationCounters: public CHeapObj { - friend class VMStructs; - PerfVariable* _current_size; // Constant PerfData types don't need to retain a reference. diff --git a/src/hotspot/share/gc/shared/hSpaceCounters.hpp b/src/hotspot/share/gc/shared/hSpaceCounters.hpp index 01310e456f6..b55b24f7601 100644 --- a/src/hotspot/share/gc/shared/hSpaceCounters.hpp +++ b/src/hotspot/share/gc/shared/hSpaceCounters.hpp @@ -33,8 +33,6 @@ // that track a collections (logical spaces) in a heap; class HSpaceCounters: public CHeapObj { - friend class VMStructs; - private: PerfVariable* _capacity; PerfVariable* _used; diff --git a/src/hotspot/share/gc/shared/parallelCleaning.cpp b/src/hotspot/share/gc/shared/parallelCleaning.cpp index 9d496783ca2..e302085d0cc 100644 --- a/src/hotspot/share/gc/shared/parallelCleaning.cpp +++ b/src/hotspot/share/gc/shared/parallelCleaning.cpp @@ -27,12 +27,11 @@ #include "code/codeCache.hpp" #include "gc/shared/parallelCleaning.hpp" #include "logging/log.hpp" -#include "memory/resourceArea.hpp" +#include "oops/klass.inline.hpp" #include "runtime/atomicAccess.hpp" -CodeCacheUnloadingTask::CodeCacheUnloadingTask(uint num_workers, bool unloading_occurred) : +CodeCacheUnloadingTask::CodeCacheUnloadingTask(bool unloading_occurred) : _unloading_occurred(unloading_occurred), - _num_workers(num_workers), _first_nmethod(nullptr), _claimed_nmethod(nullptr) { // Get first alive nmethod @@ -94,38 +93,26 @@ void CodeCacheUnloadingTask::work(uint worker_id) { } } -KlassCleaningTask::KlassCleaningTask() : - _clean_klass_tree_claimed(false), - _klass_iterator() { -} - -bool KlassCleaningTask::claim_clean_klass_tree_task() { - if (_clean_klass_tree_claimed) { - return false; - } +void KlassCleaningTask::work() { + for (ClassLoaderData* cur = _cld_iterator_atomic.next(); cur != nullptr; cur = _cld_iterator_atomic.next()) { + class CleanKlasses : public KlassClosure { + public: - return !AtomicAccess::cmpxchg(&_clean_klass_tree_claimed, false, true); -} + void do_klass(Klass* klass) override { + klass->clean_subklass(true); -InstanceKlass* KlassCleaningTask::claim_next_klass() { - Klass* klass; - do { - klass =_klass_iterator.next_klass(); - } while (klass != nullptr && !klass->is_instance_klass()); + Klass* sibling = klass->next_sibling(true); + klass->set_next_sibling(sibling); - // this can be null so don't call InstanceKlass::cast - return static_cast(klass); -} + if (klass->is_instance_klass()) { + Klass::clean_weak_instanceklass_links(InstanceKlass::cast(klass)); + } -void KlassCleaningTask::work() { - // One worker will clean the subklass/sibling klass tree. - if (claim_clean_klass_tree_task()) { - Klass::clean_weak_klass_links(true /* class_unloading_occurred */, false /* clean_alive_klasses */); - } + assert(klass->subklass() == nullptr || klass->subklass()->is_loader_alive(), "must be"); + assert(klass->next_sibling(false) == nullptr || klass->next_sibling(false)->is_loader_alive(), "must be"); + } + } cl; - // All workers will help cleaning the classes, - InstanceKlass* klass; - while ((klass = claim_next_klass()) != nullptr) { - Klass::clean_weak_instanceklass_links(klass); + cur->classes_do(&cl); } } diff --git a/src/hotspot/share/gc/shared/parallelCleaning.hpp b/src/hotspot/share/gc/shared/parallelCleaning.hpp index 4a7c724fef5..e1b07f5778d 100644 --- a/src/hotspot/share/gc/shared/parallelCleaning.hpp +++ b/src/hotspot/share/gc/shared/parallelCleaning.hpp @@ -33,14 +33,13 @@ class CodeCacheUnloadingTask { const bool _unloading_occurred; - const uint _num_workers; // Variables used to claim nmethods. nmethod* _first_nmethod; nmethod* volatile _claimed_nmethod; public: - CodeCacheUnloadingTask(uint num_workers, bool unloading_occurred); + CodeCacheUnloadingTask(bool unloading_occurred); ~CodeCacheUnloadingTask(); private: @@ -54,14 +53,10 @@ class CodeCacheUnloadingTask { // Cleans out the Klass tree from stale data. class KlassCleaningTask : public StackObj { - volatile bool _clean_klass_tree_claimed; - ClassLoaderDataGraphKlassIteratorAtomic _klass_iterator; - - bool claim_clean_klass_tree_task(); - InstanceKlass* claim_next_klass(); + ClassLoaderDataGraphIteratorAtomic _cld_iterator_atomic; public: - KlassCleaningTask(); + KlassCleaningTask() : _cld_iterator_atomic() { } void work(); }; diff --git a/src/hotspot/share/gc/shared/scavengableNMethods.hpp b/src/hotspot/share/gc/shared/scavengableNMethods.hpp index 31093a0482c..00db556577e 100644 --- a/src/hotspot/share/gc/shared/scavengableNMethods.hpp +++ b/src/hotspot/share/gc/shared/scavengableNMethods.hpp @@ -33,8 +33,6 @@ class nmethod; class NMethodToOopClosure; class ScavengableNMethods : public AllStatic { - friend class VMStructs; - static nmethod* _head; static BoolObjectClosure* _is_scavengable; diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.hpp b/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.hpp index 504e1fe617f..b1feb1b4ca9 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.hpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupThread.hpp @@ -38,8 +38,6 @@ // not an inner class of StringDedup. This is because we need a simple public // identifier for use by VMStructs. class StringDedupThread : public JavaThread { - friend class VMStructs; - StringDedupThread(); ~StringDedupThread() = default; diff --git a/src/hotspot/share/gc/shared/strongRootsScope.cpp b/src/hotspot/share/gc/shared/strongRootsScope.cpp index 1316df68e5f..2130cd5f1c0 100644 --- a/src/hotspot/share/gc/shared/strongRootsScope.cpp +++ b/src/hotspot/share/gc/shared/strongRootsScope.cpp @@ -34,18 +34,3 @@ MarkScope::MarkScope() { MarkScope::~MarkScope() { nmethod::oops_do_marking_epilogue(); } - -StrongRootsScope::StrongRootsScope(uint n_threads) : _n_threads(n_threads) { - // No need for thread claim for statically-known sequential case (_n_threads == 0) - // For positive values, clients of this class often unify sequential/parallel - // cases, so they expect the thread claim token to be updated. - if (_n_threads != 0) { - Threads::change_thread_claim_token(); - } -} - -StrongRootsScope::~StrongRootsScope() { - if (_n_threads != 0) { - Threads::assert_all_threads_claimed(); - } -} diff --git a/src/hotspot/share/gc/shared/strongRootsScope.hpp b/src/hotspot/share/gc/shared/strongRootsScope.hpp index 2d33753e4b0..be6cb4b549f 100644 --- a/src/hotspot/share/gc/shared/strongRootsScope.hpp +++ b/src/hotspot/share/gc/shared/strongRootsScope.hpp @@ -33,17 +33,4 @@ class MarkScope : public StackObj { ~MarkScope(); }; -// Sets up and tears down the required state for sequential/parallel root processing. -class StrongRootsScope : public MarkScope { - // Number of threads participating in the roots processing. - // 0 means statically-known sequential root processing; used only by Serial GC - const uint _n_threads; - - public: - StrongRootsScope(uint n_threads); - ~StrongRootsScope(); - - uint n_threads() const { return _n_threads; } -}; - #endif // SHARE_GC_SHARED_STRONGROOTSSCOPE_HPP diff --git a/src/hotspot/share/gc/shared/workerUtils.hpp b/src/hotspot/share/gc/shared/workerUtils.hpp index 223dfb34eb2..5f167ffb6b2 100644 --- a/src/hotspot/share/gc/shared/workerUtils.hpp +++ b/src/hotspot/share/gc/shared/workerUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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,11 +27,12 @@ #include "memory/allocation.hpp" #include "metaprogramming/enableIf.hpp" -#include "metaprogramming/logical.hpp" #include "runtime/mutex.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +#include + // A class that acts as a synchronisation barrier. Workers enter // the barrier and must wait until all other workers have entered // before any of them may leave. @@ -103,7 +104,7 @@ class SubTasksDone: public CHeapObj { // explicitly passed as extra arguments. Every thread in the parallel task // must execute this. template...>::value)> + ENABLE_IF(std::conjunction_v...>)> void all_tasks_claimed(T0 first_skipped, Ts... more_skipped) { static_assert(std::is_convertible::value, "not convertible"); uint skipped[] = { static_cast(first_skipped), static_cast(more_skipped)... }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp index c3b99af8a80..86ff6f22c72 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp @@ -43,7 +43,7 @@ ShenandoahAgeCensus::ShenandoahAgeCensus(uint max_workers) ShenandoahGenerationalMinTenuringAge, ShenandoahGenerationalMaxTenuringAge)); } - _global_age_table = NEW_C_HEAP_ARRAY(AgeTable*, MAX_SNAPSHOTS, mtGC); + _global_age_tables = NEW_C_HEAP_ARRAY(AgeTable*, MAX_SNAPSHOTS, mtGC); CENSUS_NOISE(_global_noise = NEW_C_HEAP_ARRAY(ShenandoahNoiseStats, MAX_SNAPSHOTS, mtGC);) _tenuring_threshold = NEW_C_HEAP_ARRAY(uint, MAX_SNAPSHOTS, mtGC); CENSUS_NOISE(_skipped = 0); @@ -52,36 +52,40 @@ ShenandoahAgeCensus::ShenandoahAgeCensus(uint max_workers) for (int i = 0; i < MAX_SNAPSHOTS; i++) { // Note that we don't now get perfdata from age_table - _global_age_table[i] = new AgeTable(false); + _global_age_tables[i] = new AgeTable(false); CENSUS_NOISE(_global_noise[i].clear();) // Sentinel value _tenuring_threshold[i] = MAX_COHORTS; } if (ShenandoahGenerationalAdaptiveTenuring) { - _local_age_table = NEW_C_HEAP_ARRAY(AgeTable*, _max_workers, mtGC); + _local_age_tables = NEW_C_HEAP_ARRAY(AgeTable*, _max_workers, mtGC); CENSUS_NOISE(_local_noise = NEW_C_HEAP_ARRAY(ShenandoahNoiseStats, max_workers, mtGC);) for (uint i = 0; i < _max_workers; i++) { - _local_age_table[i] = new AgeTable(false); + _local_age_tables[i] = new AgeTable(false); CENSUS_NOISE(_local_noise[i].clear();) } } else { - _local_age_table = nullptr; + _local_age_tables = nullptr; + } + _epoch = MAX_SNAPSHOTS - 1; // see prepare_for_census_update() + + if (!ShenandoahGenerationalAdaptiveTenuring) { + _tenuring_threshold[_epoch] = InitialTenuringThreshold; } - _epoch = MAX_SNAPSHOTS - 1; // see update_epoch() } ShenandoahAgeCensus::~ShenandoahAgeCensus() { for (uint i = 0; i < MAX_SNAPSHOTS; i++) { - delete _global_age_table[i]; + delete _global_age_tables[i]; } - FREE_C_HEAP_ARRAY(AgeTable*, _global_age_table); + FREE_C_HEAP_ARRAY(AgeTable*, _global_age_tables); FREE_C_HEAP_ARRAY(uint, _tenuring_threshold); CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _global_noise)); - if (_local_age_table) { + if (_local_age_tables) { for (uint i = 0; i < _max_workers; i++) { - delete _local_age_table[i]; + delete _local_age_tables[i]; } - FREE_C_HEAP_ARRAY(AgeTable*, _local_age_table); + FREE_C_HEAP_ARRAY(AgeTable*, _local_age_tables); CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _local_noise)); } } @@ -142,37 +146,31 @@ void ShenandoahAgeCensus::prepare_for_census_update() { if (++_epoch >= MAX_SNAPSHOTS) { _epoch=0; } - _global_age_table[_epoch]->clear(); + _global_age_tables[_epoch]->clear(); CENSUS_NOISE(_global_noise[_epoch].clear();) } // Update the census data from appropriate sources, // and compute the new tenuring threshold. -void ShenandoahAgeCensus::update_census(size_t age0_pop, AgeTable* pv1, AgeTable* pv2) { +void ShenandoahAgeCensus::update_census(size_t age0_pop) { prepare_for_census_update(); - assert(_global_age_table[_epoch]->is_clear(), "Dirty decks"); + assert(ShenandoahGenerationalAdaptiveTenuring, "Only update census when adaptive tenuring is enabled"); + assert(_global_age_tables[_epoch]->is_clear(), "Dirty decks"); CENSUS_NOISE(assert(_global_noise[_epoch].is_clear(), "Dirty decks");) - if (ShenandoahGenerationalAdaptiveTenuring) { - assert(pv1 == nullptr && pv2 == nullptr, "Error, check caller"); - // Seed cohort 0 with population that may have been missed during - // regular census. - _global_age_table[_epoch]->add(0u, age0_pop); - // Merge data from local age tables into the global age table for the epoch, - // clearing the local tables. - for (uint i = 0; i < _max_workers; i++) { - // age stats - _global_age_table[_epoch]->merge(_local_age_table[i]); - _local_age_table[i]->clear(); // clear for next census - // Merge noise stats - CENSUS_NOISE(_global_noise[_epoch].merge(_local_noise[i]);) - CENSUS_NOISE(_local_noise[i].clear();) - } - } else { - // census during evac - assert(pv1 != nullptr && pv2 != nullptr, "Error, check caller"); - _global_age_table[_epoch]->merge(pv1); - _global_age_table[_epoch]->merge(pv2); + // Seed cohort 0 with population that may have been missed during + // regular census. + _global_age_tables[_epoch]->add(0u, age0_pop); + + // Merge data from local age tables into the global age table for the epoch, + // clearing the local tables. + for (uint i = 0; i < _max_workers; i++) { + // age stats + _global_age_tables[_epoch]->merge(_local_age_tables[i]); + _local_age_tables[i]->clear(); // clear for next census + // Merge noise stats + CENSUS_NOISE(_global_noise[_epoch].merge(_local_noise[i]);) + CENSUS_NOISE(_local_noise[i].clear();) } update_tenuring_threshold(); @@ -188,7 +186,7 @@ void ShenandoahAgeCensus::update_census(size_t age0_pop, AgeTable* pv1, AgeTable void ShenandoahAgeCensus::reset_global() { assert(_epoch < MAX_SNAPSHOTS, "Out of bounds"); for (uint i = 0; i < MAX_SNAPSHOTS; i++) { - _global_age_table[i]->clear(); + _global_age_tables[i]->clear(); CENSUS_NOISE(_global_noise[i].clear();) } _epoch = MAX_SNAPSHOTS; @@ -198,11 +196,11 @@ void ShenandoahAgeCensus::reset_global() { // Reset the local age tables, clearing any partial census. void ShenandoahAgeCensus::reset_local() { if (!ShenandoahGenerationalAdaptiveTenuring) { - assert(_local_age_table == nullptr, "Error"); + assert(_local_age_tables == nullptr, "Error"); return; } for (uint i = 0; i < _max_workers; i++) { - _local_age_table[i]->clear(); + _local_age_tables[i]->clear(); CENSUS_NOISE(_local_noise[i].clear();) } } @@ -212,7 +210,7 @@ void ShenandoahAgeCensus::reset_local() { bool ShenandoahAgeCensus::is_clear_global() { assert(_epoch < MAX_SNAPSHOTS, "Out of bounds"); for (uint i = 0; i < MAX_SNAPSHOTS; i++) { - bool clear = _global_age_table[i]->is_clear(); + bool clear = _global_age_tables[i]->is_clear(); CENSUS_NOISE(clear |= _global_noise[i].is_clear();) if (!clear) { return false; @@ -224,11 +222,11 @@ bool ShenandoahAgeCensus::is_clear_global() { // Is local census information clear? bool ShenandoahAgeCensus::is_clear_local() { if (!ShenandoahGenerationalAdaptiveTenuring) { - assert(_local_age_table == nullptr, "Error"); + assert(_local_age_tables == nullptr, "Error"); return true; } for (uint i = 0; i < _max_workers; i++) { - bool clear = _local_age_table[i]->is_clear(); + bool clear = _local_age_tables[i]->is_clear(); CENSUS_NOISE(clear |= _local_noise[i].is_clear();) if (!clear) { return false; @@ -240,7 +238,7 @@ bool ShenandoahAgeCensus::is_clear_local() { size_t ShenandoahAgeCensus::get_all_ages(uint snap) { assert(snap < MAX_SNAPSHOTS, "Out of bounds"); size_t pop = 0; - const AgeTable* pv = _global_age_table[snap]; + const AgeTable* pv = _global_age_tables[snap]; for (uint i = 0; i < MAX_COHORTS; i++) { pop += pv->sizes[i]; } @@ -260,13 +258,11 @@ void ShenandoahAgeCensus::update_total() { #endif // !PRODUCT void ShenandoahAgeCensus::update_tenuring_threshold() { - if (!ShenandoahGenerationalAdaptiveTenuring) { - _tenuring_threshold[_epoch] = InitialTenuringThreshold; - } else { - uint tt = compute_tenuring_threshold(); - assert(tt <= MAX_COHORTS, "Out of bounds"); - _tenuring_threshold[_epoch] = tt; - } + assert(ShenandoahGenerationalAdaptiveTenuring, "Only update when adaptive tenuring is enabled"); + uint tt = compute_tenuring_threshold(); + assert(tt <= MAX_COHORTS, "Out of bounds"); + _tenuring_threshold[_epoch] = tt; + print(); log_info(gc, age)("New tenuring threshold %zu (min %zu, max %zu)", (uintx) _tenuring_threshold[_epoch], ShenandoahGenerationalMinTenuringAge, ShenandoahGenerationalMaxTenuringAge); @@ -296,8 +292,8 @@ uint ShenandoahAgeCensus::compute_tenuring_threshold() { const uint prev_epoch = cur_epoch > 0 ? cur_epoch - 1 : markWord::max_age; // Current and previous population vectors in ring - const AgeTable* cur_pv = _global_age_table[cur_epoch]; - const AgeTable* prev_pv = _global_age_table[prev_epoch]; + const AgeTable* cur_pv = _global_age_tables[cur_epoch]; + const AgeTable* prev_pv = _global_age_tables[prev_epoch]; uint upper_bound = ShenandoahGenerationalMaxTenuringAge; const uint prev_tt = previous_tenuring_threshold(); if (ShenandoahGenerationalCensusIgnoreOlderCohorts && prev_tt > 0) { @@ -372,8 +368,8 @@ void ShenandoahAgeCensus::print() { const uint cur_epoch = _epoch; const uint prev_epoch = cur_epoch > 0 ? cur_epoch - 1: markWord::max_age; - const AgeTable* cur_pv = _global_age_table[cur_epoch]; - const AgeTable* prev_pv = _global_age_table[prev_epoch]; + const AgeTable* cur_pv = _global_age_tables[cur_epoch]; + const AgeTable* prev_pv = _global_age_tables[prev_epoch]; const uint tt = tenuring_threshold(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp index d862498c69d..39ea4ee9002 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp @@ -97,8 +97,8 @@ struct ShenandoahNoiseStats { // once the per-worker data is consolidated into the appropriate population vector // per minor collection. The _local_age_table is thus C x N, for N GC workers. class ShenandoahAgeCensus: public CHeapObj { - AgeTable** _global_age_table; // Global age table used for adapting tenuring threshold, one per snapshot - AgeTable** _local_age_table; // Local scratch age tables to track object ages, one per worker + AgeTable** _global_age_tables; // Global age tables used for adapting tenuring threshold, one per snapshot + AgeTable** _local_age_tables; // Local scratch age tables to track object ages, one per worker #ifdef SHENANDOAH_CENSUS_NOISE ShenandoahNoiseStats* _global_noise; // Noise stats, one per snapshot @@ -175,7 +175,7 @@ class ShenandoahAgeCensus: public CHeapObj { // Return the local age table (population vector) for worker_id. // Only used in the case of ShenandoahGenerationalAdaptiveTenuring AgeTable* get_local_age_table(uint worker_id) const { - return _local_age_table[worker_id]; + return _local_age_tables[worker_id]; } // Return the most recently computed tenuring threshold. @@ -209,11 +209,7 @@ class ShenandoahAgeCensus: public CHeapObj { // age0_pop is the population of Cohort 0 that may have been missed in // the regular census during the marking cycle, corresponding to objects // allocated when the concurrent marking was in progress. - // Optional parameters, pv1 and pv2 are population vectors that together - // provide object census data (only) for the case when - // ShenandoahGenerationalCensusAtEvac. In this case, the age0_pop - // is 0, because the evacuated objects have all had their ages incremented. - void update_census(size_t age0_pop, AgeTable* pv1 = nullptr, AgeTable* pv2 = nullptr); + void update_census(size_t age0_pop); // Reset the epoch, clearing accumulated census history // Note: this isn't currently used, but reserved for planned diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCardTable.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCardTable.hpp index 33a4705b8d2..69b5a1abf72 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCardTable.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCardTable.hpp @@ -33,8 +33,6 @@ #define ShenandoahMinCardSizeInBytes 128 class ShenandoahCardTable: public CardTable { - friend class VMStructs; - private: // We maintain two copies of the card table to facilitate concurrent remembered set scanning // and concurrent clearing of stale remembered set information. During the init_mark safepoint, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index facba2236be..005d6c42f8c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -25,7 +25,6 @@ #include "gc/shared/satbMarkQueue.hpp" -#include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" @@ -94,10 +93,12 @@ class ShenandoahFinalMarkingTask : public WorkerTask { ShenandoahConcurrentMark* _cm; TaskTerminator* _terminator; bool _dedup_string; + ThreadsClaimTokenScope _threads_claim_token_scope; // needed for Threads::possibly_parallel_threads_do public: ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) : - WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string) { + WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string), + _threads_claim_token_scope() { } void work(uint worker_id) { @@ -297,7 +298,6 @@ void ShenandoahConcurrentMark::finish_mark_work() { uint nworkers = heap->workers()->active_workers(); task_queues()->reserve(nworkers); - StrongRootsScope scope(nworkers); TaskTerminator terminator(nworkers, task_queues()); switch (_generation->type()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index f4005e45f39..590e7831f07 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -43,7 +43,8 @@ ShenandoahControlThread::ShenandoahControlThread() : ShenandoahController(), _requested_gc_cause(GCCause::_no_gc), - _degen_point(ShenandoahGC::_degenerated_outside_cycle) { + _degen_point(ShenandoahGC::_degenerated_outside_cycle), + _control_lock(Mutex::nosafepoint - 2, "ShenandoahGCRequest_lock", true) { set_name("Shenandoah Control Thread"); create_and_start(); } @@ -201,26 +202,8 @@ void ShenandoahControlThread::run_service() { heuristics->clear_metaspace_oom(); } - // Commit worker statistics to cycle data - heap->phase_timings()->flush_par_workers_to_cycle(); - - // Print GC stats for current cycle - { - LogTarget(Info, gc, stats) lt; - if (lt.is_enabled()) { - ResourceMark rm; - LogStream ls(lt); - heap->phase_timings()->print_cycle_on(&ls); - if (ShenandoahEvacTracking) { - ShenandoahEvacuationTracker* evac_tracker = heap->evac_tracker(); - ShenandoahCycleStats evac_stats = evac_tracker->flush_cycle_to_global(); - evac_tracker->print_evacuations_on(&ls, &evac_stats.workers, &evac_stats.mutators); - } - } - } - - // Commit statistics to globals - heap->phase_timings()->flush_cycle_to_global(); + // Manage and print gc stats + heap->process_gc_stats(); // Print Metaspace change following GC (if logging is enabled). MetaspaceUtils::print_metaspace_change(meta_sizes); @@ -246,7 +229,9 @@ void ShenandoahControlThread::run_service() { sleep = MIN2(ShenandoahControlIntervalMax, MAX2(1, sleep * 2)); last_sleep_adjust_time = current; } - os::naked_short_sleep(sleep); + + MonitorLocker ml(&_control_lock, Mutex::_no_safepoint_check_flag); + ml.wait(sleep); } } @@ -361,6 +346,16 @@ void ShenandoahControlThread::request_gc(GCCause::Cause cause) { } } +void ShenandoahControlThread::notify_control_thread(GCCause::Cause cause) { + // Although setting gc request is under _controller_lock, the read side (run_service()) + // does not take the lock. We need to enforce following order, so that read side sees + // latest requested gc cause when the flag is set. + MonitorLocker controller(&_control_lock, Mutex::_no_safepoint_check_flag); + _requested_gc_cause = cause; + _gc_requested.set(); + controller.notify(); +} + void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { if (should_terminate()) { log_info(gc)("Control thread is terminating, no more GCs"); @@ -372,8 +367,7 @@ void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { // The whitebox caller thread will arrange for itself to wait until the GC notifies // it that has reached the requested breakpoint (phase in the GC). if (cause == GCCause::_wb_breakpoint) { - _requested_gc_cause = cause; - _gc_requested.set(); + notify_control_thread(cause); return; } @@ -390,12 +384,7 @@ void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { size_t current_gc_id = get_gc_id(); size_t required_gc_id = current_gc_id + 1; while (current_gc_id < required_gc_id && !should_terminate()) { - // Although setting gc request is under _gc_waiters_lock, but read side (run_service()) - // does not take the lock. We need to enforce following order, so that read side sees - // latest requested gc cause when the flag is set. - _requested_gc_cause = cause; - _gc_requested.set(); - + notify_control_thread(cause); ml.wait(); current_gc_id = get_gc_id(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp index 9d95b5df7ed..c9bb6419201 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp @@ -33,8 +33,6 @@ #include "gc/shenandoah/shenandoahSharedVariables.hpp" class ShenandoahControlThread: public ShenandoahController { - friend class VMStructs; - private: typedef enum { none, @@ -47,6 +45,9 @@ class ShenandoahControlThread: public ShenandoahController { GCCause::Cause _requested_gc_cause; ShenandoahGC::ShenandoahDegenPoint _degen_point; + // This lock is used to coordinate waking up the control thread + Monitor _control_lock; + public: ShenandoahControlThread(); @@ -56,6 +57,8 @@ class ShenandoahControlThread: public ShenandoahController { void request_gc(GCCause::Cause cause) override; private: + // Sets the requested cause and flag and notifies the control thread + void notify_control_thread(GCCause::Cause cause); bool check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point); void service_concurrent_normal_cycle(GCCause::Cause cause); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp b/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp index bc8fad713af..72d0773eccd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp @@ -23,7 +23,6 @@ * */ -#include "gc/shenandoah/shenandoahAgeCensus.hpp" #include "gc/shenandoah/shenandoahEvacTracker.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" @@ -44,19 +43,6 @@ ShenandoahEvacuationStats::ShenandoahEvacuations* ShenandoahEvacuationStats::get return &_old; } -ShenandoahEvacuationStats::ShenandoahEvacuationStats() - : _use_age_table(!ShenandoahGenerationalAdaptiveTenuring), - _age_table(nullptr) { - if (_use_age_table) { - _age_table = new AgeTable(false); - } -} - -AgeTable* ShenandoahEvacuationStats::age_table() const { - assert(_use_age_table, "Don't call"); - return _age_table; -} - void ShenandoahEvacuationStats::begin_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) { ShenandoahEvacuations* category = get_category(from, to); category->_evacuations_attempted++; @@ -70,31 +56,16 @@ void ShenandoahEvacuationStats::end_evacuation(size_t bytes, ShenandoahAffiliati category->_bytes_completed += bytes; } -void ShenandoahEvacuationStats::record_age(size_t bytes, uint age) { - assert(_use_age_table, "Don't call!"); - if (age <= markWord::max_age) { // Filter age sentinel. - _age_table->add(age, bytes >> LogBytesPerWord); - } -} - void ShenandoahEvacuationStats::accumulate(const ShenandoahEvacuationStats* other) { _young.accumulate(other->_young); _old.accumulate(other->_old); _promotion.accumulate(other->_promotion); - - if (_use_age_table) { - _age_table->merge(other->age_table()); - } } void ShenandoahEvacuationStats::reset() { _young.reset(); _old.reset(); _promotion.reset(); - - if (_use_age_table) { - _age_table->clear(); - } } void ShenandoahEvacuationStats::ShenandoahEvacuations::print_on(outputStream* st) const { @@ -112,10 +83,6 @@ void ShenandoahEvacuationStats::print_on(outputStream* st) const { st->print("Promotion: "); _promotion.print_on(st); st->print("Old: "); _old.print_on(st); } - - if (_use_age_table) { - _age_table->print_on(st); - } } void ShenandoahEvacuationTracker::print_global_on(outputStream* st) { @@ -125,28 +92,13 @@ void ShenandoahEvacuationTracker::print_global_on(outputStream* st) { void ShenandoahEvacuationTracker::print_evacuations_on(outputStream* st, ShenandoahEvacuationStats* workers, ShenandoahEvacuationStats* mutators) { - if (ShenandoahEvacTracking) { - st->print_cr("Workers: "); - workers->print_on(st); - st->cr(); - st->print_cr("Mutators: "); - mutators->print_on(st); - st->cr(); - } - - ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (heap->mode()->is_generational()) { - AgeTable young_region_ages(false); - for (uint i = 0; i < heap->num_regions(); ++i) { - ShenandoahHeapRegion* r = heap->get_region(i); - if (r->is_young()) { - young_region_ages.add(r->age(), r->get_live_data_words()); - } - } - st->print("Young regions: "); - young_region_ages.print_on(st); - st->cr(); - } + assert(ShenandoahEvacTracking, "Only when evac tracking is enabled"); + st->print_cr("Workers: "); + workers->print_on(st); + st->cr(); + st->print_cr("Mutators: "); + mutators->print_on(st); + st->cr(); } class ShenandoahStatAggregator : public ThreadClosure { @@ -173,15 +125,6 @@ ShenandoahCycleStats ShenandoahEvacuationTracker::flush_cycle_to_global() { _mutators_global.accumulate(&mutators); _workers_global.accumulate(&workers); - if (!ShenandoahGenerationalAdaptiveTenuring) { - // Ingest mutator & worker collected population vectors into the heap's - // global census data, and use it to compute an appropriate tenuring threshold - // for use in the next cycle. - // The first argument is used for any age 0 cohort population that we may otherwise have - // missed during the census. This is non-zero only when census happens at marking. - ShenandoahGenerationalHeap::heap()->age_census()->update_census(0, mutators.age_table(), workers.age_table()); - } - return {workers, mutators}; } @@ -192,7 +135,3 @@ void ShenandoahEvacuationTracker::begin_evacuation(Thread* thread, size_t bytes, void ShenandoahEvacuationTracker::end_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) { ShenandoahThreadLocalData::end_evacuation(thread, bytes, from, to); } - -void ShenandoahEvacuationTracker::record_age(Thread* thread, size_t bytes, uint age) { - ShenandoahThreadLocalData::record_age(thread, bytes, age); -} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.hpp b/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.hpp index e5d7a7fec94..6e1182680a5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.hpp @@ -66,20 +66,12 @@ class ShenandoahEvacuationStats : public CHeapObj { ShenandoahEvacuations _old; ShenandoahEvacuations _promotion; - bool _use_age_table; - AgeTable* _age_table; - public: - ShenandoahEvacuationStats(); - - AgeTable* age_table() const; - // Record that the current thread is attempting to copy this many bytes. void begin_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to); // Record that the current thread has completed copying this many bytes. void end_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to); - void record_age(size_t bytes, uint age); void print_on(outputStream* st) const; void accumulate(const ShenandoahEvacuationStats* other); @@ -106,7 +98,6 @@ class ShenandoahEvacuationTracker : public CHeapObj { // Multiple threads may attempt to evacuate the same object, but only the successful thread will end the evacuation. // Evacuations that were begun, but not ended are considered 'abandoned'. void end_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to); - void record_age(Thread* thread, size_t bytes, uint age); void print_global_on(outputStream* st); void print_evacuations_on(outputStream* st, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index 761ba02d569..c6d1cf02ee2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -201,6 +201,24 @@ ShenandoahGenerationalControlThread::GCMode ShenandoahGenerationalControlThread: return request.generation->is_old() ? servicing_old : concurrent_normal; } +void ShenandoahGenerationalControlThread::maybe_print_young_region_ages() const { + LogTarget(Debug, gc, age) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + AgeTable young_region_ages(false); + for (uint i = 0; i < _heap->num_regions(); ++i) { + const ShenandoahHeapRegion* r = _heap->get_region(i); + if (r->is_young()) { + young_region_ages.add(r->age(), r->get_live_data_words()); + } + } + + ls.print("Young regions: "); + young_region_ages.print_on(&ls); + ls.cr(); + } +} + void ShenandoahGenerationalControlThread::maybe_set_aging_cycle() { if (_age_period-- == 0) { _heap->set_aging_cycle(true); @@ -298,7 +316,11 @@ void ShenandoahGenerationalControlThread::run_gc_cycle(const ShenandoahGCRequest _heap->global_generation()->heuristics()->clear_metaspace_oom(); } - process_phase_timings(); + // Manage and print gc stats + _heap->process_gc_stats(); + + // Print table for young region ages if log is enabled + maybe_print_young_region_ages(); // Print Metaspace change following GC (if logging is enabled). MetaspaceUtils::print_metaspace_change(meta_sizes); @@ -317,29 +339,6 @@ void ShenandoahGenerationalControlThread::run_gc_cycle(const ShenandoahGCRequest gc_mode_name(gc_mode()), GCCause::to_string(request.cause), request.generation->name(), GCCause::to_string(_heap->cancelled_cause())); } -void ShenandoahGenerationalControlThread::process_phase_timings() const { - // Commit worker statistics to cycle data - _heap->phase_timings()->flush_par_workers_to_cycle(); - - ShenandoahEvacuationTracker* evac_tracker = _heap->evac_tracker(); - ShenandoahCycleStats evac_stats = evac_tracker->flush_cycle_to_global(); - - // Print GC stats for current cycle - { - LogTarget(Info, gc, stats) lt; - if (lt.is_enabled()) { - ResourceMark rm; - LogStream ls(lt); - _heap->phase_timings()->print_cycle_on(&ls); - evac_tracker->print_evacuations_on(&ls, &evac_stats.workers, - &evac_stats.mutators); - } - } - - // Commit statistics to globals - _heap->phase_timings()->flush_cycle_to_global(); -} - // Young and old concurrent cycles are initiated by the regulator. Implicit // and explicit GC requests are handled by the controller thread and always // run a global cycle (which is concurrent by default, but may be overridden @@ -417,7 +416,7 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(const She set_gc_mode(bootstrapping_old); young_generation->set_old_gen_task_queues(old_generation->task_queues()); service_concurrent_cycle(young_generation, request.cause, true); - process_phase_timings(); + _heap->process_gc_stats(); if (_heap->cancelled_gc()) { // Young generation bootstrap cycle has failed. Concurrent mark for old generation // is going to resume after degenerated bootstrap cycle completes. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp index 1586205742a..b7dbedd5e84 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp @@ -38,8 +38,6 @@ class ShenandoahGenerationalHeap; class ShenandoahHeap; class ShenandoahGenerationalControlThread: public ShenandoahController { - friend class VMStructs; - public: typedef enum { none, @@ -129,9 +127,6 @@ class ShenandoahGenerationalControlThread: public ShenandoahController { // Returns true if the old generation marking was interrupted to allow a young cycle. bool preempt_old_marking(ShenandoahGeneration* generation); - // Flushes cycle timings to global timings and prints the phase timings for the last completed cycle. - void process_phase_timings() const; - // Set the gc mode and post a notification if it has changed. The overloaded variant should be used // when the _control_lock is already held. void set_gc_mode(GCMode new_mode); @@ -160,6 +155,9 @@ class ShenandoahGenerationalControlThread: public ShenandoahController { GCMode prepare_for_allocation_failure_gc(ShenandoahGCRequest &request); GCMode prepare_for_explicit_gc(ShenandoahGCRequest &request) const; GCMode prepare_for_concurrent_gc(const ShenandoahGCRequest &request) const; + + // Print table for young region ages if log is enabled + void maybe_print_young_region_ages() const; }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALCONTROLTHREAD_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index 8a21ae376e1..34f217ada25 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -360,11 +360,6 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena // When copying to the old generation above, we don't care // about recording object age in the census stats. assert(target_gen == YOUNG_GENERATION, "Error"); - // We record this census only when simulating pre-adaptive tenuring behavior, or - // when we have been asked to record the census at evacuation rather than at mark - if (!ShenandoahGenerationalAdaptiveTenuring) { - evac_tracker()->record_age(thread, size * HeapWordSize, ShenandoahHeap::get_object_age(copy_val)); - } } shenandoah_assert_correct(nullptr, copy_val); return copy_val; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 10d7e8edcad..b2fd32d2fd0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1441,6 +1441,27 @@ void ShenandoahHeap::print_heap_regions_on(outputStream* st) const { } } +void ShenandoahHeap::process_gc_stats() const { + // Commit worker statistics to cycle data + phase_timings()->flush_par_workers_to_cycle(); + + // Print GC stats for current cycle + LogTarget(Info, gc, stats) lt; + if (lt.is_enabled()) { + ResourceMark rm; + LogStream ls(lt); + phase_timings()->print_cycle_on(&ls); + if (ShenandoahEvacTracking) { + ShenandoahCycleStats evac_stats = evac_tracker()->flush_cycle_to_global(); + evac_tracker()->print_evacuations_on(&ls, &evac_stats.workers, + &evac_stats.mutators); + } + } + + // Commit statistics to globals + phase_timings()->flush_cycle_to_global(); +} + size_t ShenandoahHeap::trash_humongous_region_at(ShenandoahHeapRegion* start) const { assert(start->is_humongous_start(), "reclaim regions starting with the first one"); assert(!start->has_live(), "liveness must be zero"); @@ -2238,8 +2259,7 @@ void ShenandoahHeap::stw_unload_classes(bool full_gc) { // Clean JVMCI metadata handles. JVMCI_ONLY(JVMCI::do_unloading(unloading_occurred)); - uint num_workers = _workers->active_workers(); - ShenandoahClassUnloadingTask unlink_task(phase, num_workers, unloading_occurred); + ShenandoahClassUnloadingTask unlink_task(phase, unloading_occurred); _workers->run_task(&unlink_task); } // Release unloaded nmethods's memory. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 322ac26e254..11a20d4a2f9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -206,9 +206,12 @@ class ShenandoahHeap : public CollectedHeap { void initialize_serviceability() override; void print_heap_on(outputStream* st) const override; - void print_gc_on(outputStream *st) const override; + void print_gc_on(outputStream* st) const override; void print_heap_regions_on(outputStream* st) const; + // Flushes cycle timings to global timings and prints the phase timings for the last completed cycle. + void process_gc_stats() const; + void prepare_for_verify() override; void verify(VerifyOption vo) override; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp index 637948e2615..3bea8d73959 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp @@ -135,14 +135,12 @@ inline ShenandoahMarkBitMap::idx_t ShenandoahMarkBitMap::get_next_bit_impl(idx_t // Get the word containing l_index, and shift out low bits. idx_t index = to_words_align_down(l_index); bm_word_t cword = (map(index) ^ flip) >> bit_in_word(l_index); - if ((cword & 1) != 0) { - // The first bit is similarly often interesting. When it matters - // (density or features of the calling algorithm make it likely - // the first bit is set), going straight to the next clause compares - // poorly with doing this check first; count_trailing_zeros can be - // relatively expensive, plus there is the additional range check. - // But when the first bit isn't set, the cost of having tested for - // it is relatively small compared to the rest of the search. + if ((cword & 0x03) != 0) { + // The first bits (representing weak mark or strong mark) are similarly often interesting. When it matters + // (density or features of the calling algorithm make it likely the first bits are set), going straight to + // the next clause compares poorly with doing this check first; count_trailing_zeros can be relatively expensive, + // plus there is the additional range check. But when the first bits are not set, the cost of having tested for + // them is relatively small compared to the rest of the search. return l_index; } else if (cword != 0) { // Flipped and shifted first word is non-zero. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.cpp b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.cpp index 99c739026cc..6c82f970606 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.cpp @@ -31,12 +31,11 @@ #include "runtime/safepoint.hpp" ShenandoahClassUnloadingTask::ShenandoahClassUnloadingTask(ShenandoahPhaseTimings::Phase phase, - uint num_workers, bool unloading_occurred) : WorkerTask("Shenandoah Class Unloading"), _phase(phase), _unloading_occurred(unloading_occurred), - _code_cache_task(num_workers, unloading_occurred), + _code_cache_task(unloading_occurred), _klass_cleaning_task() { assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.hpp b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.hpp index b4c4fb94a5a..c68a4fde4ce 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.hpp @@ -59,7 +59,6 @@ class ShenandoahClassUnloadingTask : public WorkerTask { KlassCleaningTask _klass_cleaning_task; public: ShenandoahClassUnloadingTask(ShenandoahPhaseTimings::Phase phase, - uint num_workers, bool unloading_occurred); void work(uint worker_id); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp index a72d6004beb..c23690b15d6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp @@ -45,8 +45,6 @@ class ShenandoahOldHeuristics; * sleep time. */ class ShenandoahRegulatorThread: public ConcurrentGCThread { - friend class VMStructs; - public: explicit ShenandoahRegulatorThread(ShenandoahGenerationalControlThread* control_thread); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 260c1e0276f..53391a3e224 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -24,8 +24,7 @@ */ - -#include "gc/shared/strongRootsScope.hpp" +#include "code/nmethod.hpp" #include "gc/shared/taskTerminator.hpp" #include "gc/shared/workerThread.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" @@ -36,10 +35,13 @@ #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" #include "gc/shenandoah/shenandoahSTWMark.hpp" #include "gc/shenandoah/shenandoahVerifier.hpp" +#include "runtime/threads.hpp" class ShenandoahSTWMarkTask : public WorkerTask { private: ShenandoahSTWMark* const _mark; + NMethodMarkingScope _nmethod_marking_scope; + ThreadsClaimTokenScope _threads_claim_token_scope; public: ShenandoahSTWMarkTask(ShenandoahSTWMark* mark); @@ -48,7 +50,9 @@ class ShenandoahSTWMarkTask : public WorkerTask { ShenandoahSTWMarkTask::ShenandoahSTWMarkTask(ShenandoahSTWMark* mark) : WorkerTask("Shenandoah STW mark"), - _mark(mark) { + _mark(mark), + _nmethod_marking_scope(), + _threads_claim_token_scope() { } void ShenandoahSTWMarkTask::work(uint worker_id) { @@ -98,7 +102,6 @@ void ShenandoahSTWMark::mark() { _generation->scan_remembered_set(false /* is_concurrent */); } - StrongRootsScope scope(nworkers); ShenandoahSTWMarkTask task(this); heap->workers()->run_task(&task); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp index 37d935d1f78..f54a65b0785 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp @@ -166,10 +166,6 @@ class ShenandoahThreadLocalData { data(thread)->_evacuation_stats->end_evacuation(bytes, from, to); } - static void record_age(Thread* thread, size_t bytes, uint age) { - data(thread)->_evacuation_stats->record_age(bytes, age); - } - static ShenandoahEvacuationStats* evacuation_stats(Thread* thread) { return data(thread)->_evacuation_stats; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp index 83151313f75..b248fab7958 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp @@ -103,7 +103,7 @@ class ShenandoahCompiledICProtectionBehaviour : public CompiledICProtectionBehav } virtual bool is_safe(nmethod* nm) { - if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading()) { + if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading() || (NMethodState_lock->owned_by_self() && nm->is_not_installed())) { return true; } diff --git a/src/hotspot/share/gc/z/zLargePages.cpp b/src/hotspot/share/gc/z/zLargePages.cpp index 639c9b0a04f..c259448563b 100644 --- a/src/hotspot/share/gc/z/zLargePages.cpp +++ b/src/hotspot/share/gc/z/zLargePages.cpp @@ -31,7 +31,7 @@ bool ZLargePages::_os_enforced_transparent_mode; void ZLargePages::initialize() { pd_initialize(); - const size_t memory = os::physical_memory(); + const size_t memory = static_cast(os::physical_memory()); log_info_p(gc, init)("Memory: " PROPERFMT, PROPERFMTARGS(memory)); log_info_p(gc, init)("Large Page Support: %s", to_string()); } diff --git a/src/hotspot/share/gc/z/zUnload.cpp b/src/hotspot/share/gc/z/zUnload.cpp index c8b32385fcd..5c50b3077dd 100644 --- a/src/hotspot/share/gc/z/zUnload.cpp +++ b/src/hotspot/share/gc/z/zUnload.cpp @@ -100,7 +100,7 @@ class ZCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour { } virtual bool is_safe(nmethod* nm) { - if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading()) { + if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading() || (NMethodState_lock->owned_by_self() && nm->is_not_installed())) { return true; } diff --git a/src/hotspot/share/interpreter/templateInterpreter.hpp b/src/hotspot/share/interpreter/templateInterpreter.hpp index 8f118bb6ec8..fd6888ffab8 100644 --- a/src/hotspot/share/interpreter/templateInterpreter.hpp +++ b/src/hotspot/share/interpreter/templateInterpreter.hpp @@ -84,7 +84,6 @@ class DispatchTable { }; class TemplateInterpreter: public AbstractInterpreter { - friend class VMStructs; friend class InterpreterMacroAssembler; friend class TemplateInterpreterGenerator; friend class TemplateTable; diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.hpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.hpp index 9941055bfd4..0032109982a 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.hpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.hpp @@ -79,7 +79,6 @@ friend class AbstractInterpreterGenerator; friend class ZeroInterpreterGenerator; friend class InterpreterMacroAssembler; friend class frame; -friend class VMStructs; public: enum messages { diff --git a/src/hotspot/share/interpreter/zero/zeroInterpreter.hpp b/src/hotspot/share/interpreter/zero/zeroInterpreter.hpp index 4cc78532379..79528de639b 100644 --- a/src/hotspot/share/interpreter/zero/zeroInterpreter.hpp +++ b/src/hotspot/share/interpreter/zero/zeroInterpreter.hpp @@ -36,7 +36,6 @@ class InterpreterCodelet; // of the c++ interpreter class ZeroInterpreter: public AbstractInterpreter { - friend class VMStructs; public: // Initialization/debugging static void initialize_stub(); diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index 57bea5c268b..cc5bbe1fc60 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -423,7 +423,7 @@ JVM_ENTRY_NO_ENV(jlong, jfr_host_total_swap_memory(JNIEnv* env, jclass jvm)) // We want the host swap memory, not the container value. return os::Linux::host_swap(); #else - size_t total_swap_space = 0; + physical_memory_size_type total_swap_space = 0; // Return value ignored - defaulting to 0 on failure. (void)os::total_swap_space(total_swap_space); return static_cast(total_swap_space); diff --git a/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp index 2d4b99d59ab..18b2d7c5785 100644 --- a/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp +++ b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp @@ -32,8 +32,6 @@ #include "runtime/vm_version.hpp" #include "utilities/ostream.hpp" -#include // for environment variables - static JfrOSInterface* _instance = nullptr; JfrOSInterface& JfrOSInterface::instance() { @@ -81,10 +79,7 @@ class JfrOSInterface::JfrOSInterfaceImpl : public JfrCHeapObj { // os information int os_version(char** os_version) const; - // environment information - void generate_environment_variables_events(); - - // system processes information + // system processes information int system_processes(SystemProcess** system_processes, int* no_of_sys_processes); int network_utilization(NetworkInterface** network_interfaces); diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index a8a9e191ed8..b30ebd8108c 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -528,23 +528,23 @@ TRACE_REQUEST_FUNC(ThreadAllocationStatistics) { * the total memory reported is the amount of memory configured for the guest OS by the hypervisor. */ TRACE_REQUEST_FUNC(PhysicalMemory) { - u8 totalPhysicalMemory = static_cast(os::physical_memory()); + physical_memory_size_type totalPhysicalMemory = os::physical_memory(); EventPhysicalMemory event; event.set_totalSize(totalPhysicalMemory); - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); - event.set_usedSize(totalPhysicalMemory - static_cast(avail_mem)); + event.set_usedSize(totalPhysicalMemory - avail_mem); event.commit(); } TRACE_REQUEST_FUNC(SwapSpace) { EventSwapSpace event; - size_t total_swap_space = 0; + physical_memory_size_type total_swap_space = 0; // Return value ignored - defaulting to 0 on failure. (void)os::total_swap_space(total_swap_space); event.set_totalSize(static_cast(total_swap_space)); - size_t free_swap_space = 0; + physical_memory_size_type free_swap_space = 0; // Return value ignored - defaulting to 0 on failure. (void)os::free_swap_space(free_swap_space); event.set_freeSize(static_cast(free_swap_space)); diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp index 3fca3ad7631..7507b9c994e 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp @@ -230,8 +230,7 @@ class JfrCPUSamplerThread : public NonJavaThread { volatile bool _is_async_processing_of_cpu_time_jfr_requests_triggered; volatile bool _warned_about_timer_creation_failure; volatile bool _signal_handler_installed; - DEBUG_ONLY(volatile bool _out_of_stack_walking_enabled;) - DEBUG_ONLY(volatile u8 _out_of_stack_walking_iterations;) + DEBUG_ONLY(volatile bool _out_of_stack_walking_enabled = true;) static const u4 STOP_SIGNAL_BIT = 0x80000000; @@ -275,6 +274,7 @@ class JfrCPUSamplerThread : public NonJavaThread { void handle_timer_signal(siginfo_t* info, void* context); bool init_timers(); void stop_timer(); + virtual void print_on(outputStream* st) const; void trigger_async_processing_of_cpu_time_jfr_requests(); @@ -282,10 +282,6 @@ class JfrCPUSamplerThread : public NonJavaThread { void set_out_of_stack_walking_enabled(bool runnable) { AtomicAccess::release_store(&_out_of_stack_walking_enabled, runnable); } - - u8 out_of_stack_walking_iterations() const { - return AtomicAccess::load(&_out_of_stack_walking_iterations); - } #endif }; @@ -393,7 +389,6 @@ void JfrCPUSamplerThread::run() { } DEBUG_ONLY(if (AtomicAccess::load_acquire(&_out_of_stack_walking_enabled)) {) if (AtomicAccess::cmpxchg(&_is_async_processing_of_cpu_time_jfr_requests_triggered, true, false)) { - DEBUG_ONLY(AtomicAccess::inc(&_out_of_stack_walking_iterations);) stackwalk_threads_in_native(); } DEBUG_ONLY(}) @@ -587,18 +582,14 @@ void JfrCPUTimeThreadSampling::handle_timer_signal(siginfo_t* info, void* contex } #ifdef ASSERT -void JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(bool runnable) { +bool JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(bool runnable) { if (_instance != nullptr && _instance->_sampler != nullptr) { _instance->_sampler->set_out_of_stack_walking_enabled(runnable); + return true; + } else { + return false; } } - -u8 JfrCPUTimeThreadSampling::out_of_stack_walking_iterations() { - if (_instance != nullptr && _instance->_sampler != nullptr) { - return _instance->_sampler->out_of_stack_walking_iterations(); - } - return 0; -} #endif void JfrCPUSamplerThread::sample_thread(JfrSampleRequest& request, void* ucontext, JavaThread* jt, JfrThreadLocal* tl, JfrTicks& now) { @@ -788,6 +779,12 @@ void JfrCPUSamplerThread::stop_timer() { VMThread::execute(&op); } +void JfrCPUSamplerThread::print_on(outputStream* st) const { + st->print("\"%s\" ", name()); + Thread::print_on(st); + st->cr(); +} + void JfrCPUSamplerThread::recompute_period_if_needed() { int64_t current_period = get_sampling_period(); int64_t period = _throttle.compute_sampling_period(); @@ -865,8 +862,9 @@ void JfrCPUTimeThreadSampling::on_javathread_terminate(JavaThread* thread) { } #ifdef ASSERT -static void set_out_of_stack_walking_enabled(bool runnable) { +bool JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(bool runnable) { warn(); + return false; } #endif diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp index e17e63fc3ed..e7c915fc8be 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp @@ -139,9 +139,7 @@ class JfrCPUTimeThreadSampling : public JfrCHeapObj { static void trigger_async_processing_of_cpu_time_jfr_requests(); - DEBUG_ONLY(static void set_out_of_stack_walking_enabled(bool runnable);) - - DEBUG_ONLY(static u8 out_of_stack_walking_iterations();) + DEBUG_ONLY(static bool set_out_of_stack_walking_enabled(bool runnable);) }; #else @@ -162,8 +160,7 @@ class JfrCPUTimeThreadSampling : public JfrCHeapObj { static void on_javathread_create(JavaThread* thread); static void on_javathread_terminate(JavaThread* thread); - DEBUG_ONLY(static void set_out_of_stack_walking_enabled(bool runnable)); - DEBUG_ONLY(static u8 out_of_stack_walking_iterations();) + DEBUG_ONLY(static bool set_out_of_stack_walking_enabled(bool runnable)); }; #endif // defined(LINUX) diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp index ae79c8bb6e3..7e7747ba396 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp @@ -85,6 +85,7 @@ class JfrSamplerThread : public NonJavaThread { bool is_JfrSampler_thread() const { return true; } int64_t java_period() const { return AtomicAccess::load(&_java_period_millis); }; int64_t native_period() const { return AtomicAccess::load(&_native_period_millis); }; + virtual void print_on(outputStream* st) const; }; JfrSamplerThread::JfrSamplerThread(int64_t java_period_millis, int64_t native_period_millis, u4 max_frames) : @@ -384,6 +385,12 @@ void JfrSamplerThread::set_native_period(int64_t period_millis) { AtomicAccess::store(&_native_period_millis, period_millis); } +void JfrSamplerThread::print_on(outputStream* st) const { + st->print("\"%s\" ", name()); + Thread::print_on(st); + st->cr(); +} + // JfrThreadSampler; static JfrThreadSampler* _instance = nullptr; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index b8ff3ba504a..ff688a297ed 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -676,18 +676,36 @@ void JfrCheckpointManager::write_simplified_vthread_checkpoint(traceid vtid) { JfrTypeManager::write_simplified_vthread_checkpoint(vtid); } -class JfrNotifyClosure : public ThreadClosure { +// Reset thread local state used for object allocation sampling. +static void clear_last_allocated_bytes(JavaThread* jt) { + assert(jt != nullptr, "invariant"); + assert(!JfrRecorder::is_recording(), "invariant"); + JfrThreadLocal* const tl = jt->jfr_thread_local(); + assert(tl != nullptr, "invariant"); + if (tl->last_allocated_bytes() != 0) { + tl->clear_last_allocated_bytes(); + } + assert(tl->last_allocated_bytes() == 0, "invariant"); +} + +class JfrNotifyClosure : public StackObj { + private: + bool _clear; public: - void do_thread(Thread* thread) { - assert(thread != nullptr, "invariant"); + JfrNotifyClosure(bool clear) : _clear(clear) {} + void do_thread(JavaThread* jt) { + assert(jt != nullptr, "invariant"); assert_locked_or_safepoint(Threads_lock); - JfrJavaEventWriter::notify(JavaThread::cast(thread)); + JfrJavaEventWriter::notify(jt); + if (_clear) { + clear_last_allocated_bytes(jt); + } } }; -void JfrCheckpointManager::notify_threads() { +void JfrCheckpointManager::notify_threads(bool clear /* false */) { assert(SafepointSynchronize::is_at_safepoint(), "invariant"); - JfrNotifyClosure tc; + JfrNotifyClosure tc(clear); JfrJavaThreadIterator iter; while (iter.has_next()) { tc.do_thread(iter.next()); diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp index f9f8f1c26cf..f713a77e66d 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp @@ -88,7 +88,7 @@ class JfrCheckpointManager : public JfrCHeapObj { size_t clear(); size_t write(); - void notify_threads(); + void notify_threads(bool clear = false); size_t write_static_type_set(Thread* thread); size_t write_threads(JavaThread* thread); diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 0087980f430..0e68e8a6032 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -122,30 +122,6 @@ const Thread* JfrRotationLock::_owner_thread = nullptr; const int JfrRotationLock::retry_wait_millis = 10; volatile int JfrRotationLock::_lock = 0; -// Reset thread local state used for object allocation sampling. -class ClearObjectAllocationSampling : public ThreadClosure { - public: - void do_thread(Thread* t) { - assert(t != nullptr, "invariant"); - t->jfr_thread_local()->clear_last_allocated_bytes(); - } -}; - -template -static inline void iterate(Iterator& it, ClearObjectAllocationSampling& coas) { - while (it.has_next()) { - coas.do_thread(it.next()); - } -} - -static void clear_object_allocation_sampling() { - ClearObjectAllocationSampling coas; - JfrJavaThreadIterator jit; - iterate(jit, coas); - JfrNonJavaThreadIterator njit; - iterate(njit, coas); -} - template class Content { private: @@ -472,7 +448,6 @@ void JfrRecorderService::clear() { } void JfrRecorderService::pre_safepoint_clear() { - clear_object_allocation_sampling(); _storage.clear(); JfrStackTraceRepository::clear(); } @@ -486,7 +461,7 @@ void JfrRecorderService::invoke_safepoint_clear() { void JfrRecorderService::safepoint_clear() { assert(SafepointSynchronize::is_at_safepoint(), "invariant"); _storage.clear(); - _checkpoint_manager.notify_threads(); + _checkpoint_manager.notify_threads(true); _chunkwriter.set_time_stamp(); JfrDeprecationManager::on_safepoint_clear(); JfrStackTraceRepository::clear(); diff --git a/src/hotspot/share/jfr/support/jfrAllocationTracer.cpp b/src/hotspot/share/jfr/support/jfrAllocationTracer.cpp index a1245d7bafe..5817ad194c2 100644 --- a/src/hotspot/share/jfr/support/jfrAllocationTracer.cpp +++ b/src/hotspot/share/jfr/support/jfrAllocationTracer.cpp @@ -22,6 +22,7 @@ * */ +#include "jfr/jfrEvents.hpp" #include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/support/jfrAllocationTracer.hpp" #include "jfr/support/jfrObjectAllocationSample.hpp" @@ -31,5 +32,7 @@ JfrAllocationTracer::JfrAllocationTracer(const Klass* klass, HeapWord* obj, size if (LeakProfiler::is_running()) { LeakProfiler::sample(obj, alloc_size, thread); } - JfrObjectAllocationSample::send_event(klass, alloc_size, outside_tlab, thread); + if (EventObjectAllocationSample::is_enabled()) { + JfrObjectAllocationSample::send_event(klass, alloc_size, outside_tlab, thread); + } } diff --git a/src/hotspot/share/jfr/support/jfrObjectAllocationSample.cpp b/src/hotspot/share/jfr/support/jfrObjectAllocationSample.cpp index 6a99271a80e..c337030bddd 100644 --- a/src/hotspot/share/jfr/support/jfrObjectAllocationSample.cpp +++ b/src/hotspot/share/jfr/support/jfrObjectAllocationSample.cpp @@ -26,7 +26,7 @@ #include "gc/shared/tlab_globals.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/support/jfrObjectAllocationSample.hpp" -#include "jfr/support/jfrThreadLocal.hpp" +#include "runtime/javaThread.hpp" #include "utilities/globalDefinitions.hpp" inline bool send_allocation_sample(const Klass* klass, int64_t allocated_bytes, JfrThreadLocal* tl) { @@ -43,35 +43,42 @@ inline bool send_allocation_sample(const Klass* klass, int64_t allocated_bytes, return false; } -inline int64_t estimate_tlab_size_bytes(Thread* thread) { - const size_t desired_tlab_size_bytes = thread->tlab().desired_size() * HeapWordSize; - const size_t alignment_reserve_bytes = thread->tlab().alignment_reserve_in_bytes(); +inline int64_t estimate_tlab_size_bytes(JavaThread* jt) { + const size_t desired_tlab_size_bytes = jt->tlab().desired_size() * HeapWordSize; + const size_t alignment_reserve_bytes = jt->tlab().alignment_reserve_in_bytes(); assert(desired_tlab_size_bytes >= alignment_reserve_bytes, "invariant"); return static_cast(desired_tlab_size_bytes - alignment_reserve_bytes); } -inline int64_t load_allocated_bytes(JfrThreadLocal* tl, Thread* thread) { - const int64_t allocated_bytes = thread->allocated_bytes(); - return allocated_bytes == tl->last_allocated_bytes() ? 0 : allocated_bytes; +inline int64_t load_allocated_bytes(JfrThreadLocal* tl, JavaThread* jt) { + const int64_t allocated_bytes = jt->allocated_bytes(); + const int64_t last_allocated_bytes = tl->last_allocated_bytes(); + assert(allocated_bytes >= last_allocated_bytes, "invariant"); + if (last_allocated_bytes == 0) { + // Initialization. + tl->set_last_allocated_bytes(allocated_bytes); + return 0; + } + return allocated_bytes == last_allocated_bytes ? 0 : allocated_bytes; } // To avoid large objects from being undersampled compared to the regular TLAB samples, // the data amount is normalized as if it was a TLAB, giving a number of TLAB sampling attempts to the large object. -static void normalize_as_tlab_and_send_allocation_samples(const Klass* klass, int64_t obj_alloc_size_bytes, JfrThreadLocal* tl, Thread* thread) { - const int64_t allocated_bytes = load_allocated_bytes(tl, thread); +static void normalize_as_tlab_and_send_allocation_samples(const Klass* klass, + int64_t obj_alloc_size_bytes, + int64_t allocated_bytes, + JfrThreadLocal* tl, + JavaThread* jt) { assert(allocated_bytes > 0, "invariant"); // obj_alloc_size_bytes is already attributed to allocated_bytes at this point. if (!UseTLAB) { send_allocation_sample(klass, allocated_bytes, tl); return; } - const int64_t tlab_size_bytes = estimate_tlab_size_bytes(thread); - if (tlab_size_bytes <= 0) { + const int64_t tlab_size_bytes = estimate_tlab_size_bytes(jt); + if (tlab_size_bytes <= 0 || allocated_bytes - tl->last_allocated_bytes() < tlab_size_bytes) { // We don't get a TLAB, avoid endless loop below. return; } - if (allocated_bytes - tl->last_allocated_bytes() < tlab_size_bytes) { - return; - } assert(obj_alloc_size_bytes > 0, "invariant"); do { if (send_allocation_sample(klass, allocated_bytes, tl)) { @@ -81,17 +88,17 @@ static void normalize_as_tlab_and_send_allocation_samples(const Klass* klass, in } while (obj_alloc_size_bytes > 0); } -void JfrObjectAllocationSample::send_event(const Klass* klass, size_t alloc_size, bool outside_tlab, Thread* thread) { - assert(thread != nullptr, "invariant"); - JfrThreadLocal* const tl = thread->jfr_thread_local(); +void JfrObjectAllocationSample::send_event(const Klass* klass, size_t alloc_size, bool outside_tlab, JavaThread* jt) { + assert(klass != nullptr, "invariant"); + assert(jt != nullptr, "invariant"); + JfrThreadLocal* const tl = jt->jfr_thread_local(); assert(tl != nullptr, "invariant"); - if (outside_tlab) { - normalize_as_tlab_and_send_allocation_samples(klass, static_cast(alloc_size), tl, thread); - return; - } - const int64_t allocated_bytes = load_allocated_bytes(tl, thread); - if (allocated_bytes == 0) { - return; + const int64_t allocated_bytes = load_allocated_bytes(tl, jt); + if (allocated_bytes > 0) { + if (outside_tlab) { + normalize_as_tlab_and_send_allocation_samples(klass, static_cast(alloc_size), allocated_bytes, tl, jt); + return; + } + send_allocation_sample(klass, allocated_bytes, tl); } - send_allocation_sample(klass, allocated_bytes, tl); } diff --git a/src/hotspot/share/jfr/support/jfrObjectAllocationSample.hpp b/src/hotspot/share/jfr/support/jfrObjectAllocationSample.hpp index f58caf3c2a6..cb63d7e1e29 100644 --- a/src/hotspot/share/jfr/support/jfrObjectAllocationSample.hpp +++ b/src/hotspot/share/jfr/support/jfrObjectAllocationSample.hpp @@ -27,12 +27,12 @@ #include "memory/allStatic.hpp" +class JavaThread; class Klass; -class Thread; class JfrObjectAllocationSample : AllStatic { friend class JfrAllocationTracer; - static void send_event(const Klass* klass, size_t alloc_size, bool outside_tlab, Thread* thread); + static void send_event(const Klass* klass, size_t alloc_size, bool outside_tlab, JavaThread* jt); }; #endif // SHARE_JFR_SUPPORT_JFROBJECTALLOCATIONSAMPLE_HPP diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index 3a9fbc54bf9..ce617a4a514 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -1141,7 +1141,7 @@ int CodeInstaller::map_jvmci_bci(int bci) { return bci; } -void CodeInstaller::record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool is_mh_invoke, bool return_oop, JVMCI_TRAPS) { +void CodeInstaller::record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool return_oop, JVMCI_TRAPS) { if (full_info) { read_virtual_objects(stream, JVMCI_CHECK); } @@ -1184,7 +1184,7 @@ void CodeInstaller::record_scope(jint pc_offset, HotSpotCompiledCodeStream* stre // has_ea_local_in_scope and arg_escape should be added to JVMCI const bool has_ea_local_in_scope = false; const bool arg_escape = false; - _debug_recorder->describe_scope(pc_offset, method, nullptr, bci, reexecute, rethrow_exception, is_mh_invoke, return_oop, + _debug_recorder->describe_scope(pc_offset, method, nullptr, bci, reexecute, rethrow_exception, return_oop, has_ea_local_in_scope, arg_escape, locals_token, stack_token, monitors_token); } @@ -1242,14 +1242,8 @@ void CodeInstaller::site_Call(CodeBuffer& buffer, u1 tag, jint pc_offset, HotSpo _debug_recorder->add_safepoint(next_pc_offset, map); if (!method.is_null()) { - vmIntrinsics::ID iid = method->intrinsic_id(); - bool is_mh_invoke = false; - if (direct_call) { - is_mh_invoke = !method->is_static() && (iid == vmIntrinsics::_compiledLambdaForm || - (MethodHandles::is_signature_polymorphic(iid) && MethodHandles::is_signature_polymorphic_intrinsic(iid))); - } bool return_oop = method->is_returning_oop(); - record_scope(next_pc_offset, stream, flags, true, is_mh_invoke, return_oop, JVMCI_CHECK); + record_scope(next_pc_offset, stream, flags, true, return_oop, JVMCI_CHECK); } else { record_scope(next_pc_offset, stream, flags, true, JVMCI_CHECK); } @@ -1339,9 +1333,6 @@ void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, HotSpotCompile case DEOPT_HANDLER_ENTRY: _offsets.set_value(CodeOffsets::Deopt, pc_offset); break; - case DEOPT_MH_HANDLER_ENTRY: - _offsets.set_value(CodeOffsets::DeoptMH, pc_offset); - break; case FRAME_COMPLETE: _offsets.set_value(CodeOffsets::Frame_Complete, pc_offset); break; @@ -1369,6 +1360,7 @@ void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, HotSpotCompile case VERIFY_OOP_BITS: case VERIFY_OOP_MASK: case VERIFY_OOP_COUNT_ADDRESS: + case DEOPT_MH_HANDLER_ENTRY: break; default: diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp index a8279e99dc2..bdebed2d9e8 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp @@ -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 @@ -411,10 +411,10 @@ class CodeInstaller : public StackObj { void record_oop_patch(HotSpotCompiledCodeStream* stream, address dest, u1 read_tag, bool narrow, JVMCI_TRAPS); // full_info: if false, only BytecodePosition is in stream otherwise all DebugInfo is in stream - void record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool is_mh_invoke, bool return_oop, JVMCI_TRAPS); + void record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool return_oop, JVMCI_TRAPS); void record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, JVMCI_TRAPS) { - record_scope(pc_offset, stream, debug_info_flags, full_info, false /* is_mh_invoke */, false /* return_oop */, JVMCIENV); + record_scope(pc_offset, stream, debug_info_flags, full_info, false /* return_oop */, JVMCIENV); } void record_object_value(ObjectValue* sv, HotSpotCompiledCodeStream* stream, JVMCI_TRAPS); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index e75527235f0..a178ac66344 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -228,9 +228,6 @@ extern void vm_exit(int code); // unpack_with_exception entry instead. This makes life for the exception blob easier // because making that same check and diverting is painful from assembly language. JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* current, oopDesc* ex, address pc, nmethod*& nm)) - // Reset method handle flag. - current->set_is_method_handle_return(false); - Handle exception(current, ex); // The frame we rethrow the exception to might not have been processed by the GC yet. @@ -305,8 +302,6 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c if (guard_pages_enabled) { address fast_continuation = nm->handler_for_exception_and_pc(exception, pc); if (fast_continuation != nullptr) { - // Set flag if return address is a method handle call site. - current->set_is_method_handle_return(nm->is_method_handle_return(pc)); return fast_continuation; } } @@ -343,9 +338,6 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c } } - // Set flag if return address is a method handle call site. - current->set_is_method_handle_return(nm->is_method_handle_return(pc)); - if (log_is_enabled(Info, exceptions)) { ResourceMark rm; log_info(exceptions)("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index f4c322e831c..885ff0dbf9b 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -137,6 +137,11 @@ class JVMCINMethodData : public ResourceObj { // Gets the JVMCI name of the nmethod (which may be null). const char* name() { return has_name() ? (char*)(((address) this) + sizeof(JVMCINMethodData)) : nullptr; } + // Returns true if this nmethod has a mirror + bool has_mirror() const { + return _nmethod_mirror_index != -1; + } + // Clears the HotSpotNmethod.address field in the mirror. If nm // is dead, the HotSpotNmethod.entryPoint field is also cleared. void invalidate_nmethod_mirror(nmethod* nm, nmethod::InvalidationReason invalidation_reason); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 7ddb9be540a..7ef16f6e32c 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -168,7 +168,7 @@ nonstatic_field(Array, _length, int) \ nonstatic_field(Array, _data[0], Klass*) \ \ - volatile_nonstatic_field(BasicLock, _metadata, uintptr_t) \ + volatile_nonstatic_field(BasicLock, _monitor, ObjectMonitor*) \ \ static_field(CodeCache, _low_bound, address) \ static_field(CodeCache, _high_bound, address) \ @@ -242,7 +242,6 @@ nonstatic_field(JavaThread, _stack_overflow_state._stack_overflow_limit, address) \ volatile_nonstatic_field(JavaThread, _exception_oop, oop) \ volatile_nonstatic_field(JavaThread, _exception_pc, address) \ - volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \ volatile_nonstatic_field(JavaThread, _doing_unsafe_access, bool) \ nonstatic_field(JavaThread, _osthread, OSThread*) \ nonstatic_field(JavaThread, _saved_exception_pc, address) \ @@ -256,7 +255,6 @@ nonstatic_field(JavaThread, _should_post_on_exceptions_flag, int) \ nonstatic_field(JavaThread, _jni_environment, JNIEnv) \ nonstatic_field(JavaThread, _stack_overflow_state._reserved_stack_activation, address) \ - nonstatic_field(JavaThread, _held_monitor_count, intx) \ nonstatic_field(JavaThread, _lock_stack, LockStack) \ nonstatic_field(JavaThread, _om_cache, OMCache) \ nonstatic_field(JavaThread, _cont_entry, ContinuationEntry*) \ diff --git a/src/hotspot/share/memory/heap.hpp b/src/hotspot/share/memory/heap.hpp index 5056f0f6c21..9db8aae79cb 100644 --- a/src/hotspot/share/memory/heap.hpp +++ b/src/hotspot/share/memory/heap.hpp @@ -70,7 +70,6 @@ class HeapBlock { }; class FreeBlock: public HeapBlock { - friend class VMStructs; protected: FreeBlock* _link; diff --git a/src/hotspot/share/memory/metaspace/chunkManager.cpp b/src/hotspot/share/memory/metaspace/chunkManager.cpp index 2c787046ce8..436b22aad94 100644 --- a/src/hotspot/share/memory/metaspace/chunkManager.cpp +++ b/src/hotspot/share/memory/metaspace/chunkManager.cpp @@ -117,10 +117,6 @@ Metachunk* ChunkManager::get_chunk(chunklevel_t preferred_level, chunklevel_t ma c = get_chunk_locked(preferred_level, max_level, min_committed_words); } - if (c != nullptr) { - ASAN_UNPOISON_MEMORY_REGION(c->base(), c->word_size() * BytesPerWord); - } - return c; } @@ -243,9 +239,6 @@ Metachunk* ChunkManager::get_chunk_locked(chunklevel_t preferred_level, chunklev // !! Note: this may invalidate the chunk. Do not access the chunk after // this function returns !! void ChunkManager::return_chunk(Metachunk* c) { - // It is valid to poison the chunk payload area at this point since its physically separated from - // the chunk meta info. - ASAN_POISON_MEMORY_REGION(c->base(), c->word_size() * BytesPerWord); MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag); return_chunk_locked(c); } @@ -303,9 +296,6 @@ bool ChunkManager::attempt_enlarge_chunk(Metachunk* c) { enlarged = c->vsnode()->attempt_enlarge_chunk(c, &_chunks); } - if (enlarged) { - ASAN_UNPOISON_MEMORY_REGION(c->base() + old_word_size, (c->word_size() - old_word_size) * BytesPerWord); - } return enlarged; } diff --git a/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp b/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp index d14cc5699fa..d21c6546cf5 100644 --- a/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp +++ b/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp @@ -113,6 +113,8 @@ bool VirtualSpaceNode::commit_range(MetaWord* p, size_t word_size) { vm_exit_out_of_memory(word_size * BytesPerWord, OOM_MMAP_ERROR, "Failed to commit metaspace."); } + ASAN_UNPOISON_MEMORY_REGION((char*)p, word_size * BytesPerWord); + if (AlwaysPreTouch) { os::pretouch_memory(p, p + word_size); } @@ -193,6 +195,8 @@ void VirtualSpaceNode::uncommit_range(MetaWord* p, size_t word_size) { fatal("Failed to uncommit metaspace."); } + ASAN_POISON_MEMORY_REGION((char*)p, word_size * BytesPerWord); + UL2(debug, "... uncommitted %zu words.", committed_words_in_range); // ... tell commit limiter... @@ -238,10 +242,6 @@ VirtualSpaceNode::VirtualSpaceNode(ReservedSpace rs, bool owns_rs, CommitLimiter assert_is_aligned(_base, chunklevel::MAX_CHUNK_BYTE_SIZE); assert_is_aligned(_word_size, chunklevel::MAX_CHUNK_WORD_SIZE); - // Poison the memory region. It will be unpoisoned later on a per-chunk base for chunks that are - // handed to arenas. - ASAN_POISON_MEMORY_REGION(rs.base(), rs.size()); - // Register memory region related to Metaspace. The Metaspace contains lots of pointers to malloc // memory. LSAN_REGISTER_ROOT_REGION(rs.base(), rs.size()); @@ -290,10 +290,6 @@ VirtualSpaceNode::~VirtualSpaceNode() { // Unregister memory region related to Metaspace. LSAN_UNREGISTER_ROOT_REGION(_rs.base(), _rs.size()); - // Undo the poisoning before potentially unmapping memory. This ensures that future mappings at - // the same address do not unexpectedly fail with use-after-poison. - ASAN_UNPOISON_MEMORY_REGION(_rs.base(), _rs.size()); - UL(debug, ": dies."); if (_owns_rs) { diff --git a/src/hotspot/share/memory/metaspaceCounters.cpp b/src/hotspot/share/memory/metaspaceCounters.cpp index b57373516f9..7396ac78655 100644 --- a/src/hotspot/share/memory/metaspaceCounters.cpp +++ b/src/hotspot/share/memory/metaspaceCounters.cpp @@ -32,7 +32,6 @@ #include "utilities/exceptions.hpp" class MetaspacePerfCounters { - friend class VMStructs; PerfVariable* _capacity; PerfVariable* _used; PerfVariable* _max_capacity; diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index a3b841a400b..424e43c5e83 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -504,7 +504,7 @@ void Universe::genesis(TRAPS) { // Since some of the old system object arrays have been converted to // ordinary object arrays, _objectArrayKlass will be loaded when // SystemDictionary::initialize(CHECK); is run. See the extra check - // for Object_klass_loaded in objArrayKlassKlass::allocate_objArray_klass_impl. + // for Object_klass_is_loaded in ObjArrayKlass::allocate_objArray_klass. { Klass* oak = vmClasses::Object_klass()->array_klass(CHECK); _objectArrayKlass = ObjArrayKlass::cast(oak); @@ -593,7 +593,7 @@ void Universe::fixup_mirrors(TRAPS) { // but we cannot do that for classes created before java.lang.Class is loaded. Here we simply // walk over permanent objects created so far (mostly classes) and fixup their mirrors. Note // that the number of objects allocated at this point is very small. - assert(vmClasses::Class_klass_loaded(), "java.lang.Class should be loaded"); + assert(vmClasses::Class_klass_is_loaded(), "java.lang.Class should be loaded"); HandleMark hm(THREAD); if (!CDSConfig::is_using_archive()) { diff --git a/src/hotspot/share/metaprogramming/logical.hpp b/src/hotspot/share/metaprogramming/logical.hpp deleted file mode 100644 index a488b94f8b9..00000000000 --- a/src/hotspot/share/metaprogramming/logical.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_METAPROGRAMMING_LOGICAL_HPP -#define SHARE_METAPROGRAMMING_LOGICAL_HPP - -// Stand-ins for C++17 logical operations on types. - -#include - -// Stand-in for C++17 std::bool_constant. -template -using BoolConstant = std::integral_constant; - -// Stand-in for C++17 std::conjunction -template -struct Conjunction : public std::true_type {}; - -template -struct Conjunction : public T1 {}; - -template -struct Conjunction : - public std::conditional_t, T1> -{}; - -// Stand-in for C++17 std::disjunction. -template -struct Disjunction : public std::false_type {}; - -template -struct Disjunction : public T1 {}; - -template -struct Disjunction : - public std::conditional_t> -{}; - -// Stand-in for C++17 std::negation. -template -using Negation = BoolConstant; - -#endif // SHARE_METAPROGRAMMING_LOGICAL_HPP diff --git a/src/hotspot/share/nmt/memoryFileTracker.cpp b/src/hotspot/share/nmt/memoryFileTracker.cpp index 2f3f4f1973a..fe723d09364 100644 --- a/src/hotspot/share/nmt/memoryFileTracker.cpp +++ b/src/hotspot/share/nmt/memoryFileTracker.cpp @@ -42,7 +42,8 @@ void MemoryFileTracker::allocate_memory(MemoryFile* file, size_t offset, MemTag mem_tag) { NativeCallStackStorage::StackIndex sidx = _stack_storage.push(stack); VMATree::RegionData regiondata(sidx, mem_tag); - VMATree::SummaryDiff diff = file->_tree.commit_mapping(offset, size, regiondata); + VMATree::SummaryDiff diff; + file->_tree.commit_mapping(offset, size, regiondata, diff); for (int i = 0; i < mt_number_of_tags; i++) { VirtualMemory* summary = file->_summary.by_tag(NMTUtil::index_to_tag(i)); summary->reserve_memory(diff.tag[i].commit); @@ -51,7 +52,8 @@ void MemoryFileTracker::allocate_memory(MemoryFile* file, size_t offset, } void MemoryFileTracker::free_memory(MemoryFile* file, size_t offset, size_t size) { - VMATree::SummaryDiff diff = file->_tree.release_mapping(offset, size); + VMATree::SummaryDiff diff; + file->_tree.release_mapping(offset, size, diff); for (int i = 0; i < mt_number_of_tags; i++) { VirtualMemory* summary = file->_summary.by_tag(NMTUtil::index_to_tag(i)); summary->reserve_memory(diff.tag[i].commit); diff --git a/src/hotspot/share/nmt/regionsTree.cpp b/src/hotspot/share/nmt/regionsTree.cpp index a2f5a5df67a..83306cbc14f 100644 --- a/src/hotspot/share/nmt/regionsTree.cpp +++ b/src/hotspot/share/nmt/regionsTree.cpp @@ -25,12 +25,12 @@ #include "nmt/regionsTree.inline.hpp" #include "nmt/virtualMemoryTracker.hpp" -VMATree::SummaryDiff RegionsTree::commit_region(address addr, size_t size, const NativeCallStack& stack) { - return commit_mapping((VMATree::position)addr, size, make_region_data(stack, mtNone), /*use tag inplace*/ true); +void RegionsTree::commit_region(address addr, size_t size, const NativeCallStack& stack, VMATree::SummaryDiff& diff) { + commit_mapping((VMATree::position)addr, size, make_region_data(stack, mtNone), diff, /*use tag inplace*/ true); } -VMATree::SummaryDiff RegionsTree::uncommit_region(address addr, size_t size) { - return uncommit_mapping((VMATree::position)addr, size, make_region_data(NativeCallStack::empty_stack(), mtNone)); +void RegionsTree::uncommit_region(address addr, size_t size, VMATree::SummaryDiff& diff) { + uncommit_mapping((VMATree::position)addr, size, make_region_data(NativeCallStack::empty_stack(), mtNone), diff); } #ifdef ASSERT diff --git a/src/hotspot/share/nmt/regionsTree.hpp b/src/hotspot/share/nmt/regionsTree.hpp index 35272c27423..2e1b37d0c1a 100644 --- a/src/hotspot/share/nmt/regionsTree.hpp +++ b/src/hotspot/share/nmt/regionsTree.hpp @@ -48,8 +48,8 @@ class RegionsTree : public VMATree { ReservedMemoryRegion find_reserved_region(address addr); - SummaryDiff commit_region(address addr, size_t size, const NativeCallStack& stack); - SummaryDiff uncommit_region(address addr, size_t size); + void commit_region(address addr, size_t size, const NativeCallStack& stack, SummaryDiff& diff); + void uncommit_region(address addr, size_t size, SummaryDiff& diff); using Node = VMATree::TNode; diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.cpp b/src/hotspot/share/nmt/virtualMemoryTracker.cpp index 643a3d1f8d7..d676d93e040 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.cpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.cpp @@ -69,7 +69,8 @@ void VirtualMemoryTracker::Instance::add_reserved_region(address base_addr, size void VirtualMemoryTracker::add_reserved_region(address base_addr, size_t size, const NativeCallStack& stack, MemTag mem_tag) { - VMATree::SummaryDiff diff = tree()->reserve_mapping((size_t)base_addr, size, tree()->make_region_data(stack, mem_tag)); + VMATree::SummaryDiff diff; + tree()->reserve_mapping((size_t)base_addr, size, tree()->make_region_data(stack, mem_tag), diff); apply_summary_diff(diff); } @@ -148,7 +149,8 @@ void VirtualMemoryTracker::Instance::add_committed_region(address addr, size_t s void VirtualMemoryTracker::add_committed_region(address addr, size_t size, const NativeCallStack& stack) { - VMATree::SummaryDiff diff = tree()->commit_region(addr, size, stack); + VMATree::SummaryDiff diff; + tree()->commit_region(addr, size, stack, diff); apply_summary_diff(diff); } @@ -159,7 +161,8 @@ void VirtualMemoryTracker::Instance::remove_uncommitted_region(address addr, siz void VirtualMemoryTracker::remove_uncommitted_region(address addr, size_t size) { MemTracker::assert_locked(); - VMATree::SummaryDiff diff = tree()->uncommit_region(addr, size); + VMATree::SummaryDiff diff; + tree()->uncommit_region(addr, size, diff); apply_summary_diff(diff); } @@ -169,7 +172,8 @@ void VirtualMemoryTracker::Instance::remove_released_region(address addr, size_t } void VirtualMemoryTracker::remove_released_region(address addr, size_t size) { - VMATree::SummaryDiff diff = tree()->release_mapping((VMATree::position)addr, size); + VMATree::SummaryDiff diff; + tree()->release_mapping((VMATree::position)addr, size, diff); apply_summary_diff(diff); } diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index 69887068cb2..df7b1ac867e 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -242,14 +242,14 @@ void VMATree::update_region(TNode* n1, TNode* n2, const RequestInfo& req, Summar } -VMATree::SummaryDiff VMATree::register_mapping(position _A, position _B, StateType state, - const RegionData& metadata, bool use_tag_inplace) { +void VMATree::register_mapping(position _A, position _B, StateType state, + const RegionData& metadata, VMATree::SummaryDiff& diff, bool use_tag_inplace) { + diff.clear(); if (_A == _B) { - return SummaryDiff(); + return; } assert(_A < _B, "should be"); - SummaryDiff diff; RequestInfo req{_A, _B, state, metadata.mem_tag, metadata.stack_idx, use_tag_inplace}; IntervalChange stA{ IntervalState{StateType::Released, empty_regiondata}, @@ -644,8 +644,6 @@ VMATree::SummaryDiff VMATree::register_mapping(position _A, position _B, StateTy while(to_be_removed.length() != 0) { _tree.remove(to_be_removed.pop()); } - - return diff; } #ifdef ASSERT @@ -702,7 +700,8 @@ VMATree::SummaryDiff VMATree::set_tag(const position start, const size size, con // Ignore any released ranges, these must be mtNone and have no stack if (type != StateType::Released) { RegionData new_data = RegionData(out.reserved_stack(), tag); - SummaryDiff result = register_mapping(from, end, type, new_data); + SummaryDiff result; + register_mapping(from, end, type, new_data, result); diff.add(result); } @@ -723,7 +722,8 @@ VMATree::SummaryDiff VMATree::set_tag(const position start, const size size, con if (type != StateType::Released) { RegionData new_data = RegionData(out.reserved_stack(), tag); - SummaryDiff result = register_mapping(from, end, type, new_data); + SummaryDiff result; + register_mapping(from, end, type, new_data, result); diff.add(result); } remsize = remsize - (end - from); diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index dff2491c69c..f7ca8f4c7e0 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -241,6 +241,9 @@ class VMATree : public CHeapObjBase { struct SummaryDiff { SingleDiff tag[mt_number_of_tags]; SummaryDiff() { + clear(); + } + void clear() { for (int i = 0; i < mt_number_of_tags; i++) { tag[i] = SingleDiff{0, 0}; } @@ -283,7 +286,7 @@ class VMATree : public CHeapObjBase { }; private: - SummaryDiff register_mapping(position A, position B, StateType state, const RegionData& metadata, bool use_tag_inplace = false); + void register_mapping(position A, position B, StateType state, const RegionData& metadata, SummaryDiff& diff, bool use_tag_inplace = false); StateType get_new_state(const StateType existinting_state, const RequestInfo& req) const; MemTag get_new_tag(const MemTag existinting_tag, const RequestInfo& req) const; SIndex get_new_reserve_callstack(const SIndex existinting_stack, const StateType ex, const RequestInfo& req) const; @@ -298,12 +301,12 @@ class VMATree : public CHeapObjBase { } public: - SummaryDiff reserve_mapping(position from, size size, const RegionData& metadata) { - return register_mapping(from, from + size, StateType::Reserved, metadata, false); + void reserve_mapping(position from, size size, const RegionData& metadata, SummaryDiff& diff ) { + register_mapping(from, from + size, StateType::Reserved, metadata, diff, false); } - SummaryDiff commit_mapping(position from, size size, const RegionData& metadata, bool use_tag_inplace = false) { - return register_mapping(from, from + size, StateType::Committed, metadata, use_tag_inplace); + void commit_mapping(position from, size size, const RegionData& metadata, SummaryDiff& diff, bool use_tag_inplace = false) { + register_mapping(from, from + size, StateType::Committed, metadata, diff, use_tag_inplace); } // Given an interval and a tag, find all reserved and committed ranges at least @@ -312,12 +315,12 @@ class VMATree : public CHeapObjBase { // Released regions are ignored. SummaryDiff set_tag(position from, size size, MemTag tag); - SummaryDiff uncommit_mapping(position from, size size, const RegionData& metadata) { - return register_mapping(from, from + size, StateType::Reserved, metadata, true); + void uncommit_mapping(position from, size size, const RegionData& metadata, SummaryDiff& diff) { + register_mapping(from, from + size, StateType::Reserved, metadata, diff, true); } - SummaryDiff release_mapping(position from, position sz) { - return register_mapping(from, from + sz, StateType::Released, VMATree::empty_regiondata); + void release_mapping(position from, position sz, SummaryDiff& diff) { + register_mapping(from, from + sz, StateType::Released, VMATree::empty_regiondata, diff); } public: diff --git a/src/hotspot/share/oops/compressedKlass.cpp b/src/hotspot/share/oops/compressedKlass.cpp index d7c97d3c8d5..b32d10c74d2 100644 --- a/src/hotspot/share/oops/compressedKlass.cpp +++ b/src/hotspot/share/oops/compressedKlass.cpp @@ -110,7 +110,7 @@ void CompressedKlassPointers::sanity_check_after_initialization() { // Check that Klass range is fully engulfed in the encoding range const address encoding_start = _base; const address encoding_end = (address) - LP64_ONLY(p2u(_base) + (uintptr_t)nth_bit(narrow_klass_pointer_bits() + _shift)) + LP64_ONLY((p2u(_base) + (uintptr_t)nth_bit(narrow_klass_pointer_bits() + _shift))) NOT_LP64(max_klass_range_size()); ASSERT_HERE_2(_klass_range_start >= _base && _klass_range_end <= encoding_end, "Resulting encoding range does not fully cover the class range"); diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index ddb24302d69..5d5c0548215 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -395,7 +395,7 @@ void ConstantPool::restore_unshareable_info(TRAPS) { // Only create the new resolved references array if it hasn't been attempted before if (resolved_references() != nullptr) return; - if (vmClasses::Object_klass_loaded()) { + if (vmClasses::Object_klass_is_loaded()) { ClassLoaderData* loader_data = pool_holder()->class_loader_data(); #if INCLUDE_CDS_JAVA_HEAP if (ArchiveHeapLoader::is_in_use() && diff --git a/src/hotspot/share/oops/instanceClassLoaderKlass.hpp b/src/hotspot/share/oops/instanceClassLoaderKlass.hpp index 985c81c3cd6..f6aedc312aa 100644 --- a/src/hotspot/share/oops/instanceClassLoaderKlass.hpp +++ b/src/hotspot/share/oops/instanceClassLoaderKlass.hpp @@ -37,7 +37,6 @@ class ClassFileParser; // the list later? class InstanceClassLoaderKlass: public InstanceKlass { - friend class VMStructs; friend class InstanceKlass; public: static const KlassKind Kind = InstanceClassLoaderKlassKind; diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 9d6cb951aeb..e13f4849454 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -159,7 +159,7 @@ static inline bool is_class_loader(const Symbol* class_name, return true; } - if (vmClasses::ClassLoader_klass_loaded()) { + if (vmClasses::ClassLoader_klass_is_loaded()) { const Klass* const super_klass = parser.super_klass(); if (super_klass != nullptr) { if (super_klass->is_subtype_of(vmClasses::ClassLoader_klass())) { diff --git a/src/hotspot/share/oops/instanceMirrorKlass.hpp b/src/hotspot/share/oops/instanceMirrorKlass.hpp index e9928647db9..4546f904eca 100644 --- a/src/hotspot/share/oops/instanceMirrorKlass.hpp +++ b/src/hotspot/share/oops/instanceMirrorKlass.hpp @@ -41,7 +41,6 @@ class ClassFileParser; class InstanceMirrorKlass: public InstanceKlass { - friend class VMStructs; friend class InstanceKlass; public: diff --git a/src/hotspot/share/oops/instanceStackChunkKlass.hpp b/src/hotspot/share/oops/instanceStackChunkKlass.hpp index 19ce37c4ddd..5afbc5d00eb 100644 --- a/src/hotspot/share/oops/instanceStackChunkKlass.hpp +++ b/src/hotspot/share/oops/instanceStackChunkKlass.hpp @@ -100,7 +100,6 @@ Chunk layout: class InstanceStackChunkKlass: public InstanceKlass { - friend class VMStructs; friend class InstanceKlass; friend class Continuations; diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index a93875b86a5..208a274d766 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -614,8 +614,7 @@ GrowableArray* Klass::compute_secondary_supers(int num_extra_slots, // subklass links. Used by the compiler (and vtable initialization) // May be cleaned concurrently, so must use the Compile_lock. -// The log parameter is for clean_weak_klass_links to report unlinked classes. -Klass* Klass::subklass(bool log) const { +Klass* Klass::subklass() const { // Need load_acquire on the _subklass, because it races with inserts that // publishes freshly initialized data. for (Klass* chain = AtomicAccess::load_acquire(&_subklass); @@ -626,11 +625,6 @@ Klass* Klass::subklass(bool log) const { { if (chain->is_loader_alive()) { return chain; - } else if (log) { - if (log_is_enabled(Trace, class, unload)) { - ResourceMark rm; - log_trace(class, unload)("unlinking class (subclass): %s", chain->external_name()); - } } } return nullptr; @@ -701,15 +695,20 @@ void Klass::append_to_sibling_list() { DEBUG_ONLY(verify();) } -void Klass::clean_subklass() { +// The log parameter is for clean_weak_klass_links to report unlinked classes. +Klass* Klass::clean_subklass(bool log) { for (;;) { // Need load_acquire, due to contending with concurrent inserts Klass* subklass = AtomicAccess::load_acquire(&_subklass); if (subklass == nullptr || subklass->is_loader_alive()) { - return; + return subklass; + } + if (log && log_is_enabled(Trace, class, unload)) { + ResourceMark rm; + log_trace(class, unload)("unlinking class (subclass): %s", subklass->external_name()); } // Try to fix _subklass until it points at something not dead. - AtomicAccess::cmpxchg(&_subklass, subklass, subklass->next_sibling()); + AtomicAccess::cmpxchg(&_subklass, subklass, subklass->next_sibling(log)); } } @@ -728,8 +727,7 @@ void Klass::clean_weak_klass_links(bool unloading_occurred, bool clean_alive_kla assert(current->is_loader_alive(), "just checking, this should be live"); // Find and set the first alive subklass - Klass* sub = current->subklass(true); - current->clean_subklass(); + Klass* sub = current->clean_subklass(true); if (sub != nullptr) { stack.push(sub); } @@ -874,11 +872,10 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec // modify the CLD list outside a safepoint. 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); } + // Add to class loader list first before creating the mirror + // (same order as class file parsing) + loader_data->add_class(this); Handle loader(THREAD, loader_data->class_loader()); ModuleEntry* module_entry = nullptr; diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 70d9ce3a881..db3360b080e 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -300,7 +300,7 @@ class Klass : public Metadata { // Use InstanceKlass::contains_field_offset to classify field offsets. // sub/superklass links - Klass* subklass(bool log = false) const; + Klass* subklass() const; Klass* next_sibling(bool log = false) const; void append_to_sibling_list(); // add newly created receiver to superklass' subklass list @@ -413,9 +413,9 @@ class Klass : public Metadata { virtual ModuleEntry* module() const = 0; virtual PackageEntry* package() const = 0; + void set_next_sibling(Klass* s); protected: // internal accessors void set_subklass(Klass* s); - void set_next_sibling(Klass* s); private: static uint8_t compute_hash_slot(Symbol* s); @@ -743,7 +743,7 @@ class Klass : public Metadata { inline bool is_loader_alive() const; inline bool is_loader_present_and_alive() const; - void clean_subklass(); + Klass* clean_subklass(bool log = false); // Clean out unnecessary weak klass links from the whole klass hierarchy. static void clean_weak_klass_links(bool unloading_occurred, bool clean_alive_klasses = true); diff --git a/src/hotspot/share/oops/objArrayKlass.cpp b/src/hotspot/share/oops/objArrayKlass.cpp index 48d56ddc540..ba2bc7f889f 100644 --- a/src/hotspot/share/oops/objArrayKlass.cpp +++ b/src/hotspot/share/oops/objArrayKlass.cpp @@ -78,7 +78,7 @@ ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_da // Eagerly allocate the direct array supertype. Klass* super_klass = nullptr; - if (!Universe::is_bootstrapping() || vmClasses::Object_klass_loaded()) { + if (!Universe::is_bootstrapping() || vmClasses::Object_klass_is_loaded()) { assert(MultiArray_lock->holds_lock(THREAD), "must hold lock after bootstrapping"); Klass* element_super = element_klass->super(); if (element_super != nullptr) { diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index c768d13fe59..dcf95cf4653 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -25,7 +25,6 @@ #include "cds/cdsConfig.hpp" #include "ci/ciEnv.hpp" #include "ci/ciMetadata.hpp" -#include "classfile/classLoaderData.hpp" #include "classfile/compactHashtable.hpp" #include "classfile/javaClasses.hpp" #include "classfile/symbolTable.hpp" @@ -312,7 +311,6 @@ void CompileTrainingData::notice_jit_observation(ciEnv* env, ciBaseObject* what) CompileTask* task = env->task(); assert(task != nullptr, ""); Method* method = task->method(); - InstanceKlass* compiling_klass = method->method_holder(); if (what->is_metadata()) { ciMetadata* md = what->as_metadata(); if (md->is_loaded() && md->is_instance_klass()) { @@ -328,7 +326,9 @@ void CompileTrainingData::notice_jit_observation(ciEnv* env, ciBaseObject* what) // This JIT task is (probably) requesting that ik be initialized, // so add him to my _init_deps list. TrainingDataLocker l; - add_init_dep(ktd); + if (l.can_add()) { + add_init_dep(ktd); + } } } } @@ -339,13 +339,7 @@ void KlassTrainingData::prepare(Visitor& visitor) { return; } visitor.visit(this); - ClassLoaderData* loader_data = nullptr; - if (_holder != nullptr) { - loader_data = _holder->class_loader_data(); - } else { - loader_data = java_lang_ClassLoader::loader_data(SystemDictionary::java_system_loader()); // default CLD - } - _comp_deps.prepare(loader_data); + _comp_deps.prepare(); } void MethodTrainingData::prepare(Visitor& visitor) { @@ -373,9 +367,8 @@ void CompileTrainingData::prepare(Visitor& visitor) { } visitor.visit(this); method()->prepare(visitor); - ClassLoaderData* loader_data = _method->klass()->class_loader_data(); - _init_deps.prepare(loader_data); - _ci_records.prepare(loader_data); + _init_deps.prepare(); + _ci_records.prepare(); } KlassTrainingData* KlassTrainingData::make(InstanceKlass* holder, bool null_if_not_found) { @@ -618,7 +611,7 @@ void CompileTrainingData::verify(bool verify_dep_counter) { for (int i = 0; i < init_dep_count(); i++) { KlassTrainingData* ktd = init_dep(i); if (ktd->has_holder() && ktd->holder()->defined_by_other_loaders()) { - LogStreamHandle(Warning, training) log; + LogStreamHandle(Info, training) log; if (log.is_enabled()) { ResourceMark rm; log.print("CTD "); print_value_on(&log); @@ -767,7 +760,7 @@ void CompileTrainingData::metaspace_pointers_do(MetaspaceClosure* iter) { } template -void TrainingData::DepList::prepare(ClassLoaderData* loader_data) { +void TrainingData::DepList::prepare() { if (_deps == nullptr && _deps_dyn != nullptr) { int len = _deps_dyn->length(); _deps = MetadataFactory::new_array_from_c_heap(len, mtClassShared); diff --git a/src/hotspot/share/oops/trainingData.hpp b/src/hotspot/share/oops/trainingData.hpp index d214a03a284..fbecb5c46bf 100644 --- a/src/hotspot/share/oops/trainingData.hpp +++ b/src/hotspot/share/oops/trainingData.hpp @@ -26,7 +26,6 @@ #define SHARE_OOPS_TRAININGDATA_HPP #include "cds/cdsConfig.hpp" -#include "classfile/classLoaderData.hpp" #include "classfile/compactHashtable.hpp" #include "compiler/compiler_globals.hpp" #include "compiler/compilerDefinitions.hpp" @@ -402,7 +401,7 @@ class TrainingData : public Metadata { _deps_dyn = nullptr; } #endif - void prepare(ClassLoaderData* loader_data); + void prepare(); void metaspace_pointers_do(MetaspaceClosure *iter); }; @@ -479,10 +478,6 @@ class KlassTrainingData : public TrainingData { } virtual KlassTrainingData* as_KlassTrainingData() const { return const_cast(this); }; - ClassLoaderData* class_loader_data() { - assert(has_holder(), ""); - return holder()->class_loader_data(); - } void notice_fully_initialized() NOT_CDS_RETURN; void print_on(outputStream* st, bool name_only) const; @@ -620,8 +615,8 @@ class CompileTrainingData : public TrainingData { #if INCLUDE_CDS void remove_unshareable_info() { _data.remove_unshareable_info(); } #endif - void prepare(ClassLoaderData* loader_data) { - _data.prepare(loader_data); + void prepare() { + _data.prepare(); } void metaspace_pointers_do(MetaspaceClosure *iter) { _data.metaspace_pointers_do(iter); @@ -639,8 +634,8 @@ class CompileTrainingData : public TrainingData { ciMethod__inline_instructions_size.remove_unshareable_info(); } #endif - void prepare(ClassLoaderData* loader_data) { - ciMethod__inline_instructions_size.prepare(loader_data); + void prepare() { + ciMethod__inline_instructions_size.prepare(); } void metaspace_pointers_do(MetaspaceClosure *iter) { ciMethod__inline_instructions_size.metaspace_pointers_do(iter); diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index e09d8cabe2c..483cb731103 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -169,10 +169,6 @@ JVMState* DirectCallGenerator::generate(JVMState* jvms) { } // Mark the call node as virtual, sort of: call->set_optimized_virtual(true); - if (method()->is_method_handle_intrinsic() || - method()->is_compiled_lambda_form()) { - call->set_method_handle_invoke(true); - } } kit.set_arguments_for_java_call(call); kit.set_edges_for_java_call(call, false, _separate_io_proj); @@ -469,6 +465,10 @@ class LateInlineVirtualCallGenerator : public VirtualCallGenerator { // Convert the CallDynamicJava into an inline virtual void do_late_inline(); + virtual ciMethod* callee_method() { + return _callee; + } + virtual void set_callee_method(ciMethod* m) { assert(_callee == nullptr || _callee == m, "repeated inline attempt with different callee"); _callee = m; diff --git a/src/hotspot/share/opto/callGenerator.hpp b/src/hotspot/share/opto/callGenerator.hpp index 82b195e0c76..e24ea5e5356 100644 --- a/src/hotspot/share/opto/callGenerator.hpp +++ b/src/hotspot/share/opto/callGenerator.hpp @@ -88,6 +88,7 @@ class CallGenerator : public ArenaObj { virtual void set_unique_id(jlong id) { fatal("unique id only for late inlines"); }; virtual jlong unique_id() const { fatal("unique id only for late inlines"); return 0; }; + virtual ciMethod* callee_method() { ShouldNotReachHere(); } virtual void set_callee_method(ciMethod* callee) { ShouldNotReachHere(); } // Note: It is possible for a CG to be both inline and virtual. diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index 995208ba24f..ef1ebc5cef9 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1228,33 +1228,37 @@ Node* CallDynamicJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) { assert(IncrementalInlineVirtual, "required"); assert(cg->call_node() == this, "mismatch"); - // Recover symbolic info for method resolution. - ciMethod* caller = jvms()->method(); - ciBytecodeStream iter(caller); - iter.force_bci(jvms()->bci()); - - bool not_used1; - ciSignature* not_used2; - ciMethod* orig_callee = iter.get_method(not_used1, ¬_used2); // callee in the bytecode - ciKlass* holder = iter.get_declared_method_holder(); - if (orig_callee->is_method_handle_intrinsic()) { - assert(_override_symbolic_info, "required"); - orig_callee = method(); - holder = method()->holder(); - } + if (cg->callee_method() == nullptr) { + // Recover symbolic info for method resolution. + ciMethod* caller = jvms()->method(); + ciBytecodeStream iter(caller); + iter.force_bci(jvms()->bci()); + + bool not_used1; + ciSignature* not_used2; + ciMethod* orig_callee = iter.get_method(not_used1, ¬_used2); // callee in the bytecode + ciKlass* holder = iter.get_declared_method_holder(); + if (orig_callee->is_method_handle_intrinsic()) { + assert(_override_symbolic_info, "required"); + orig_callee = method(); + holder = method()->holder(); + } - ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder); + ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder); - Node* receiver_node = in(TypeFunc::Parms); - const TypeOopPtr* receiver_type = phase->type(receiver_node)->isa_oopptr(); + Node* receiver_node = in(TypeFunc::Parms); + const TypeOopPtr* receiver_type = phase->type(receiver_node)->isa_oopptr(); - int not_used3; - bool call_does_dispatch; - ciMethod* callee = phase->C->optimize_virtual_call(caller, klass, holder, orig_callee, receiver_type, true /*is_virtual*/, - call_does_dispatch, not_used3); // out-parameters - if (!call_does_dispatch) { + int not_used3; + bool call_does_dispatch; + ciMethod* callee = phase->C->optimize_virtual_call(caller, klass, holder, orig_callee, receiver_type, true /*is_virtual*/, + call_does_dispatch, not_used3); // out-parameters + if (!call_does_dispatch) { + cg->set_callee_method(callee); + } + } + if (cg->callee_method() != nullptr) { // Register for late inlining. - cg->set_callee_method(callee); register_for_late_inline(); // MH late inlining prepends to the list, so do the same } } else { diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 093c47194ef..9029a009989 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -778,7 +778,6 @@ class CallJavaNode : public CallNode { ciMethod* _method; // Method being direct called bool _optimized_virtual; - bool _method_handle_invoke; bool _override_symbolic_info; // Override symbolic call site info from bytecode bool _arg_escape; // ArgEscape in parameter list public: @@ -786,7 +785,6 @@ class CallJavaNode : public CallNode { : CallNode(tf, addr, TypePtr::BOTTOM), _method(method), _optimized_virtual(false), - _method_handle_invoke(false), _override_symbolic_info(false), _arg_escape(false) { @@ -798,8 +796,6 @@ class CallJavaNode : public CallNode { void set_method(ciMethod *m) { _method = m; } void set_optimized_virtual(bool f) { _optimized_virtual = f; } bool is_optimized_virtual() const { return _optimized_virtual; } - void set_method_handle_invoke(bool f) { _method_handle_invoke = f; } - bool is_method_handle_invoke() const { return _method_handle_invoke; } void set_override_symbolic_info(bool f) { _override_symbolic_info = f; } bool override_symbolic_info() const { return _override_symbolic_info; } void set_arg_escape(bool f) { _arg_escape = f; } diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index f828dfb6928..6babc13e1b3 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -650,7 +650,6 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, _igv_idx(0), _trace_opto_output(directive->TraceOptoOutputOption), #endif - _has_method_handle_invokes(false), _clinit_barrier_on_entry(false), _stress_seed(0), _comp_arena(mtCompiler, Arena::Tag::tag_comp), @@ -925,7 +924,6 @@ Compile::Compile(ciEnv* ci_env, _igv_idx(0), _trace_opto_output(directive->TraceOptoOutputOption), #endif - _has_method_handle_invokes(false), _clinit_barrier_on_entry(false), _stress_seed(0), _comp_arena(mtCompiler, Arena::Tag::tag_comp), @@ -2106,6 +2104,12 @@ bool Compile::inline_incrementally_one() { bool is_scheduled_for_igvn_before = C->igvn_worklist()->member(cg->call_node()); bool does_dispatch = cg->is_virtual_late_inline() || cg->is_mh_late_inline(); if (inlining_incrementally() || does_dispatch) { // a call can be either inlined or strength-reduced to a direct call + if (should_stress_inlining()) { + // randomly add repeated inline attempt if stress-inlining + cg->call_node()->set_generator(cg); + C->igvn_worklist()->push(cg->call_node()); + continue; + } cg->do_late_inline(); assert(_late_inlines.at(i) == cg, "no insertions before current position allowed"); if (failing()) { @@ -5374,3 +5378,158 @@ Node* Compile::narrow_value(BasicType bt, Node* value, const Type* type, PhaseGV void Compile::record_method_not_compilable_oom() { record_method_not_compilable(CompilationMemoryStatistic::failure_reason_memlimit()); } + +#ifndef PRODUCT +// Collects all the control inputs from nodes on the worklist and from their data dependencies +static void find_candidate_control_inputs(Unique_Node_List& worklist, Unique_Node_List& candidates) { + // Follow non-control edges until we reach CFG nodes + for (uint i = 0; i < worklist.size(); i++) { + const Node* n = worklist.at(i); + for (uint j = 0; j < n->req(); j++) { + Node* in = n->in(j); + if (in == nullptr || in->is_Root()) { + continue; + } + if (in->is_CFG()) { + if (in->is_Call()) { + // The return value of a call is only available if the call did not result in an exception + Node* control_proj_use = in->as_Call()->proj_out(TypeFunc::Control)->unique_out(); + if (control_proj_use->is_Catch()) { + Node* fall_through = control_proj_use->as_Catch()->proj_out(CatchProjNode::fall_through_index); + candidates.push(fall_through); + continue; + } + } + + if (in->is_Multi()) { + // We got here by following data inputs so we should only have one control use + // (no IfNode, etc) + assert(!n->is_MultiBranch(), "unexpected node type: %s", n->Name()); + candidates.push(in->as_Multi()->proj_out(TypeFunc::Control)); + } else { + candidates.push(in); + } + } else { + worklist.push(in); + } + } + } +} + +// Returns the candidate node that is a descendant to all the other candidates +static Node* pick_control(Unique_Node_List& candidates) { + Unique_Node_List worklist; + worklist.copy(candidates); + + // Traverse backwards through the CFG + for (uint i = 0; i < worklist.size(); i++) { + const Node* n = worklist.at(i); + if (n->is_Root()) { + continue; + } + for (uint j = 0; j < n->req(); j++) { + // Skip backedge of loops to avoid cycles + if (n->is_Loop() && j == LoopNode::LoopBackControl) { + continue; + } + + Node* pred = n->in(j); + if (pred != nullptr && pred != n && pred->is_CFG()) { + worklist.push(pred); + // if pred is an ancestor of n, then pred is an ancestor to at least one candidate + candidates.remove(pred); + } + } + } + + assert(candidates.size() == 1, "unexpected control flow"); + return candidates.at(0); +} + +// Initialize a parameter input for a debug print call, using a placeholder for jlong and jdouble +static void debug_print_init_parm(Node* call, Node* parm, Node* half, int* pos) { + call->init_req((*pos)++, parm); + const BasicType bt = parm->bottom_type()->basic_type(); + if (bt == T_LONG || bt == T_DOUBLE) { + call->init_req((*pos)++, half); + } +} + +Node* Compile::make_debug_print_call(const char* str, address call_addr, PhaseGVN* gvn, + Node* parm0, Node* parm1, + Node* parm2, Node* parm3, + Node* parm4, Node* parm5, + Node* parm6) const { + Node* str_node = gvn->transform(new ConPNode(TypeRawPtr::make(((address) str)))); + const TypeFunc* type = OptoRuntime::debug_print_Type(parm0, parm1, parm2, parm3, parm4, parm5, parm6); + Node* call = new CallLeafNode(type, call_addr, "debug_print", TypeRawPtr::BOTTOM); + + // find the most suitable control input + Unique_Node_List worklist, candidates; + if (parm0 != nullptr) { worklist.push(parm0); + if (parm1 != nullptr) { worklist.push(parm1); + if (parm2 != nullptr) { worklist.push(parm2); + if (parm3 != nullptr) { worklist.push(parm3); + if (parm4 != nullptr) { worklist.push(parm4); + if (parm5 != nullptr) { worklist.push(parm5); + if (parm6 != nullptr) { worklist.push(parm6); + /* close each nested if ===> */ } } } } } } } + find_candidate_control_inputs(worklist, candidates); + Node* control = nullptr; + if (candidates.size() == 0) { + control = C->start()->proj_out(TypeFunc::Control); + } else { + control = pick_control(candidates); + } + + // find all the previous users of the control we picked + GrowableArray users_of_control; + for (DUIterator_Fast kmax, i = control->fast_outs(kmax); i < kmax; i++) { + Node* use = control->fast_out(i); + if (use->is_CFG() && use != control) { + users_of_control.push(use); + } + } + + // we do not actually care about IO and memory as it uses neither + call->init_req(TypeFunc::Control, control); + call->init_req(TypeFunc::I_O, top()); + call->init_req(TypeFunc::Memory, top()); + call->init_req(TypeFunc::FramePtr, C->start()->proj_out(TypeFunc::FramePtr)); + call->init_req(TypeFunc::ReturnAdr, top()); + + int pos = TypeFunc::Parms; + call->init_req(pos++, str_node); + if (parm0 != nullptr) { debug_print_init_parm(call, parm0, top(), &pos); + if (parm1 != nullptr) { debug_print_init_parm(call, parm1, top(), &pos); + if (parm2 != nullptr) { debug_print_init_parm(call, parm2, top(), &pos); + if (parm3 != nullptr) { debug_print_init_parm(call, parm3, top(), &pos); + if (parm4 != nullptr) { debug_print_init_parm(call, parm4, top(), &pos); + if (parm5 != nullptr) { debug_print_init_parm(call, parm5, top(), &pos); + if (parm6 != nullptr) { debug_print_init_parm(call, parm6, top(), &pos); + /* close each nested if ===> */ } } } } } } } + assert(call->in(call->req()-1) != nullptr, "must initialize all parms"); + + call = gvn->transform(call); + Node* call_control_proj = gvn->transform(new ProjNode(call, TypeFunc::Control)); + + // rewire previous users to have the new call as control instead + PhaseIterGVN* igvn = gvn->is_IterGVN(); + for (int i = 0; i < users_of_control.length(); i++) { + Node* use = users_of_control.at(i); + for (uint j = 0; j < use->req(); j++) { + if (use->in(j) == control) { + if (igvn != nullptr) { + igvn->replace_input_of(use, j, call_control_proj); + } else { + gvn->hash_delete(use); + use->set_req(j, call_control_proj); + gvn->hash_insert(use); + } + } + } + } + + return call; +} +#endif // !PRODUCT diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 1cfcdca9610..66a5497a7ad 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -354,8 +354,6 @@ class Compile : public Phase { bool _parsed_irreducible_loop; // True if ciTypeFlow detected irreducible loops during parsing #endif bool _has_irreducible_loop; // Found irreducible loops - // JSR 292 - bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. bool _has_monitors; // Metadata transfered to nmethod to enable Continuations lock-detection fastpath bool _has_scoped_access; // For shared scope closure bool _clinit_barrier_on_entry; // True if clinit barrier is needed on nmethod entry @@ -666,10 +664,6 @@ class Compile : public Phase { bool has_irreducible_loop() const { return _has_irreducible_loop; } void set_has_irreducible_loop(bool z) { _has_irreducible_loop = z; } - // JSR 292 - bool has_method_handle_invokes() const { return _has_method_handle_invokes; } - void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } - Ticks _latest_stage_start_counter; void begin_method(); @@ -1100,7 +1094,8 @@ class Compile : public Phase { bool inline_incrementally_one(); void inline_incrementally_cleanup(PhaseIterGVN& igvn); void inline_incrementally(PhaseIterGVN& igvn); - bool should_delay_inlining() { return AlwaysIncrementalInline || (StressIncrementalInlining && (random() % 2) == 0); } + bool should_stress_inlining() { return StressIncrementalInlining && (random() % 2) == 0; } + bool should_delay_inlining() { return AlwaysIncrementalInline || should_stress_inlining(); } void inline_string_calls(bool parse_time); void inline_boxing_calls(PhaseIterGVN& igvn); bool optimize_loops(PhaseIterGVN& igvn, LoopOptsMode mode); @@ -1321,6 +1316,28 @@ class Compile : public Phase { BasicType out_bt, BasicType in_bt); static Node* narrow_value(BasicType bt, Node* value, const Type* type, PhaseGVN* phase, bool transform_res); + +#ifndef PRODUCT +private: + // getting rid of the template makes things easier + Node* make_debug_print_call(const char* str, address call_addr, PhaseGVN* gvn, + Node* parm0 = nullptr, Node* parm1 = nullptr, + Node* parm2 = nullptr, Node* parm3 = nullptr, + Node* parm4 = nullptr, Node* parm5 = nullptr, + Node* parm6 = nullptr) const; + +public: + // Creates a CallLeafNode for a runtime call that prints a static string and the values of the + // nodes passed as arguments. + // This function also takes care of doing the necessary wiring, including finding a suitable control + // based on the nodes that need to be printed. Note that passing nodes that have incompatible controls + // is undefined behavior. + template + Node* make_debug_print(const char* str, PhaseGVN* gvn, NN... in) { + address call_addr = CAST_FROM_FN_PTR(address, SharedRuntime::debug_print); + return make_debug_print_call(str, call_addr, gvn, in...); + } +#endif }; #endif // SHARE_OPTO_COMPILE_HPP diff --git a/src/hotspot/share/opto/divnode.cpp b/src/hotspot/share/opto/divnode.cpp index 213f2e1e9a8..823745ea8e7 100644 --- a/src/hotspot/share/opto/divnode.cpp +++ b/src/hotspot/share/opto/divnode.cpp @@ -1206,6 +1206,11 @@ static const Type* mod_value(const PhaseGVN* phase, const Node* in1, const Node* if (t1 == Type::TOP) { return Type::TOP; } if (t2 == Type::TOP) { return Type::TOP; } + // Mod by zero? Throw exception at runtime! + if (t2 == TypeInteger::zero(bt)) { + return Type::TOP; + } + // We always generate the dynamic check for 0. // 0 MOD X is 0 if (t1 == TypeInteger::zero(bt)) { return t1; } @@ -1215,11 +1220,6 @@ static const Type* mod_value(const PhaseGVN* phase, const Node* in1, const Node* return TypeInteger::zero(bt); } - // Mod by zero? Throw exception at runtime! - if (t2 == TypeInteger::zero(bt)) { - return Type::TOP; - } - const TypeInteger* i1 = t1->is_integer(bt); const TypeInteger* i2 = t2->is_integer(bt); if (i1->is_con() && i2->is_con()) { diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index e6a593770b4..cbf0666c00e 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -201,7 +201,7 @@ bool ConnectionGraph::compute_escape() { if (!UseStoreStoreForCtor || n->req() > MemBarNode::Precedent) { storestore_worklist.append(n->as_MemBarStoreStore()); } - break; + // If MemBarStoreStore has a precedent edge add it to the worklist (like MemBarRelease) case Op_MemBarRelease: if (n->req() > MemBarNode::Precedent) { record_for_optimizer(n); diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp index ca1863b685e..fd7644f8587 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -946,17 +946,6 @@ uint PhaseCFG::sched_call(Block* block, uint node_cnt, Node_List& worklist, Grow // references but there no way to handle oops differently than other // pointers as far as the kill mask goes. bool exclude_soe = op == Op_CallRuntime; - - // If the call is a MethodHandle invoke, we need to exclude the - // register which is used to save the SP value over MH invokes from - // the mask. Otherwise this register could be used for - // deoptimization information. - if (op == Op_CallStaticJava) { - MachCallStaticJavaNode* mcallstaticjava = (MachCallStaticJavaNode*) mcall; - if (mcallstaticjava->_method_handle_invoke) - proj->_rout.OR(Matcher::method_handle_invoke_SP_save_mask()); - } - add_call_kills(proj, regs, save_policy, exclude_soe); return node_cnt; diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 5f5e0520e7e..f92833e9e1c 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1668,6 +1668,30 @@ void PhaseIdealLoop::insert_vector_post_loop(IdealLoopTree *loop, Node_List &old loop->record_for_igvn(); } +Node* PhaseIdealLoop::find_last_store_in_outer_loop(Node* store, const IdealLoopTree* outer_loop) { + assert(store != nullptr && store->is_Store(), "starting point should be a store node"); + // Follow the memory uses until we get out of the loop. + // Store nodes in the outer loop body were moved by PhaseIdealLoop::try_move_store_after_loop. + // Because of the conditions in try_move_store_after_loop (no other usage in the loop body + // except for the phi node associated with the loop head), we have the guarantee of a + // linear memory subgraph within the outer loop body. + Node* last = store; + Node* unique_next = store; + do { + last = unique_next; + for (DUIterator_Fast imax, l = last->fast_outs(imax); l < imax; l++) { + Node* use = last->fast_out(l); + if (use->is_Store() && use->in(MemNode::Memory) == last) { + if (is_member(outer_loop, get_ctrl(use))) { + assert(unique_next == last, "memory node should only have one usage in the loop body"); + unique_next = use; + } + } + } + } while (last != unique_next); + return last; +} + //------------------------------insert_post_loop------------------------------- // Insert post loops. Add a post loop to the given loop passed. Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, @@ -1758,6 +1782,26 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, cur_phi->set_req(LoopNode::EntryControl, fallnew); } } + // Store nodes that were moved to the outer loop by PhaseIdealLoop::try_move_store_after_loop + // do not have an associated Phi node. Such nodes are attached to the false projection of the CountedLoopEnd node, + // right after the execution of the inner CountedLoop. + // We have to make sure that such stores in the post loop have the right memory inputs from the main loop + // The moved store node is always attached right after the inner loop exit, and just before the safepoint + const Node* if_false = main_end->proj_out(false); + for (DUIterator j = if_false->outs(); if_false->has_out(j); j++) { + Node* store = if_false->out(j); + if (store->is_Store()) { + // We only make changes if the memory input of the store is outside the outer loop body, + // as this is when we would normally expect a Phi as input. If the memory input + // is in the loop body as well, then we can safely assume it is still correct as the entire + // body was cloned as a unit + if (!is_member(outer_loop, get_ctrl(store->in(MemNode::Memory)))) { + Node* mem_out = find_last_store_in_outer_loop(store, outer_loop); + Node* store_new = old_new[store->_idx]; + store_new->set_req(MemNode::Memory, mem_out); + } + } + } DEBUG_ONLY(ensure_zero_trip_guard_proj(post_head->in(LoopNode::EntryControl), false);) initialize_assertion_predicates_for_post_loop(main_head, post_head, first_node_index_in_cloned_loop_body); diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index bdccffa18b2..2645df86d96 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1380,6 +1380,9 @@ class PhaseIdealLoop : public PhaseTransform { // during RCE, unrolling and aligning loops. void insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_new, bool peel_only ); + // Find the last store in the body of an OuterStripMinedLoop when following memory uses + Node *find_last_store_in_outer_loop(Node* store, const IdealLoopTree* outer_loop); + // Add post loop after the given loop. Node *insert_post_loop(IdealLoopTree* loop, Node_List& old_new, CountedLoopNode* main_head, CountedLoopEndNode* main_end, diff --git a/src/hotspot/share/opto/machnode.cpp b/src/hotspot/share/opto/machnode.cpp index e5acad98c09..5da929e4748 100644 --- a/src/hotspot/share/opto/machnode.cpp +++ b/src/hotspot/share/opto/machnode.cpp @@ -772,8 +772,6 @@ bool MachCallJavaNode::cmp( const Node &n ) const { } #ifndef PRODUCT void MachCallJavaNode::dump_spec(outputStream *st) const { - if (_method_handle_invoke) - st->print("MethodHandle "); if (_method) { _method->print_short_name(st); st->print(" "); @@ -794,10 +792,7 @@ const RegMask &MachCallJavaNode::in_RegMask(uint idx) const { } // Values outside the domain represent debug info Matcher* m = Compile::current()->matcher(); - // If this call is a MethodHandle invoke we have to use a different - // debugmask which does not include the register we use to save the - // SP over MH invokes. - RegMask** debugmask = _method_handle_invoke ? m->idealreg2mhdebugmask : m->idealreg2debugmask; + RegMask** debugmask = m->idealreg2debugmask; return *debugmask[in(idx)->ideal_reg()]; } diff --git a/src/hotspot/share/opto/machnode.hpp b/src/hotspot/share/opto/machnode.hpp index 5490f717a25..43e9a35df34 100644 --- a/src/hotspot/share/opto/machnode.hpp +++ b/src/hotspot/share/opto/machnode.hpp @@ -960,7 +960,6 @@ class MachCallJavaNode : public MachCallNode { ciMethod* _method; // Method being direct called bool _override_symbolic_info; // Override symbolic call site info from bytecode bool _optimized_virtual; // Tells if node is a static call or an optimized virtual - bool _method_handle_invoke; // Tells if the call has to preserve SP bool _arg_escape; // ArgEscape in parameter list MachCallJavaNode() : MachCallNode(), _override_symbolic_info(false) { init_class_id(Class_MachCallJava); diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index b43bc05c465..7d73487cf88 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -50,8 +50,6 @@ const RegMask *Matcher::idealreg2regmask[_last_machine_leaf]; RegMask Matcher::mreg2regmask[_last_Mach_Reg]; RegMask Matcher::caller_save_regmask; RegMask Matcher::caller_save_regmask_exclude_soe; -RegMask Matcher::mh_caller_save_regmask; -RegMask Matcher::mh_caller_save_regmask_exclude_soe; RegMask Matcher::STACK_ONLY_mask; RegMask Matcher::c_frame_ptr_mask; const uint Matcher::_begin_rematerialize = _BEGIN_REMATERIALIZE; @@ -114,21 +112,6 @@ Matcher::Matcher() idealreg2debugmask [Op_RegFlags] = nullptr; idealreg2debugmask [Op_RegVectMask] = nullptr; - idealreg2mhdebugmask[Op_RegI] = nullptr; - idealreg2mhdebugmask[Op_RegN] = nullptr; - idealreg2mhdebugmask[Op_RegL] = nullptr; - idealreg2mhdebugmask[Op_RegF] = nullptr; - idealreg2mhdebugmask[Op_RegD] = nullptr; - idealreg2mhdebugmask[Op_RegP] = nullptr; - idealreg2mhdebugmask[Op_VecA] = nullptr; - idealreg2mhdebugmask[Op_VecS] = nullptr; - idealreg2mhdebugmask[Op_VecD] = nullptr; - idealreg2mhdebugmask[Op_VecX] = nullptr; - idealreg2mhdebugmask[Op_VecY] = nullptr; - idealreg2mhdebugmask[Op_VecZ] = nullptr; - idealreg2mhdebugmask[Op_RegFlags] = nullptr; - idealreg2mhdebugmask[Op_RegVectMask] = nullptr; - DEBUG_ONLY(_mem_node = nullptr;) // Ideal memory node consumed by mach node } @@ -465,7 +448,7 @@ int Matcher::scalable_predicate_reg_slots() { return round_up_power_of_2(slots); } -#define NOF_STACK_MASKS (3*13) +#define NOF_STACK_MASKS (2*13) // Create the initial stack mask used by values spilling to the stack. // Disallow any debug info in outgoing argument areas by setting the @@ -480,51 +463,12 @@ void Matcher::init_first_stack_mask() { new (rms + i) RegMask(C->comp_arena()); } - idealreg2spillmask [Op_RegN] = &rms[0]; - idealreg2spillmask [Op_RegI] = &rms[1]; - idealreg2spillmask [Op_RegL] = &rms[2]; - idealreg2spillmask [Op_RegF] = &rms[3]; - idealreg2spillmask [Op_RegD] = &rms[4]; - idealreg2spillmask [Op_RegP] = &rms[5]; - - idealreg2debugmask [Op_RegN] = &rms[6]; - idealreg2debugmask [Op_RegI] = &rms[7]; - idealreg2debugmask [Op_RegL] = &rms[8]; - idealreg2debugmask [Op_RegF] = &rms[9]; - idealreg2debugmask [Op_RegD] = &rms[10]; - idealreg2debugmask [Op_RegP] = &rms[11]; - - idealreg2mhdebugmask[Op_RegN] = &rms[12]; - idealreg2mhdebugmask[Op_RegI] = &rms[13]; - idealreg2mhdebugmask[Op_RegL] = &rms[14]; - idealreg2mhdebugmask[Op_RegF] = &rms[15]; - idealreg2mhdebugmask[Op_RegD] = &rms[16]; - idealreg2mhdebugmask[Op_RegP] = &rms[17]; - - idealreg2spillmask [Op_VecA] = &rms[18]; - idealreg2spillmask [Op_VecS] = &rms[19]; - idealreg2spillmask [Op_VecD] = &rms[20]; - idealreg2spillmask [Op_VecX] = &rms[21]; - idealreg2spillmask [Op_VecY] = &rms[22]; - idealreg2spillmask [Op_VecZ] = &rms[23]; - - idealreg2debugmask [Op_VecA] = &rms[24]; - idealreg2debugmask [Op_VecS] = &rms[25]; - idealreg2debugmask [Op_VecD] = &rms[26]; - idealreg2debugmask [Op_VecX] = &rms[27]; - idealreg2debugmask [Op_VecY] = &rms[28]; - idealreg2debugmask [Op_VecZ] = &rms[29]; - - idealreg2mhdebugmask[Op_VecA] = &rms[30]; - idealreg2mhdebugmask[Op_VecS] = &rms[31]; - idealreg2mhdebugmask[Op_VecD] = &rms[32]; - idealreg2mhdebugmask[Op_VecX] = &rms[33]; - idealreg2mhdebugmask[Op_VecY] = &rms[34]; - idealreg2mhdebugmask[Op_VecZ] = &rms[35]; - - idealreg2spillmask [Op_RegVectMask] = &rms[36]; - idealreg2debugmask [Op_RegVectMask] = &rms[37]; - idealreg2mhdebugmask[Op_RegVectMask] = &rms[38]; + int index = 0; + for (int i = Op_RegN; i <= Op_RegVectMask; ++i) { + idealreg2spillmask[i] = &rms[index++]; + idealreg2debugmask[i] = &rms[index++]; + } + assert(index == NOF_STACK_MASKS, "wrong size"); // At first, start with the empty mask C->FIRST_STACK_mask().Clear(); @@ -710,26 +654,10 @@ void Matcher::init_first_stack_mask() { *idealreg2debugmask [Op_VecY] = *idealreg2spillmask[Op_VecY]; *idealreg2debugmask [Op_VecZ] = *idealreg2spillmask[Op_VecZ]; - *idealreg2mhdebugmask[Op_RegN] = *idealreg2spillmask[Op_RegN]; - *idealreg2mhdebugmask[Op_RegI] = *idealreg2spillmask[Op_RegI]; - *idealreg2mhdebugmask[Op_RegL] = *idealreg2spillmask[Op_RegL]; - *idealreg2mhdebugmask[Op_RegF] = *idealreg2spillmask[Op_RegF]; - *idealreg2mhdebugmask[Op_RegD] = *idealreg2spillmask[Op_RegD]; - *idealreg2mhdebugmask[Op_RegP] = *idealreg2spillmask[Op_RegP]; - *idealreg2mhdebugmask[Op_RegVectMask] = *idealreg2spillmask[Op_RegVectMask]; - - *idealreg2mhdebugmask[Op_VecA] = *idealreg2spillmask[Op_VecA]; - *idealreg2mhdebugmask[Op_VecS] = *idealreg2spillmask[Op_VecS]; - *idealreg2mhdebugmask[Op_VecD] = *idealreg2spillmask[Op_VecD]; - *idealreg2mhdebugmask[Op_VecX] = *idealreg2spillmask[Op_VecX]; - *idealreg2mhdebugmask[Op_VecY] = *idealreg2spillmask[Op_VecY]; - *idealreg2mhdebugmask[Op_VecZ] = *idealreg2spillmask[Op_VecZ]; - // Prevent stub compilations from attempting to reference // callee-saved (SOE) registers from debug info bool exclude_soe = !Compile::current()->is_method_compilation(); RegMask* caller_save_mask = exclude_soe ? &caller_save_regmask_exclude_soe : &caller_save_regmask; - RegMask* mh_caller_save_mask = exclude_soe ? &mh_caller_save_regmask_exclude_soe : &mh_caller_save_regmask; idealreg2debugmask[Op_RegN]->SUBTRACT(*caller_save_mask); idealreg2debugmask[Op_RegI]->SUBTRACT(*caller_save_mask); @@ -745,21 +673,6 @@ void Matcher::init_first_stack_mask() { idealreg2debugmask[Op_VecX]->SUBTRACT(*caller_save_mask); idealreg2debugmask[Op_VecY]->SUBTRACT(*caller_save_mask); idealreg2debugmask[Op_VecZ]->SUBTRACT(*caller_save_mask); - - idealreg2mhdebugmask[Op_RegN]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_RegI]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_RegL]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_RegF]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_RegD]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_RegP]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_RegVectMask]->SUBTRACT(*mh_caller_save_mask); - - idealreg2mhdebugmask[Op_VecA]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_VecS]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_VecD]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_VecX]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_VecY]->SUBTRACT(*mh_caller_save_mask); - idealreg2mhdebugmask[Op_VecZ]->SUBTRACT(*mh_caller_save_mask); } //---------------------------is_save_on_entry---------------------------------- @@ -984,23 +897,15 @@ void Matcher::init_spill_mask( Node *ret ) { if (_register_save_policy[i] == 'C' || _register_save_policy[i] == 'A') { caller_save_regmask.Insert(i); - mh_caller_save_regmask.Insert(i); } // Exclude save-on-entry registers from debug masks for stub compilations. if (_register_save_policy[i] == 'C' || _register_save_policy[i] == 'A' || _register_save_policy[i] == 'E') { caller_save_regmask_exclude_soe.Insert(i); - mh_caller_save_regmask_exclude_soe.Insert(i); } } - // Also exclude the register we use to save the SP for MethodHandle - // invokes to from the corresponding MH debug masks - const RegMask sp_save_mask = method_handle_invoke_SP_save_mask(); - mh_caller_save_regmask.OR(sp_save_mask); - mh_caller_save_regmask_exclude_soe.OR(sp_save_mask); - // Grab the Frame Pointer Node *fp = ret->in(TypeFunc::FramePtr); // Share frame pointer while making spill ops @@ -1272,7 +1177,6 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) { CallNode *call; const TypeTuple *domain; ciMethod* method = nullptr; - bool is_method_handle_invoke = false; // for special kill effects if( sfpt->is_Call() ) { call = sfpt->as_Call(); domain = call->tf()->domain(); @@ -1298,13 +1202,8 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) { method = call_java->method(); mcall_java->_method = method; mcall_java->_optimized_virtual = call_java->is_optimized_virtual(); - is_method_handle_invoke = call_java->is_method_handle_invoke(); - mcall_java->_method_handle_invoke = is_method_handle_invoke; mcall_java->_override_symbolic_info = call_java->override_symbolic_info(); mcall_java->_arg_escape = call_java->arg_escape(); - if (is_method_handle_invoke) { - C->set_has_method_handle_invokes(true); - } if( mcall_java->is_MachCallStaticJava() ) mcall_java->as_MachCallStaticJava()->_name = call_java->as_CallStaticJava()->_name; diff --git a/src/hotspot/share/opto/matcher.hpp b/src/hotspot/share/opto/matcher.hpp index 2ee2ded17b6..0b609b70ab5 100644 --- a/src/hotspot/share/opto/matcher.hpp +++ b/src/hotspot/share/opto/matcher.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,8 +43,6 @@ class MachOper; //---------------------------Matcher------------------------------------------- class Matcher : public PhaseTransform { - friend class VMStructs; - public: // Machine-dependent definitions @@ -179,7 +177,6 @@ class Matcher : public PhaseTransform { static const RegMask *idealreg2regmask[]; RegMask *idealreg2spillmask [_last_machine_leaf]; RegMask *idealreg2debugmask [_last_machine_leaf]; - RegMask *idealreg2mhdebugmask[_last_machine_leaf]; void init_spill_mask( Node *ret ); // Convert machine register number to register mask static uint mreg2regmask_max; @@ -187,8 +184,6 @@ class Matcher : public PhaseTransform { static RegMask STACK_ONLY_mask; static RegMask caller_save_regmask; static RegMask caller_save_regmask_exclude_soe; - static RegMask mh_caller_save_regmask; - static RegMask mh_caller_save_regmask_exclude_soe; MachNode* mach_null() const { return _mach_null; } @@ -426,8 +421,6 @@ class Matcher : public PhaseTransform { // a code which use multiply for division by constant. static bool use_asm_for_ldiv_by_con( jlong divisor ); - static const RegMask method_handle_invoke_SP_save_mask(); - // Java-Interpreter calling convention // (what you use when calling between compiled-Java and Interpreted-Java diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index f358729dfb2..2080b7cbeb5 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -4229,10 +4229,7 @@ MemBarNode* MemBarNode::make(Compile* C, int opcode, int atp, Node* pn) { } void MemBarNode::remove(PhaseIterGVN *igvn) { - if (outcnt() != 2) { - assert(Opcode() == Op_Initialize, "Only seen when there are no use of init memory"); - assert(outcnt() == 1, "Only control then"); - } + assert(outcnt() > 0 && outcnt() <= 2, "Only one or two out edges allowed"); if (trailing_store() || trailing_load_store()) { MemBarNode* leading = leading_membar(); if (leading != nullptr) { diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 90d24b609a7..84c01c68e38 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -992,7 +992,6 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { MachCallNode *mcall; int safepoint_pc_offset = current_offset; - bool is_method_handle_invoke = false; bool return_oop = false; bool has_ea_local_in_scope = sfn->_has_ea_local_in_scope; bool arg_escape = false; @@ -1004,12 +1003,7 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { } else { mcall = mach->as_MachCall(); - // Is the call a MethodHandle call? if (mcall->is_MachCallJava()) { - if (mcall->as_MachCallJava()->_method_handle_invoke) { - assert(C->has_method_handle_invokes(), "must have been set during call generation"); - is_method_handle_invoke = true; - } arg_escape = mcall->as_MachCallJava()->_arg_escape; } @@ -1192,7 +1186,6 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { jvms->bci(), jvms->should_reexecute(), rethrow_exception, - is_method_handle_invoke, return_oop, has_ea_local_in_scope, arg_escape, @@ -1370,9 +1363,6 @@ CodeBuffer* PhaseOutput::init_buffer() { exception_handler_req + deopt_handler_req; // deopt handler - if (C->has_method_handle_invokes()) - total_req += deopt_handler_req; // deopt MH handler - CodeBuffer* cb = code_buffer(); cb->set_const_section_alignment(constant_table().alignment()); cb->initialize(total_req, _buf_sizes._reloc); @@ -1806,13 +1796,6 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) { } // Emit the deopt handler code. _code_offsets.set_value(CodeOffsets::Deopt, HandlerImpl::emit_deopt_handler(masm)); - - // Emit the MethodHandle deopt handler code (if required). - if (C->has_method_handle_invokes() && !C->failing()) { - // We can use the same code as for the normal deopt handler, we - // just need a different entry point address. - _code_offsets.set_value(CodeOffsets::DeoptMH, HandlerImpl::emit_deopt_handler(masm)); - } } // One last check for failed CodeBuffer::expand: diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index 83b211828ce..19b302a8924 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -41,8 +41,6 @@ class SwitchRange; //------------------------------InlineTree------------------------------------- class InlineTree : public AnyObj { - friend class VMStructs; - Compile* C; // cache JVMState* _caller_jvms; // state of caller ciMethod* _method; // method being called by the caller_jvms diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp index 5c733c7dc0a..f24938b51c1 100644 --- a/src/hotspot/share/opto/phasetype.hpp +++ b/src/hotspot/share/opto/phasetype.hpp @@ -89,10 +89,9 @@ flags(PHASEIDEALLOOP2, "PhaseIdealLoop 2") \ flags(PHASEIDEALLOOP3, "PhaseIdealLoop 3") \ flags(AUTO_VECTORIZATION1_BEFORE_APPLY, "AutoVectorization 1, before Apply") \ - flags(AUTO_VECTORIZATION2_AFTER_REORDER, "AutoVectorization 2, after Apply Memop Reordering") \ - flags(AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, "AutoVectorization 3, after Adjusting Pre-loop Limit") \ - flags(AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS, "AutoVectorization 4, after Adding Speculative Runtime Checks") \ - flags(AUTO_VECTORIZATION5_AFTER_APPLY, "AutoVectorization 5, after Apply") \ + flags(AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, "AutoVectorization 2, after Adjusting Pre-loop Limit") \ + flags(AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS, "AutoVectorization 3, after Adding Speculative Runtime Checks") \ + flags(AUTO_VECTORIZATION5_AFTER_APPLY, "AutoVectorization 4, after Apply") \ flags(BEFORE_CCP1, "Before PhaseCCP 1") \ flags(CCP1, "PhaseCCP 1") \ flags(ITER_GVN2, "Iter GVN 2") \ diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 0d148edda6e..9de9fe5da03 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -1780,6 +1780,62 @@ static const TypeFunc* make_osr_end_Type() { return TypeFunc::make(domain, range); } +#ifndef PRODUCT +static void debug_print_convert_type(const Type** fields, int* argp, Node *parm) { + const BasicType bt = parm->bottom_type()->basic_type(); + fields[(*argp)++] = Type::get_const_basic_type(bt); + if (bt == T_LONG || bt == T_DOUBLE) { + fields[(*argp)++] = Type::HALF; + } +} + +static void update_arg_cnt(const Node* parm, int* arg_cnt) { + (*arg_cnt)++; + const BasicType bt = parm->bottom_type()->basic_type(); + if (bt == T_LONG || bt == T_DOUBLE) { + (*arg_cnt)++; + } +} + +const TypeFunc* OptoRuntime::debug_print_Type(Node* parm0, Node* parm1, + Node* parm2, Node* parm3, + Node* parm4, Node* parm5, + Node* parm6) { + int argcnt = 1; + if (parm0 != nullptr) { update_arg_cnt(parm0, &argcnt); + if (parm1 != nullptr) { update_arg_cnt(parm1, &argcnt); + if (parm2 != nullptr) { update_arg_cnt(parm2, &argcnt); + if (parm3 != nullptr) { update_arg_cnt(parm3, &argcnt); + if (parm4 != nullptr) { update_arg_cnt(parm4, &argcnt); + if (parm5 != nullptr) { update_arg_cnt(parm5, &argcnt); + if (parm6 != nullptr) { update_arg_cnt(parm6, &argcnt); + /* close each nested if ===> */ } } } } } } } + + // create input type (domain) + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // static string pointer + + if (parm0 != nullptr) { debug_print_convert_type(fields, &argp, parm0); + if (parm1 != nullptr) { debug_print_convert_type(fields, &argp, parm1); + if (parm2 != nullptr) { debug_print_convert_type(fields, &argp, parm2); + if (parm3 != nullptr) { debug_print_convert_type(fields, &argp, parm3); + if (parm4 != nullptr) { debug_print_convert_type(fields, &argp, parm4); + if (parm5 != nullptr) { debug_print_convert_type(fields, &argp, parm5); + if (parm6 != nullptr) { debug_print_convert_type(fields, &argp, parm6); + /* close each nested if ===> */ } } } } } } } + + assert(argp == TypeFunc::Parms+argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields); + + // no result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms+0] = nullptr; // void + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields); + return TypeFunc::make(domain, range); +} +#endif // PRODUCT + //------------------------------------------------------------------------------------- // register policy @@ -1913,9 +1969,6 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* c current->set_exception_pc(pc); current->set_exception_handler_pc(handler_address); - - // Check if the exception PC is a MethodHandle call site. - current->set_is_method_handle_return(nm->is_method_handle_return(pc)); } // Restore correct return pc. Was saved above. diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index 40e436c0d5c..76e69fd9d36 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -737,6 +737,16 @@ class OptoRuntime : public AllStatic { return _dtrace_object_alloc_Type; } +#ifndef PRODUCT + // Signature for runtime calls in debug printing nodes, which depends on which nodes are actually passed + // Note: we do not allow more than 7 node arguments as GraphKit::make_runtime_call only allows 8, and we need + // one for the static string + static const TypeFunc* debug_print_Type(Node* parm0 = nullptr, Node* parm1 = nullptr, + Node* parm2 = nullptr, Node* parm3 = nullptr, + Node* parm4 = nullptr, Node* parm5 = nullptr, + Node* parm6 = nullptr); +#endif // PRODUCT + private: static NamedCounter * volatile _named_counters; diff --git a/src/hotspot/share/opto/stringopts.cpp b/src/hotspot/share/opto/stringopts.cpp index 25aa82870c3..420423dd246 100644 --- a/src/hotspot/share/opto/stringopts.cpp +++ b/src/hotspot/share/opto/stringopts.cpp @@ -53,6 +53,11 @@ class StringConcat : public ResourceObj { Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten // to restart at the initial JVMState. + static constexpr uint STACKED_CONCAT_UPPER_BOUND = 256; // argument limit for a merged concat. + // The value 256 was derived by measuring + // compilation time on variable length sequences + // of stackable concatenations and chosen to keep + // a safe margin to any critical point. public: // Mode for converting arguments to Strings enum { @@ -295,6 +300,8 @@ StringConcat* StringConcat::merge(StringConcat* other, Node* arg) { } assert(result->_control.contains(other->_end), "what?"); assert(result->_control.contains(_begin), "what?"); + + uint arguments_appended = 0; for (int x = 0; x < num_arguments(); x++) { Node* argx = argument_uncast(x); if (argx == arg) { @@ -303,8 +310,21 @@ StringConcat* StringConcat::merge(StringConcat* other, Node* arg) { for (int y = 0; y < other->num_arguments(); y++) { result->append(other->argument(y), other->mode(y)); } + arguments_appended += other->num_arguments(); } else { result->append(argx, mode(x)); + arguments_appended++; + } + // Check if this concatenation would result in an excessive number of arguments + // -- leading to high memory use, compilation time, and later, a large number of IR nodes + // -- and bail out in that case. + if (arguments_appended > STACKED_CONCAT_UPPER_BOUND) { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("Merge candidate of length %d exceeds argument limit", arguments_appended); + } +#endif + return nullptr; } } result->set_allocation(other->_begin); @@ -680,7 +700,7 @@ PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn): #endif StringConcat* merged = sc->merge(other, arg); - if (merged->validate_control_flow() && merged->validate_mem_flow()) { + if (merged != nullptr && merged->validate_control_flow() && merged->validate_mem_flow()) { #ifndef PRODUCT AtomicAccess::inc(&_stropts_merged); if (PrintOptimizeStringConcat) { diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 2b3928781b8..41a4339e4c9 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -40,7 +40,7 @@ SuperWord::SuperWord(const VLoopAnalyzer &vloop_analyzer) : NOT_PRODUCT(COMMA is_trace_superword_packset()) NOT_PRODUCT(COMMA is_trace_superword_rejections()) ), - _mem_ref_for_main_loop_alignment(nullptr), + _vpointer_for_main_loop_alignment(nullptr), _aw_for_main_loop_alignment(0), _do_vector_loop(phase()->C->do_vector_loop()), // whether to do vectorization/simd style _num_work_vecs(0), // amount of vector work we have @@ -455,11 +455,16 @@ bool SuperWord::transform_loop() { // // 8) The pairs are combined into vector sized packs. // -// 9) Reorder the memory slices to co-locate members of the memory packs. +// 9) The packs are split and filtered, to ensure correctness and that +// all packs have corresponding vector nodes implemented in the backend. // -// 10) Generate ideal vector nodes for the final set of packs and where necessary, -// inserting scalar promotion, vector creation from multiple scalars, and -// extraction of scalar values from vectors. +// 10) VTransform (see vtransform.hpp) +// - construct from PackSet +// - schedule (detect circles) +// - apply +// - align main loop +// - add runtime checks (aliasing and alignment) +// - build new loop with vector C2 nodes // // Runtime Checks: // Some required properties cannot be proven statically, and require a @@ -498,7 +503,7 @@ bool SuperWord::SLP_extract() { DEBUG_ONLY(verify_packs();) DEBUG_ONLY(verify_no_extract()); - return schedule_and_apply(); + return do_vtransform(); } int SuperWord::MemOp::cmp_by_group(MemOp* a, MemOp* b) { @@ -660,39 +665,9 @@ void SuperWord::create_adjacent_memop_pairs_in_one_group(const GrowableArrayfast_outs(imax); i < imax; i++) { - PhiNode* phi = cl->fast_out(i)->isa_Phi(); - if (phi != nullptr && _vloop.in_bb(phi) && phi->is_memory_phi()) { - Node* phi_tail = phi->in(LoopNode::LoopBackControl); - if (phi_tail != phi->in(LoopNode::EntryControl)) { - _heads.push(phi); - _tails.push(phi_tail->as_Mem()); - } - } - } - - NOT_PRODUCT( if (_vloop.is_trace_memory_slices()) { print(); } ) -} - -#ifndef PRODUCT -void VLoopMemorySlices::print() const { - tty->print_cr("\nVLoopMemorySlices::print: %s", - heads().length() > 0 ? "" : "NONE"); - for (int m = 0; m < heads().length(); m++) { - tty->print("%6d ", m); heads().at(m)->dump(); - tty->print(" "); tails().at(m)->dump(); - } -} -#endif - // Get all memory nodes of a slice, in reverse order void VLoopMemorySlices::get_slice_in_reverse_order(PhiNode* head, MemNode* tail, GrowableArray &slice) const { + assert(head != nullptr && tail != nullptr, "must be slice with memory state loop"); assert(slice.is_empty(), "start empty"); Node* n = tail; Node* prev = nullptr; @@ -1576,7 +1551,7 @@ void SuperWord::filter_packs_for_alignment() { MemNode const* mem = current->as_constrained()->mem_ref(); Node_List* pack = get_pack(mem); assert(pack != nullptr, "memop of final solution must still be packed"); - _mem_ref_for_main_loop_alignment = mem; + _vpointer_for_main_loop_alignment = &vpointer(mem); _aw_for_main_loop_alignment = pack->size() * mem->memory_size(); } } @@ -1946,7 +1921,9 @@ void PackSet::verify() const { } #endif -bool SuperWord::schedule_and_apply() const { +// Build VTransform from SuperWord Packset, and eventually apply it (create new vectorized C2 loop). +// See description at top of "vtransform.hpp". +bool SuperWord::do_vtransform() const { if (_packset.is_empty()) { return false; } // Make an empty transform. @@ -1959,7 +1936,7 @@ bool SuperWord::schedule_and_apply() const { is_trace_superword_info()); #endif VTransform vtransform(_vloop_analyzer, - _mem_ref_for_main_loop_alignment, + _vpointer_for_main_loop_alignment, _aw_for_main_loop_alignment NOT_PRODUCT(COMMA trace) ); @@ -1988,6 +1965,7 @@ bool SuperWord::schedule_and_apply() const { // Apply the vectorization, i.e. we irreversibly edit the C2 graph. At this point, all // correctness and profitability checks have passed, and the graph was successfully scheduled. +// See description at top of "vtransform.hpp". void VTransform::apply() { #ifndef PRODUCT if (_trace._info || TraceLoopOpts) { @@ -2002,9 +1980,6 @@ void VTransform::apply() { Compile* C = phase()->C; C->print_method(PHASE_AUTO_VECTORIZATION1_BEFORE_APPLY, 4, cl()); - _graph.apply_memops_reordering_with_schedule(); - C->print_method(PHASE_AUTO_VECTORIZATION2_AFTER_REORDER, 4, cl()); - adjust_pre_loop_limit_to_align_main_loop_vectors(); C->print_method(PHASE_AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, 4, cl()); @@ -2016,102 +1991,11 @@ void VTransform::apply() { C->print_method(PHASE_AUTO_VECTORIZATION5_AFTER_APPLY, 4, cl()); } -// We prepare the memory graph for the replacement of scalar memops with vector memops. -// We reorder all slices in parallel, ensuring that the memops inside each slice are -// ordered according to the _schedule. This means that all packed memops are consecutive -// in the memory graph after the reordering. -void VTransformGraph::apply_memops_reordering_with_schedule() const { -#ifndef PRODUCT - assert(is_scheduled(), "must be already scheduled"); - if (_trace._info) { - print_memops_schedule(); - } -#endif - - ResourceMark rm; - int max_slices = phase()->C->num_alias_types(); - // When iterating over the schedule, we keep track of the current memory state, - // which is the Phi or a store in the loop. - GrowableArray current_state_in_slice(max_slices, max_slices, nullptr); - // The memory state after the loop is the last store inside the loop. If we reorder the - // loop we may have a different last store, and we need to adjust the uses accordingly. - GrowableArray old_last_store_in_slice(max_slices, max_slices, nullptr); - - const GrowableArray& mem_slice_head = _vloop_analyzer.memory_slices().heads(); - - // (1) Set up the initial memory state from Phi. And find the old last store. - for (int i = 0; i < mem_slice_head.length(); i++) { - Node* phi = mem_slice_head.at(i); - assert(phi->is_Phi(), "must be phi"); - int alias_idx = phase()->C->get_alias_index(phi->adr_type()); - current_state_in_slice.at_put(alias_idx, phi); - - // If we have a memory phi, we have a last store in the loop, find it over backedge. - StoreNode* last_store = phi->in(2)->as_Store(); - old_last_store_in_slice.at_put(alias_idx, last_store); - } - - // (2) Walk over schedule, append memops to the current state - // of that slice. If it is a Store, we take it as the new state. - for_each_memop_in_schedule([&] (MemNode* n) { - assert(n->is_Load() || n->is_Store(), "only loads or stores"); - int alias_idx = phase()->C->get_alias_index(n->adr_type()); - Node* current_state = current_state_in_slice.at(alias_idx); - if (current_state == nullptr) { - // If there are only loads in a slice, we never update the memory - // state in the loop, hence there is no phi for the memory state. - // We just keep the old memory state that was outside the loop. - assert(n->is_Load() && !in_bb(n->in(MemNode::Memory)), - "only loads can have memory state from outside loop"); - } else { - igvn().replace_input_of(n, MemNode::Memory, current_state); - if (n->is_Store()) { - current_state_in_slice.at_put(alias_idx, n); - } - } - }); - - // (3) For each slice, we add the current state to the backedge - // in the Phi. Further, we replace uses of the old last store - // with uses of the new last store (current_state). - GrowableArray uses_after_loop; - for (int i = 0; i < mem_slice_head.length(); i++) { - Node* phi = mem_slice_head.at(i); - int alias_idx = phase()->C->get_alias_index(phi->adr_type()); - Node* current_state = current_state_in_slice.at(alias_idx); - assert(current_state != nullptr, "slice is mapped"); - assert(current_state != phi, "did some work in between"); - assert(current_state->is_Store(), "sanity"); - igvn().replace_input_of(phi, 2, current_state); - - // Replace uses of old last store with current_state (new last store) - // Do it in two loops: first find all the uses, and change the graph - // in as second loop so that we do not break the iterator. - Node* last_store = old_last_store_in_slice.at(alias_idx); - assert(last_store != nullptr, "we have a old last store"); - uses_after_loop.clear(); - for (DUIterator_Fast kmax, k = last_store->fast_outs(kmax); k < kmax; k++) { - Node* use = last_store->fast_out(k); - if (!in_bb(use)) { - uses_after_loop.push(use); - } - } - for (int k = 0; k < uses_after_loop.length(); k++) { - Node* use = uses_after_loop.at(k); - for (uint j = 0; j < use->req(); j++) { - Node* def = use->in(j); - if (def == last_store) { - igvn().replace_input_of(use, j, current_state); - } - } - } - } -} - void VTransformGraph::apply_vectorization_for_each_vtnode(uint& max_vector_length, uint& max_vector_width) const { ResourceMark rm; VTransformApplyState apply_state(_vloop_analyzer, _vtnodes.length()); + // Apply: transform the node and connect with inputs (no backedges). for (int i = 0; i < _schedule.length(); i++) { VTransformNode* vtn = _schedule.at(i); VTransformApplyResult result = vtn->apply(apply_state); @@ -2121,6 +2005,16 @@ void VTransformGraph::apply_vectorization_for_each_vtnode(uint& max_vector_lengt max_vector_length = MAX2(max_vector_length, result.vector_length()); max_vector_width = MAX2(max_vector_width, result.vector_width()); } + + // Cleanup: connect backedges + for (int i = 0; i < _schedule.length(); i++) { + VTransformNode* vtn = _schedule.at(i); + vtn->apply_backedge(apply_state); + } + + // Memory uses after the loop: used to connect to old last store, + // now need to connect to new last store. + apply_state.fix_memory_state_uses_after_loop(); } // We call "apply" on every VTransformNode, which replaces the packed scalar nodes with vector nodes. @@ -2774,10 +2668,10 @@ bool VLoopMemorySlices::same_memory_slice(MemNode* m1, MemNode* m2) const { _vloop.phase()->C->get_alias_index(m2->adr_type()); } -LoadNode::ControlDependency VTransformLoadVectorNode::control_dependency() const { +LoadNode::ControlDependency SuperWordVTransformBuilder::load_control_dependency(const Node_List* pack) const { LoadNode::ControlDependency dep = LoadNode::DependsOnlyOnTest; - for (int i = 0; i < nodes().length(); i++) { - Node* n = nodes().at(i); + for (uint i = 0; i < pack->size(); i++) { + Node* n = pack->at(i); assert(n->is_Load(), "only meaningful for loads"); if (!n->depends_only_on_test()) { if (n->as_Load()->has_unknown_control_dependency() && @@ -2795,22 +2689,24 @@ LoadNode::ControlDependency VTransformLoadVectorNode::control_dependency() const // Find the memop pack with the maximum vector width, unless they were already // determined (e.g. by SuperWord::filter_packs_for_alignment()). -void VTransform::determine_mem_ref_and_aw_for_main_loop_alignment() { - if (_mem_ref_for_main_loop_alignment != nullptr) { - assert(VLoop::vectors_should_be_aligned(), "mem_ref only set if filtered for alignment"); +void VTransform::determine_vpointer_and_aw_for_main_loop_alignment() { + if (_vpointer_for_main_loop_alignment != nullptr) { + assert(VLoop::vectors_should_be_aligned(), "vpointer_for_main_loop_alignment only set if filtered for alignment"); return; } - MemNode const* mem_ref = nullptr; + VPointer const* vpointer = nullptr; int max_aw = 0; + bool vpointer_is_load = false; const GrowableArray& vtnodes = _graph.vtnodes(); for (int i = 0; i < vtnodes.length(); i++) { VTransformMemVectorNode* vtn = vtnodes.at(i)->isa_MemVector(); if (vtn == nullptr) { continue; } - MemNode* p0 = vtn->nodes().at(0)->as_Mem(); - int vw = p0->memory_size() * vtn->nodes().length(); + int vw = vtn->vpointer().size(); + bool vtn_is_load = vtn->is_load_in_loop(); + // Generally, we prefer to align with the largest memory op (load or store). // If there are multiple, then SuperWordAutomaticAlignment determines if we // prefer loads or stores. @@ -2820,15 +2716,16 @@ void VTransform::determine_mem_ref_and_aw_for_main_loop_alignment() { // it is worse if a store is split, and less bad if a load is split. // By default, we have SuperWordAutomaticAlignment=1, i.e. we align with a // store if possible, to avoid splitting that store. - bool prefer_store = mem_ref != nullptr && SuperWordAutomaticAlignment == 1 && mem_ref->is_Load() && p0->is_Store(); - bool prefer_load = mem_ref != nullptr && SuperWordAutomaticAlignment == 2 && mem_ref->is_Store() && p0->is_Load(); + bool prefer_store = SuperWordAutomaticAlignment == 1 && vpointer_is_load && !vtn_is_load; + bool prefer_load = SuperWordAutomaticAlignment == 2 && !vpointer_is_load && vtn_is_load; if (vw > max_aw || (vw == max_aw && (prefer_load || prefer_store))) { + vpointer = &vtn->vpointer(); max_aw = vw; - mem_ref = p0; + vpointer_is_load = vtn_is_load; } } - assert(mem_ref != nullptr && max_aw > 0, "found mem_ref and aw"); - _mem_ref_for_main_loop_alignment = mem_ref; + assert(vpointer != nullptr && max_aw > 0, "found vpointer and aw"); + _vpointer_for_main_loop_alignment = vpointer; _aw_for_main_loop_alignment = max_aw; } @@ -2842,13 +2739,17 @@ void VTransform::determine_mem_ref_and_aw_for_main_loop_alignment() { } \ // Ensure that the main loop vectors are aligned by adjusting the pre loop limit. We memory-align -// the address of "_mem_ref_for_main_loop_alignment" to "_aw_for_main_loop_alignment", which is a +// the address of "_vpointer_for_main_loop_alignment" to "_aw_for_main_loop_alignment", which is a // sufficiently large alignment width. We adjust the pre-loop iteration count by adjusting the // pre-loop limit. void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { - determine_mem_ref_and_aw_for_main_loop_alignment(); - const MemNode* align_to_ref = _mem_ref_for_main_loop_alignment; - const int aw = _aw_for_main_loop_alignment; + determine_vpointer_and_aw_for_main_loop_alignment(); + + assert(cl()->is_main_loop(), "can only do alignment for main loop"); + assert(_vpointer_for_main_loop_alignment != nullptr && + _vpointer_for_main_loop_alignment->is_valid() && + _aw_for_main_loop_alignment > 0, + "must have alignment reference and aw"); if (!VLoop::vectors_should_be_aligned() && SuperWordAutomaticAlignment == 0) { #ifdef ASSERT @@ -2859,8 +2760,8 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { return; } - assert(align_to_ref != nullptr && aw > 0, "must have alignment reference and aw"); - assert(cl()->is_main_loop(), "can only do alignment for main loop"); + const VPointer& p = *_vpointer_for_main_loop_alignment; + const int aw = _aw_for_main_loop_alignment; // The opaque node for the limit, where we adjust the input Opaque1Node* pre_opaq = _vloop.pre_loop_end()->limit()->as_Opaque1(); @@ -2875,10 +2776,7 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { Node* orig_limit = pre_opaq->original_loop_limit(); assert(orig_limit != nullptr && igvn().type(orig_limit) != Type::TOP, ""); - const VPointer& p = vpointer(align_to_ref); - assert(p.is_valid(), "sanity"); - - // For the main-loop, we want the address of align_to_ref to be memory aligned + // For the main-loop, we want the address of vpointer p to be memory aligned // with some alignment width (aw, a power of 2). When we enter the main-loop, // we know that iv is equal to the pre-loop limit. If we adjust the pre-loop // limit by executing adjust_pre_iter many extra iterations, we can change the @@ -3013,9 +2911,7 @@ void VTransform::adjust_pre_loop_limit_to_align_main_loop_vectors() { #ifdef ASSERT if (_trace._align_vector) { tty->print_cr("\nVTransform::adjust_pre_loop_limit_to_align_main_loop_vectors:"); - tty->print(" align_to_ref:"); - align_to_ref->dump(); - tty->print(" "); + tty->print(" vpointer_for_main_loop_alignment"); p.print_on(tty); tty->print_cr(" aw: %d", aw); tty->print_cr(" iv_stride: %d", iv_stride); diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index 0940e752f85..118e0aa042c 100644 --- a/src/hotspot/share/opto/superword.hpp +++ b/src/hotspot/share/opto/superword.hpp @@ -410,9 +410,9 @@ class SuperWord : public ResourceObj { PairSet _pairset; PackSet _packset; - // Memory reference, and the alignment width (aw) for which we align the main-loop, + // VPointer, and the alignment width (aw) for which we align the main-loop, // by adjusting the pre-loop limit. - MemNode const* _mem_ref_for_main_loop_alignment; + VPointer const* _vpointer_for_main_loop_alignment; int _aw_for_main_loop_alignment; public: @@ -657,7 +657,7 @@ class SuperWord : public ResourceObj { bool is_velt_basic_type_compatible_use_def(Node* use, Node* def) const; - bool schedule_and_apply() const; + bool do_vtransform() const; }; #endif // SHARE_OPTO_SUPERWORD_HPP diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.cpp b/src/hotspot/share/opto/superwordVTransformBuilder.cpp index dbc96c234a9..45c919ccffa 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.cpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.cpp @@ -37,6 +37,10 @@ void SuperWordVTransformBuilder::build() { VectorSet vtn_memory_dependencies; // Shared, but cleared for every vtnode. build_inputs_for_vector_vtnodes(vtn_memory_dependencies); build_inputs_for_scalar_vtnodes(vtn_memory_dependencies); + + // Build vtnodes for all uses of nodes from the loop, and connect them + // as outputs to the nodes in the loop. + build_uses_after_loop(); } void SuperWordVTransformBuilder::build_vector_vtnodes_for_packed_nodes() { @@ -50,8 +54,8 @@ void SuperWordVTransformBuilder::build_vector_vtnodes_for_packed_nodes() { } void SuperWordVTransformBuilder::build_scalar_vtnodes_for_non_packed_nodes() { - for (int i = 0; i < _vloop_analyzer.body().body().length(); i++) { - Node* n = _vloop_analyzer.body().body().at(i); + for (uint i = 0; i < _vloop.lpt()->_body.size(); i++) { + Node* n = _vloop.lpt()->_body.at(i); if (_packset.get_pack(n) != nullptr) { continue; } VTransformNode* vtn = nullptr; @@ -61,6 +65,8 @@ void SuperWordVTransformBuilder::build_scalar_vtnodes_for_non_packed_nodes() { vtn = new (_vtransform.arena()) VTransformMemopScalarNode(_vtransform, mem, mem_p); } else if (n->is_Phi()) { vtn = new (_vtransform.arena()) VTransformLoopPhiNode(_vtransform, n->as_Phi()); + } else if (n->is_CountedLoop()) { + vtn = new (_vtransform.arena()) VTransformCountedLoopNode(_vtransform, n->as_CountedLoop()); } else if (n->is_CFG()) { vtn = new (_vtransform.arena()) VTransformCFGNode(_vtransform, n); } else { @@ -121,8 +127,8 @@ void SuperWordVTransformBuilder::build_inputs_for_vector_vtnodes(VectorSet& vtn_ } void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_memory_dependencies) { - for (int i = 0; i < _vloop_analyzer.body().body().length(); i++) { - Node* n = _vloop_analyzer.body().body().at(i); + for (uint i = 0; i < _vloop.lpt()->_body.size(); i++) { + Node* n = _vloop.lpt()->_body.at(i); VTransformNode* vtn = get_vtnode(n); if (vtn->isa_Vector() != nullptr) { continue; } vtn_memory_dependencies.clear(); // Add every dependency only once per vtn. @@ -135,18 +141,41 @@ void SuperWordVTransformBuilder::build_inputs_for_scalar_vtnodes(VectorSet& vtn_ init_req_with_scalar(n, vtn, MemNode::ValueIn); add_memory_dependencies_of_node_to_vtnode(n, vtn, vtn_memory_dependencies); } else if (n->is_CountedLoop()) { - continue; // Is "root", has no dependency. - } else if (n->is_Phi()) { - // CountedLoop Phi's: ignore backedge (and entry value). - assert(n->in(0) == _vloop.cl(), "only Phi's from the CountedLoop allowed"); - init_req_with_scalar(n, vtn, 0); - continue; + // Avoid self-loop, it only creates unnecessary issues in scheduling. + init_req_with_scalar(n, vtn, LoopNode::EntryControl); + init_req_with_scalar(n, vtn, LoopNode::LoopBackControl); } else { init_all_req_with_scalars(n, vtn); } } } +// Build vtnodes for all uses of nodes from the loop, and connect them +// as outputs to the nodes in the loop. +void SuperWordVTransformBuilder::build_uses_after_loop() { + for (uint i = 0; i < _vloop.lpt()->_body.size(); i++) { + Node* n = _vloop.lpt()->_body.at(i); + VTransformNode* vtn = get_vtnode(n); + + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node* use = n->fast_out(i); + + if (!_vloop.in_bb(use)) { + VTransformNode* vtn_use = get_vtnode_or_wrap_as_outer(use); + + // Set all edges + for (uint j = 0; j < use->req(); j++) { + Node* def = use->in(j); + if (n == def && vtn_use->in_req(j) != vtn) { + assert(vtn_use->in_req(j) == nullptr, "should not yet be set"); + vtn_use->init_req(j, vtn); + } + } + } + } + } +} + // Create a vtnode for each pack. No in/out edges set yet. VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(const Node_List* pack) const { Node* p0 = pack->at(0); @@ -159,7 +188,8 @@ VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(co if (p0->is_Load()) { const VPointer& scalar_p = _vloop_analyzer.vpointers().vpointer(p0->as_Load()); const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * vlen)); - vtn = new (_vtransform.arena()) VTransformLoadVectorNode(_vtransform, properties, vector_p, p0->adr_type()); + const LoadNode::ControlDependency control_dependency = load_control_dependency(pack); + vtn = new (_vtransform.arena()) VTransformLoadVectorNode(_vtransform, properties, vector_p, p0->adr_type(), control_dependency); } else if (p0->is_Store()) { const VPointer& scalar_p = _vloop_analyzer.vpointers().vpointer(p0->as_Store()); const VPointer vector_p(scalar_p.make_with_size(scalar_p.size() * vlen)); @@ -209,7 +239,6 @@ VTransformVectorNode* SuperWordVTransformBuilder::make_vector_vtnode_for_pack(co int vopc = VectorNode::opcode(sopc, bt); vtn = new (_vtransform.arena()) VTransformElementWiseVectorNode(_vtransform, p0->req(), properties, vopc); } - vtn->set_nodes(pack); return vtn; } @@ -276,15 +305,15 @@ VTransformNode* SuperWordVTransformBuilder::get_or_make_vtnode_vector_input_at_i // case of a ConvL2I, it can be int or some narrower type such // as short etc. But given we replicate the input of the Convert // node, we have to use the input type instead. - BasicType element_type = p0->is_Convert() ? p0->in(1)->bottom_type()->basic_type() : _vloop_analyzer.types().velt_basic_type(p0); - if (index == 2 && VectorNode::is_scalar_rotate(p0) && element_type == T_LONG) { + BasicType element_bt = p0->is_Convert() ? p0->in(1)->bottom_type()->basic_type() : _vloop_analyzer.types().velt_basic_type(p0); + if (index == 2 && VectorNode::is_scalar_rotate(p0) && element_bt == T_LONG) { // Scalar rotate has int rotation value, but the scalar rotate expects longs. assert(same_input->bottom_type()->isa_int(), "scalar rotate expects int rotation"); VTransformNode* conv = new (_vtransform.arena()) VTransformConvI2LNode(_vtransform); conv->init_req(1, same_input_vtn); same_input_vtn = conv; } - VTransformNode* replicate = new (_vtransform.arena()) VTransformReplicateNode(_vtransform, pack->size(), element_type); + VTransformNode* replicate = new (_vtransform.arena()) VTransformReplicateNode(_vtransform, pack->size(), element_bt); replicate->init_req(1, same_input_vtn); return replicate; } @@ -307,6 +336,7 @@ VTransformNode* SuperWordVTransformBuilder::get_vtnode_or_wrap_as_outer(Node* n) assert(!_vloop.in_bb(n), "only nodes outside the loop can be input nodes to the loop"); vtn = new (_vtransform.arena()) VTransformOuterNode(_vtransform, n); map_node_to_vtnode(n, vtn); + assert(vtn == get_vtnode_or_null(n), "consistency"); return vtn; } diff --git a/src/hotspot/share/opto/superwordVTransformBuilder.hpp b/src/hotspot/share/opto/superwordVTransformBuilder.hpp index 6ed8480209a..cc9dd225f01 100644 --- a/src/hotspot/share/opto/superwordVTransformBuilder.hpp +++ b/src/hotspot/share/opto/superwordVTransformBuilder.hpp @@ -56,6 +56,7 @@ class SuperWordVTransformBuilder : public StackObj { void build_scalar_vtnodes_for_non_packed_nodes(); void build_inputs_for_vector_vtnodes(VectorSet& vtn_memory_dependencies); void build_inputs_for_scalar_vtnodes(VectorSet& vtn_memory_dependencies); + void build_uses_after_loop(); // Helper methods for building VTransform. VTransformNode* get_vtnode_or_null(Node* n) const { @@ -82,6 +83,7 @@ class SuperWordVTransformBuilder : public StackObj { void init_all_req_with_scalars(Node* n, VTransformNode* vtn); void init_all_req_with_vectors(const Node_List* pack, VTransformNode* vtn); void add_memory_dependencies_of_node_to_vtnode(Node* n, VTransformNode* vtn, VectorSet& vtn_memory_dependencies); + LoadNode::ControlDependency load_control_dependency(const Node_List* pack) const; }; #endif // SHARE_OPTO_SUPERWORD_VTRANSFORM_BUILDER_HPP diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 8e0f0980ff7..5c4e15fdbb9 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -182,6 +182,11 @@ VStatus VLoopAnalyzer::setup_submodules_helper() { _reductions.mark_reductions(); } + VStatus body_status = _body.construct(); + if (!body_status.is_success()) { + return body_status; + } + _memory_slices.find_memory_slices(); // If there is no memory slice detected, it means there is no store. @@ -192,11 +197,6 @@ VStatus VLoopAnalyzer::setup_submodules_helper() { return VStatus::make_failure(VLoopAnalyzer::FAILURE_NO_REDUCTION_OR_STORE); } - VStatus body_status = _body.construct(); - if (!body_status.is_success()) { - return body_status; - } - _types.compute_vector_element_type(); _vpointers.compute_vpointers(); @@ -206,6 +206,64 @@ VStatus VLoopAnalyzer::setup_submodules_helper() { return VStatus::make_success(); } +// There are 2 kinds of slices: +// - No memory phi: only loads. All have the same input memory state from before the loop. +// - With memory phi. Chain of memory operations inside the loop. +void VLoopMemorySlices::find_memory_slices() { + Compile* C = _vloop.phase()->C; + // We iterate over the body, which is topologically sorted. Hence, if there is a phi + // in a slice, we will find it first, and the loads and stores afterwards. + for (int i = 0; i < _body.body().length(); i++) { + Node* n = _body.body().at(i); + if (n->is_memory_phi()) { + // Memory slice with stores (and maybe loads) + PhiNode* phi = n->as_Phi(); + int alias_idx = C->get_alias_index(phi->adr_type()); + assert(_inputs.at(alias_idx) == nullptr, "did not yet touch this slice"); + _inputs.at_put(alias_idx, phi->in(1)); + _heads.at_put(alias_idx, phi); + } else if (n->is_Load()) { + LoadNode* load = n->as_Load(); + int alias_idx = C->get_alias_index(load->adr_type()); + PhiNode* head = _heads.at(alias_idx); + if (head == nullptr) { + // We did not find a phi on this slice yet -> must be a slice with only loads. + assert(_inputs.at(alias_idx) == nullptr || _inputs.at(alias_idx) == load->in(1), + "not yet touched or the same input"); + _inputs.at_put(alias_idx, load->in(1)); + } // else: the load belongs to a slice with a phi that already set heads and inputs. +#ifdef ASSERT + } else if (n->is_Store()) { + // Found a store. Make sure it is in a slice with a Phi. + StoreNode* store = n->as_Store(); + int alias_idx = C->get_alias_index(store->adr_type()); + PhiNode* head = _heads.at(alias_idx); + assert(head != nullptr, "should have found a mem phi for this slice"); +#endif + } + } + NOT_PRODUCT( if (_vloop.is_trace_memory_slices()) { print(); } ) +} + +#ifndef PRODUCT +void VLoopMemorySlices::print() const { + tty->print_cr("\nVLoopMemorySlices::print: %s", + heads().length() > 0 ? "" : "NONE"); + for (int i = 0; i < _inputs.length(); i++) { + Node* input = _inputs.at(i); + PhiNode* head = _heads.at(i); + if (input != nullptr) { + tty->print("%3d input", i); input->dump(); + if (head == nullptr) { + tty->print_cr(" load only"); + } else { + tty->print(" head "); head->dump(); + } + } + } +} +#endif + void VLoopVPointers::compute_vpointers() { count_vpointers(); allocate_vpointers_array(); @@ -267,7 +325,6 @@ void VLoopVPointers::print() const { // the edge, i.e. spaw the order. void VLoopDependencyGraph::construct() { const GrowableArray& mem_slice_heads = _memory_slices.heads(); - const GrowableArray& mem_slice_tails = _memory_slices.tails(); ResourceMark rm; GrowableArray slice_nodes; @@ -277,7 +334,10 @@ void VLoopDependencyGraph::construct() { // For each memory slice, create the memory subgraph for (int i = 0; i < mem_slice_heads.length(); i++) { PhiNode* head = mem_slice_heads.at(i); - MemNode* tail = mem_slice_tails.at(i); + // If there is no head (memory-phi) for this slice, then we have either no memops + // in the loop, or only loads. We do not need to add any memory edges in that case. + if (head == nullptr) { continue; } + MemNode* tail = head->in(2)->as_Mem(); _memory_slices.get_slice_in_reverse_order(head, tail, slice_nodes); diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index b39e46cbf35..e006589cce9 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -379,37 +379,6 @@ class VLoopReductions : public StackObj { static Node* original_input(const Node* n, uint i); }; -// Submodule of VLoopAnalyzer. -// Find the memory slices in the loop. -class VLoopMemorySlices : public StackObj { -private: - const VLoop& _vloop; - - GrowableArray _heads; - GrowableArray _tails; - -public: - VLoopMemorySlices(Arena* arena, const VLoop& vloop) : - _vloop(vloop), - _heads(arena, 8, 0, nullptr), - _tails(arena, 8, 0, nullptr) {}; - NONCOPYABLE(VLoopMemorySlices); - - void find_memory_slices(); - - const GrowableArray& heads() const { return _heads; } - const GrowableArray& tails() const { return _tails; } - - // Get all memory nodes of a slice, in reverse order - void get_slice_in_reverse_order(PhiNode* head, MemNode* tail, GrowableArray& slice) const; - - bool same_memory_slice(MemNode* m1, MemNode* m2) const; - -#ifndef PRODUCT - void print() const; -#endif -}; - // Submodule of VLoopAnalyzer. // Finds all nodes in the body, and creates a mapping node->_idx to a body_idx. // This mapping is used so that subsequent datastructures sizes only grow with @@ -461,6 +430,73 @@ class VLoopBody : public StackObj { } }; +// Submodule of VLoopAnalyzer. +// Find the memory slices in the loop. There are 3 kinds of slices: +// 1. no use in loop: inputs(i) = nullptr, heads(i) = nullptr +// 2. stores in loop: inputs(i) = entry_mem, heads(i) = phi_mem +// +// = entry_mem +// | +// CountedLoop | +-----------------------+ +// | v v | +// phi_mem | +// | | +// | +// | | +// +---------------------------+ +// | +// +// +// Note: the mem uses after the loop are dependent on the last store in the loop. +// Once we vectorize, we may reorder the loads and stores, and replace +// scalar mem ops with vector mem ops. We will have to make sure that all +// uses after the loop use the new last store. +// See: VTransformApplyState::fix_memory_state_uses_after_loop +// +// 3. only loads but no stores in loop: inputs(i) = entry_mem, heads(i) = nullptr +// +// = entry_mem +// | | +// | CountedLoop | +// | | | +// | +// | +// +// +// Note: the mem uses after the loop are NOT dependent any mem ops in the loop, +// since there are no stores. +// +class VLoopMemorySlices : public StackObj { +private: + const VLoop& _vloop; + const VLoopBody& _body; + + GrowableArray _inputs; + GrowableArray _heads; + +public: + VLoopMemorySlices(Arena* arena, const VLoop& vloop, const VLoopBody& body) : + _vloop(vloop), + _body(body), + _inputs(arena, num_slices(), num_slices(), nullptr), + _heads(arena, num_slices(), num_slices(), nullptr) {}; + NONCOPYABLE(VLoopMemorySlices); + + const GrowableArray& inputs() const { return _inputs; } + const GrowableArray& heads() const { return _heads; } + + void find_memory_slices(); + void get_slice_in_reverse_order(PhiNode* head, MemNode* tail, GrowableArray& slice) const; + bool same_memory_slice(MemNode* m1, MemNode* m2) const; + +private: +#ifndef PRODUCT + void print() const; +#endif + + int num_slices() const { return _vloop.phase()->C->num_alias_types(); } +}; + // Submodule of VLoopAnalyzer. // Compute the vector element type for every node in the loop body. // We need to do this to be able to vectorize the narrower integer @@ -737,8 +773,8 @@ class VLoopAnalyzer : StackObj { // Submodules VLoopReductions _reductions; - VLoopMemorySlices _memory_slices; VLoopBody _body; + VLoopMemorySlices _memory_slices; VLoopTypes _types; VLoopVPointers _vpointers; VLoopDependencyGraph _dependency_graph; @@ -749,8 +785,8 @@ class VLoopAnalyzer : StackObj { _arena(mtCompiler, Arena::Tag::tag_superword), _success(false), _reductions (&_arena, vloop), - _memory_slices (&_arena, vloop), _body (&_arena, vloop, vshared), + _memory_slices (&_arena, vloop, _body), _types (&_arena, vloop, _body), _vpointers (&_arena, vloop, _body), _dependency_graph(&_arena, vloop, _body, _memory_slices, _vpointers) diff --git a/src/hotspot/share/opto/vtransform.cpp b/src/hotspot/share/opto/vtransform.cpp index 8c1210a5a09..27c541c2732 100644 --- a/src/hotspot/share/opto/vtransform.cpp +++ b/src/hotspot/share/opto/vtransform.cpp @@ -78,6 +78,10 @@ bool VTransformGraph::schedule() { // runtime check, see VTransform::apply_speculative_aliasing_runtime_checks. for (uint i = 0; i < vtn->out_strong_edges(); i++) { VTransformNode* use = vtn->out_strong_edge(i); + + // Skip LoopPhi backedge. + if ((use->isa_LoopPhi() != nullptr || use->isa_CountedLoop() != nullptr) && use->in_req(2) == vtn) { continue; } + if (post_visited.test(use->_idx)) { continue; } if (pre_visited.test(use->_idx)) { // Cycle detected! @@ -120,6 +124,11 @@ void VTransformGraph::collect_nodes_without_strong_in_edges(GrowableArrayhas_strong_in_edge()) { stack.push(vtn); } + // If an Outer node has both inputs and outputs, we will most likely have cycles in the final graph. + // This is not a correctness problem, but it just will prevent vectorization. If this ever happens + // try to find a way to avoid the cycle somehow. + assert(vtn->isa_Outer() == nullptr || (vtn->has_strong_in_edge() != (vtn->out_strong_edges() > 0)), + "Outer nodes should either be inputs or outputs, but not both, otherwise we may get cycles"); } } @@ -717,28 +726,111 @@ Node* VTransformApplyState::transformed_node(const VTransformNode* vtn) const { return n; } +void VTransformApplyState::init_memory_states_and_uses_after_loop() { + const GrowableArray& inputs = _vloop_analyzer.memory_slices().inputs(); + const GrowableArray& heads = _vloop_analyzer.memory_slices().heads(); + for (int i = 0; i < inputs.length(); i++) { + PhiNode* head = heads.at(i); + if (head != nullptr) { + // Slice with Phi (i.e. with stores) -> start with the phi (phi_mem) + _memory_states.at_put(i, head); + + // Remember uses outside the loop of the last memory state (store). + StoreNode* last_store = head->in(2)->as_Store(); + assert(vloop().in_bb(last_store), "backedge store should be in the loop"); + for (DUIterator_Fast jmax, j = last_store->fast_outs(jmax); j < jmax; j++) { + Node* use = last_store->fast_out(j); + if (!vloop().in_bb(use)) { + for (uint k = 0; k < use->req(); k++) { + if (use->in(k) == last_store) { + _memory_state_uses_after_loop.push(MemoryStateUseAfterLoop(use, k, i)); + } + } + } + } + } else { + // Slice without Phi (i.e. only loads) -> use the input state (entry_mem) + _memory_states.at_put(i, inputs.at(i)); + } + } +} + +// We may have reordered the scalar stores, or replaced them with vectors. Now +// the last memory state in the loop may have changed. Thus, we need to change +// the uses of the old last memory state the new last memory state. +void VTransformApplyState::fix_memory_state_uses_after_loop() { + for (int i = 0; i < _memory_state_uses_after_loop.length(); i++) { + MemoryStateUseAfterLoop& use = _memory_state_uses_after_loop.at(i); + Node* last_state = memory_state(use._alias_idx); + phase()->igvn().replace_input_of(use._use, use._in_idx, last_state); + } +} + +void VTransformNode::apply_vtn_inputs_to_node(Node* n, VTransformApplyState& apply_state) const { + PhaseIdealLoop* phase = apply_state.phase(); + for (uint i = 0; i < req(); i++) { + VTransformNode* vtn_def = in_req(i); + if (vtn_def != nullptr) { + Node* def = apply_state.transformed_node(vtn_def); + phase->igvn().replace_input_of(n, i, def); + } + } +} + VTransformApplyResult VTransformMemopScalarNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwrap without touching the inputs. + apply_vtn_inputs_to_node(_node, apply_state); + // The memory state has to be applied separately: the vtn does not hold it. This allows reordering. + Node* mem = apply_state.memory_state(_node->adr_type()); + apply_state.phase()->igvn().replace_input_of(_node, 1, mem); + if (_node->is_Store()) { + apply_state.set_memory_state(_node->adr_type(), _node); + } + return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformDataScalarNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwrap without touching the inputs. + apply_vtn_inputs_to_node(_node, apply_state); return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformLoopPhiNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwrap without touching the inputs. + PhaseIdealLoop* phase = apply_state.phase(); + Node* in0 = apply_state.transformed_node(in_req(0)); + Node* in1 = apply_state.transformed_node(in_req(1)); + phase->igvn().replace_input_of(_node, 0, in0); + phase->igvn().replace_input_of(_node, 1, in1); + // Note: the backedge is hooked up later. return VTransformApplyResult::make_scalar(_node); } +// Cleanup backedges. In the schedule, the backedges come after their phis. Hence, +// we only have the transformed backedges after the phis are already transformed. +// We hook the backedges into the phis now, during cleanup. +void VTransformLoopPhiNode::apply_backedge(VTransformApplyState& apply_state) const { + PhaseIdealLoop* phase = apply_state.phase(); + if (_node->is_memory_phi()) { + // Memory phi/backedge + // The last memory state of that slice is the backedge. + Node* last_state = apply_state.memory_state(_node->adr_type()); + phase->igvn().replace_input_of(_node, 2, last_state); + } else { + // Data phi/backedge + Node* in2 = apply_state.transformed_node(in_req(2)); + phase->igvn().replace_input_of(_node, 2, in2); + } +} + VTransformApplyResult VTransformCFGNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwrap without touching the inputs. + // We do not modify the inputs of the CountedLoop (and certainly not its backedge) + if (!_node->is_CountedLoop()) { + apply_vtn_inputs_to_node(_node, apply_state); + } return VTransformApplyResult::make_scalar(_node); } VTransformApplyResult VTransformOuterNode::apply(VTransformApplyState& apply_state) const { - // This was just wrapped. Now we simply unwrap without touching the inputs. + apply_vtn_inputs_to_node(_node, apply_state); return VTransformApplyResult::make_scalar(_node); } @@ -797,7 +889,7 @@ VTransformApplyResult VTransformElementWiseVectorNode::apply(VTransformApplyStat vn = VectorNode::make(_vector_opcode, in1, in2, in3, vt); // ternary } - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + register_new_node_from_vectorization(apply_state, vn); return VTransformApplyResult::make_vector(vn); } @@ -812,7 +904,7 @@ VTransformApplyResult VTransformElementWiseLongOpWithCastToIntVectorNode::apply( register_new_node_from_vectorization(apply_state, long_vn); // Cast long -> int, to mimic the scalar long -> int operation. VectorNode* vn = VectorCastNode::make(Op_VectorCastL2X, long_vn, T_INT, vlen); - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + register_new_node_from_vectorization(apply_state, vn); return VTransformApplyResult::make_vector(vn); } @@ -824,7 +916,7 @@ VTransformApplyResult VTransformReinterpretVectorNode::apply(VTransformApplyStat Node* in1 = apply_state.transformed_node(in_req(1)); VectorNode* vn = new VectorReinterpretNode(in1, src_vt, dst_vt); - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + register_new_node_from_vectorization(apply_state, vn); return VTransformApplyResult::make_vector(vn); } @@ -843,7 +935,7 @@ VTransformApplyResult VTransformBoolVectorNode::apply(VTransformApplyState& appl PhaseIdealLoop* phase = apply_state.phase(); ConINode* mask_node = phase->intcon((int)mask); VectorNode* vn = new VectorMaskCmpNode(mask, cmp_in1, cmp_in2, mask_node, vt); - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + register_new_node_from_vectorization(apply_state, vn); return VTransformApplyResult::make_vector(vn); } @@ -852,7 +944,7 @@ VTransformApplyResult VTransformReductionVectorNode::apply(VTransformApplyState& Node* vec = apply_state.transformed_node(in_req(2)); ReductionNode* vn = ReductionNode::make(scalar_opcode(), nullptr, init, vec, element_basic_type()); - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + register_new_node_from_vectorization(apply_state, vn); return VTransformApplyResult::make_vector(vn, vn->vect_type()); } @@ -861,10 +953,9 @@ VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& appl uint vlen = vector_length(); BasicType bt = element_basic_type(); - LoadNode* first = nodes().at(0)->as_Load(); + // The memory state has to be applied separately: the vtn does not hold it. This allows reordering. Node* ctrl = apply_state.transformed_node(in_req(MemNode::Control)); - // first has the correct memory state, determined by VTransformGraph::apply_memops_reordering_with_schedule - Node* mem = first->in(MemNode::Memory); + Node* mem = apply_state.memory_state(_adr_type); Node* adr = apply_state.transformed_node(in_req(MemNode::Address)); // Set the memory dependency of the LoadVector as early as possible. @@ -880,10 +971,9 @@ VTransformApplyResult VTransformLoadVectorNode::apply(VTransformApplyState& appl } } - LoadVectorNode* vn = LoadVectorNode::make(sopc, ctrl, mem, adr, _adr_type, vlen, bt, - control_dependency()); + LoadVectorNode* vn = LoadVectorNode::make(sopc, ctrl, mem, adr, _adr_type, vlen, bt, _control_dependency); DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); + register_new_node_from_vectorization(apply_state, vn); return VTransformApplyResult::make_vector(vn, vn->vect_type()); } @@ -891,27 +981,17 @@ VTransformApplyResult VTransformStoreVectorNode::apply(VTransformApplyState& app int sopc = scalar_opcode(); uint vlen = vector_length(); - StoreNode* first = nodes().at(0)->as_Store(); + // The memory state has to be applied separately: the vtn does not hold it. This allows reordering. Node* ctrl = apply_state.transformed_node(in_req(MemNode::Control)); - // first has the correct memory state, determined by VTransformGraph::apply_memops_reordering_with_schedule - Node* mem = first->in(MemNode::Memory); + Node* mem = apply_state.memory_state(_adr_type); Node* adr = apply_state.transformed_node(in_req(MemNode::Address)); Node* value = apply_state.transformed_node(in_req(MemNode::ValueIn)); StoreVectorNode* vn = StoreVectorNode::make(sopc, ctrl, mem, adr, _adr_type, value, vlen); DEBUG_ONLY( if (VerifyAlignVector) { vn->set_must_verify_alignment(); } ) - register_new_node_from_vectorization_and_replace_scalar_nodes(apply_state, vn); - return VTransformApplyResult::make_vector(vn, vn->vect_type()); -} - -void VTransformVectorNode::register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const { - PhaseIdealLoop* phase = apply_state.phase(); register_new_node_from_vectorization(apply_state, vn); - - for (int i = 0; i < _nodes.length(); i++) { - Node* n = _nodes.at(i); - phase->igvn().replace_node(n, vn); - } + apply_state.set_memory_state(_adr_type, vn); + return VTransformApplyResult::make_vector(vn, vn->vect_type()); } void VTransformNode::register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn) const { @@ -944,15 +1024,6 @@ void VTransformGraph::print_schedule() const { } } -void VTransformGraph::print_memops_schedule() const { - tty->print_cr("\nVTransformGraph::print_memops_schedule:"); - int i = 0; - for_each_memop_in_schedule([&] (MemNode* mem) { - tty->print(" %3d: ", i++); - mem->dump(); - }); -} - void VTransformNode::print() const { tty->print("%3d %s (", _idx, name()); for (uint i = 0; i < _req; i++) { diff --git a/src/hotspot/share/opto/vtransform.hpp b/src/hotspot/share/opto/vtransform.hpp index 9a4e4de01a2..a004962eea7 100644 --- a/src/hotspot/share/opto/vtransform.hpp +++ b/src/hotspot/share/opto/vtransform.hpp @@ -39,7 +39,7 @@ // // This is the life-cycle of a VTransform: // - Construction: -// - From SuperWord, with the SuperWordVTransformBuilder. +// - From SuperWord PackSet, with the SuperWordVTransformBuilder. // // - Future Plans: optimize, if-conversion, etc. // @@ -49,8 +49,16 @@ // // - Apply: // - Changes to the C2 IR are only made once the "apply" method is called. +// - Align the main loop, by adjusting pre loop limit. +// - Add speculative runtime checks (alignment and aliasing). // - Each vtnode generates its corresponding scalar and vector C2 nodes, -// possibly replacing old scalar C2 nodes. +// possibly replacing old scalar C2 nodes. We apply each vtnode in order +// of the schedule, so that all input vtnodes are already applied, i.e. +// all input vtnodes have already generated the transformed C2 nodes. +// - We also build the new memory graph on the fly. The schedule may have +// reordered the memory operations, and so we cannot use the old memory +// graph, but must build it from the scheduled order. We keep track of +// the current memory state in VTransformApplyState. // // Future Plans with VTransform: // - Cost model: estimate if vectorization is profitable. @@ -65,6 +73,7 @@ class VTransformMemopScalarNode; class VTransformDataScalarNode; class VTransformLoopPhiNode; class VTransformCFGNode; +class VTransformCountedLoopNode; class VTransformOuterNode; class VTransformVectorNode; class VTransformElementWiseVectorNode; @@ -176,7 +185,6 @@ class VTransformGraph : public StackObj { bool schedule(); bool has_store_to_load_forwarding_failure(const VLoopAnalyzer& vloop_analyzer) const; - void apply_memops_reordering_with_schedule() const; void apply_vectorization_for_each_vtnode(uint& max_vector_length, uint& max_vector_width) const; private: @@ -187,13 +195,9 @@ class VTransformGraph : public StackObj { void collect_nodes_without_strong_in_edges(GrowableArray& stack) const; - template - void for_each_memop_in_schedule(Callback callback) const; - #ifndef PRODUCT void print_vtnodes() const; void print_schedule() const; - void print_memops_schedule() const; void trace_schedule_cycle(const GrowableArray& stack, const VectorSet& pre_visited, const VectorSet& post_visited) const; @@ -215,14 +219,14 @@ class VTransform : public StackObj { VTransformGraph _graph; - // Memory reference, and the alignment width (aw) for which we align the main-loop, + // VPointer, and the alignment width (aw) for which we align the main-loop, // by adjusting the pre-loop limit. - MemNode const* _mem_ref_for_main_loop_alignment; + VPointer const* _vpointer_for_main_loop_alignment; int _aw_for_main_loop_alignment; public: VTransform(const VLoopAnalyzer& vloop_analyzer, - MemNode const* mem_ref_for_main_loop_alignment, + VPointer const* vpointer_for_main_loop_alignment, int aw_for_main_loop_alignment NOT_PRODUCT( COMMA const VTransformTrace trace) ) : @@ -231,7 +235,7 @@ class VTransform : public StackObj { NOT_PRODUCT(_trace(trace) COMMA) _arena(mtCompiler, Arena::Tag::tag_superword), _graph(_vloop_analyzer, _arena NOT_PRODUCT(COMMA _trace)), - _mem_ref_for_main_loop_alignment(mem_ref_for_main_loop_alignment), + _vpointer_for_main_loop_alignment(vpointer_for_main_loop_alignment), _aw_for_main_loop_alignment(aw_for_main_loop_alignment) {} const VLoopAnalyzer& vloop_analyzer() const { return _vloop_analyzer; } @@ -257,7 +261,7 @@ class VTransform : public StackObj { } // Ensure that the main loop vectors are aligned by adjusting the pre loop limit. - void determine_mem_ref_and_aw_for_main_loop_alignment(); + void determine_vpointer_and_aw_for_main_loop_alignment(); void adjust_pre_loop_limit_to_align_main_loop_vectors(); void apply_speculative_alignment_runtime_checks(); @@ -271,7 +275,7 @@ class VTransform : public StackObj { }; // Keeps track of the state during "VTransform::apply" -// -> keep track of the already transformed nodes +// -> keep track of the already transformed nodes and the memory state. class VTransformApplyState : public StackObj { private: const VLoopAnalyzer& _vloop_analyzer; @@ -281,11 +285,35 @@ class VTransformApplyState : public StackObj { // generated def (input) nodes when we are generating the use nodes in "apply". GrowableArray _vtnode_idx_to_transformed_node; + // We keep track of the current memory state in each slice. If the slice has only + // loads (and no phi), then this is always the input memory state from before the + // loop. If there is a memory phi, this is initially the memory phi, and each time + // a store is processed, it is updated to that store. + GrowableArray _memory_states; + + // We need to keep track of the memory uses after the loop, for the slices that + // have a memory phi. + // use->in(in_idx) = + class MemoryStateUseAfterLoop : public StackObj { + public: + Node* _use; + int _in_idx; + int _alias_idx; + + MemoryStateUseAfterLoop(Node* use, int in_idx, int alias_idx) : + _use(use), _in_idx(in_idx), _alias_idx(alias_idx) {} + MemoryStateUseAfterLoop() : MemoryStateUseAfterLoop(nullptr, 0, 0) {} + }; + + GrowableArray _memory_state_uses_after_loop; + public: VTransformApplyState(const VLoopAnalyzer& vloop_analyzer, int num_vtnodes) : _vloop_analyzer(vloop_analyzer), - _vtnode_idx_to_transformed_node(num_vtnodes, num_vtnodes, nullptr) + _vtnode_idx_to_transformed_node(num_vtnodes, num_vtnodes, nullptr), + _memory_states(num_slices(), num_slices(), nullptr) { + init_memory_states_and_uses_after_loop(); } const VLoop& vloop() const { return _vloop_analyzer.vloop(); } @@ -294,6 +322,25 @@ class VTransformApplyState : public StackObj { void set_transformed_node(VTransformNode* vtn, Node* n); Node* transformed_node(const VTransformNode* vtn) const; + + Node* memory_state(int alias_idx) const { return _memory_states.at(alias_idx); } + void set_memory_state(int alias_idx, Node* n) { _memory_states.at_put(alias_idx, n); } + + Node* memory_state(const TypePtr* adr_type) const { + int alias_idx = phase()->C->get_alias_index(adr_type); + return memory_state(alias_idx); + } + + void set_memory_state(const TypePtr* adr_type, Node* n) { + int alias_idx = phase()->C->get_alias_index(adr_type); + return set_memory_state(alias_idx, n); + } + + void fix_memory_state_uses_after_loop(); + +private: + int num_slices() const { return _vloop_analyzer.memory_slices().heads().length(); } + void init_memory_states_and_uses_after_loop(); }; // The vtnodes (VTransformNode) resemble the C2 IR Nodes, and model a part of the @@ -433,6 +480,8 @@ class VTransformNode : public ArenaObj { } virtual VTransformMemopScalarNode* isa_MemopScalar() { return nullptr; } + virtual VTransformLoopPhiNode* isa_LoopPhi() { return nullptr; } + virtual VTransformCountedLoopNode* isa_CountedLoop() { return nullptr; } virtual VTransformOuterNode* isa_Outer() { return nullptr; } virtual VTransformVectorNode* isa_Vector() { return nullptr; } virtual VTransformElementWiseVectorNode* isa_ElementWiseVector() { return nullptr; } @@ -448,9 +497,8 @@ class VTransformNode : public ArenaObj { virtual const VPointer& vpointer() const { ShouldNotReachHere(); } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const = 0; - - Node* find_transformed_input(int i, const GrowableArray& vnode_idx_to_transformed_node) const; - + virtual void apply_backedge(VTransformApplyState& apply_state) const {}; + void apply_vtn_inputs_to_node(Node* n, VTransformApplyState& apply_state) const; void register_new_node_from_vectorization(VTransformApplyState& apply_state, Node* vn) const; NOT_PRODUCT(virtual const char* name() const = 0;) @@ -510,7 +558,9 @@ class VTransformLoopPhiNode : public VTransformNode { assert(_node->in(0)->is_Loop(), "phi ctrl must be Loop: %s", _node->in(0)->Name()); } + virtual VTransformLoopPhiNode* isa_LoopPhi() override { return this; } virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; + virtual void apply_backedge(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "LoopPhi"; };) NOT_PRODUCT(virtual void print_spec() const override;) }; @@ -531,6 +581,16 @@ class VTransformCFGNode : public VTransformNode { NOT_PRODUCT(virtual void print_spec() const override;) }; +// Identity transform for CountedLoop, the only CFG node with a backedge. +class VTransformCountedLoopNode : public VTransformCFGNode { +public: + VTransformCountedLoopNode(VTransform& vtransform, CountedLoopNode* n) : + VTransformCFGNode(vtransform, n) {} + + virtual VTransformCountedLoopNode* isa_CountedLoop() override { return this; } + NOT_PRODUCT(virtual const char* name() const override { return "CountedLoop"; };) +}; + // Wrapper node for nodes outside the loop that are inputs to nodes in the loop. // Since we want the loop-internal nodes to be able to reference all inputs as vtnodes, // we must wrap the inputs that are outside the loop into special vtnodes, too. @@ -632,22 +692,9 @@ class VTransformVectorNodeProperties : public StackObj { class VTransformVectorNode : public VTransformNode { private: const VTransformVectorNodeProperties _properties; -protected: - GrowableArray _nodes; public: VTransformVectorNode(VTransform& vtransform, const uint req, const VTransformVectorNodeProperties properties) : - VTransformNode(vtransform, req), - _properties(properties), - _nodes(vtransform.arena(), - properties.vector_length(), - properties.vector_length(), - nullptr) {} - - void set_nodes(const Node_List* pack) { - for (uint k = 0; k < pack->size(); k++) { - _nodes.at_put(k, pack->at(k)); - } - } + VTransformNode(vtransform, req), _properties(properties) {} virtual VTransformVectorNode* isa_Vector() override { return this; } void register_new_node_from_vectorization_and_replace_scalar_nodes(VTransformApplyState& apply_state, Node* vn) const; @@ -749,17 +796,23 @@ class VTransformMemVectorNode : public VTransformVectorNode { _vpointer(vpointer), _adr_type(adr_type) {} - const GrowableArray& nodes() const { return _nodes; } virtual VTransformMemVectorNode* isa_MemVector() override { return this; } virtual bool is_load_or_store_in_loop() const override { return true; } virtual const VPointer& vpointer() const override { return _vpointer; } }; class VTransformLoadVectorNode : public VTransformMemVectorNode { +private: + const LoadNode::ControlDependency _control_dependency; + public: // req = 3 -> [ctrl, mem, adr] - VTransformLoadVectorNode(VTransform& vtransform, const VTransformVectorNodeProperties properties, const VPointer& vpointer, const TypePtr* adr_type) : - VTransformMemVectorNode(vtransform, 3, properties, vpointer, adr_type) {} + VTransformLoadVectorNode(VTransform& vtransform, + const VTransformVectorNodeProperties properties, + const VPointer& vpointer, + const TypePtr* adr_type, + const LoadNode::ControlDependency control_dependency) : + VTransformMemVectorNode(vtransform, 3, properties, vpointer, adr_type), _control_dependency(control_dependency) {} LoadNode::ControlDependency control_dependency() const; virtual VTransformLoadVectorNode* isa_LoadVector() override { return this; } virtual bool is_load_in_loop() const override { return true; } @@ -777,30 +830,4 @@ class VTransformStoreVectorNode : public VTransformMemVectorNode { virtual VTransformApplyResult apply(VTransformApplyState& apply_state) const override; NOT_PRODUCT(virtual const char* name() const override { return "StoreVector"; };) }; - -// Invoke callback on all memops, in the order of the schedule. -template -void VTransformGraph::for_each_memop_in_schedule(Callback callback) const { - assert(_schedule.length() == _vtnodes.length(), "schedule was computed"); - - for (int i = 0; i < _schedule.length(); i++) { - VTransformNode* vtn = _schedule.at(i); - - // We must ignore nodes outside the loop. - if (vtn->isa_Outer() != nullptr) { continue; } - - VTransformMemopScalarNode* scalar = vtn->isa_MemopScalar(); - if (scalar != nullptr) { - callback(scalar->node()); - } - - VTransformMemVectorNode* vector = vtn->isa_MemVector(); - if (vector != nullptr) { - for (int j = 0; j < vector->nodes().length(); j++) { - callback(vector->nodes().at(j)->as_Mem()); - } - } - } -} - #endif // SHARE_OPTO_VTRANSFORM_HPP diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 2da9a074fb6..077b3fec505 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -1690,6 +1690,23 @@ void JvmtiExport::post_vthread_unmount(jobject vthread) { } } +bool JvmtiExport::has_frame_pops(JavaThread* thread) { + if (!can_post_frame_pop()) { + return false; + } + JvmtiThreadState *state = get_jvmti_thread_state(thread); + if (state == nullptr) { + return false; + } + JvmtiEnvThreadStateIterator it(state); + for (JvmtiEnvThreadState* ets = it.first(); ets != nullptr; ets = it.next(ets)) { + if (ets->has_frame_pops()) { + return true; + } + } + return false; +} + void JvmtiExport::continuation_yield_cleanup(JavaThread* thread, jint continuation_frame_count) { if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) { return; diff --git a/src/hotspot/share/prims/jvmtiExport.hpp b/src/hotspot/share/prims/jvmtiExport.hpp index 4f8c3016908..062057c70ab 100644 --- a/src/hotspot/share/prims/jvmtiExport.hpp +++ b/src/hotspot/share/prims/jvmtiExport.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, 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 @@ -373,6 +373,7 @@ class JvmtiExport : public AllStatic { JVMTI_ONLY(return _should_post_class_file_load_hook); NOT_JVMTI(return false;) } + static bool has_frame_pops(JavaThread* thread) NOT_JVMTI_RETURN_(false); static bool is_early_phase() NOT_JVMTI_RETURN_(false); static bool has_early_class_hook_env() NOT_JVMTI_RETURN_(false); static bool has_early_vmstart_env() NOT_JVMTI_RETURN_(false); diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index 74192d724f6..ef8875d582e 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -1358,11 +1358,11 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() { // constant pools HandleMark hm(current); InstanceKlass* the_class = get_ik(_class_defs[i].klass); - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); log_debug(redefine, class, load) - ("loading name=%s kind=%d (avail_mem=%zuK)", + ("loading name=%s kind=%d (avail_mem=" PHYS_MEM_TYPE_FORMAT "K)", the_class->external_name(), _class_load_kind, avail_mem >> 10); ClassFileStream st((u1*)_class_defs[i].class_bytes, @@ -1530,7 +1530,7 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() { // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); log_debug(redefine, class, load) - ("loaded name=%s (avail_mem=%zuK)", the_class->external_name(), avail_mem >> 10); + ("loaded name=%s (avail_mem=" PHYS_MEM_TYPE_FORMAT "K)", the_class->external_name(), avail_mem >> 10); } return JVMTI_ERROR_NONE; @@ -4438,11 +4438,11 @@ void VM_RedefineClasses::redefine_single_class(Thread* current, jclass the_jclas ResourceMark rm(current); // increment the classRedefinedCount field in the_class and in any // direct and indirect subclasses of the_class - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); log_info(redefine, class, load) - ("redefined name=%s, count=%d (avail_mem=%zuK)", + ("redefined name=%s, count=%d (avail_mem=" PHYS_MEM_TYPE_FORMAT "K)", the_class->external_name(), java_lang_Class::classRedefinedCount(the_class->java_mirror()), avail_mem >> 10); Events::log_redefinition(current, "redefined class name=%s, count=%d", the_class->external_name(), diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 6d9ab57bb9a..b4d100341e0 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -39,6 +39,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" +#include "code/compiledIC.hpp" #include "compiler/compilationPolicy.hpp" #include "compiler/compilerOracle.hpp" #include "compiler/directivesParser.hpp" @@ -1548,19 +1549,23 @@ struct CodeBlobStub { name(os::strdup(blob->name())), size(blob->size()), blob_type(static_cast(WhiteBox::get_blob_type(blob))), - address((jlong) blob) { } + address((jlong) blob), + code_begin((jlong) blob->code_begin()), + is_nmethod((jboolean) blob->is_nmethod()) { } ~CodeBlobStub() { os::free((void*) name); } const char* const name; const jint size; const jint blob_type; const jlong address; + const jlong code_begin; + const jboolean is_nmethod; }; static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBlobStub* cb) { ResourceMark rm; jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); CHECK_JNI_EXCEPTION_(env, nullptr); - jobjectArray result = env->NewObjectArray(4, clazz, nullptr); + jobjectArray result = env->NewObjectArray(6, clazz, nullptr); jstring name = env->NewStringUTF(cb->name); CHECK_JNI_EXCEPTION_(env, nullptr); @@ -1578,6 +1583,14 @@ static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBl CHECK_JNI_EXCEPTION_(env, nullptr); env->SetObjectArrayElement(result, 3, obj); + obj = longBox(thread, env, cb->code_begin); + CHECK_JNI_EXCEPTION_(env, nullptr); + env->SetObjectArrayElement(result, 4, obj); + + obj = booleanBox(thread, env, cb->is_nmethod); + CHECK_JNI_EXCEPTION_(env, nullptr); + env->SetObjectArrayElement(result, 5, obj); + return result; } @@ -1627,6 +1640,44 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo return result; WB_END +WB_ENTRY(void, WB_RelocateNMethodFromMethod(JNIEnv* env, jobject o, jobject method, jint blob_type)) + ResourceMark rm(THREAD); + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION(env); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + nmethod* code = mh->code(); + if (code != nullptr) { + MutexLocker ml_Compile_lock(Compile_lock); + CompiledICLocker ic_locker(code); + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); + code->relocate(static_cast(blob_type)); + } +WB_END + +WB_ENTRY(void, WB_RelocateNMethodFromAddr(JNIEnv* env, jobject o, jlong addr, jint blob_type)) + ResourceMark rm(THREAD); + CHECK_JNI_EXCEPTION(env); + void* address = (void*) addr; + + if (address == nullptr) { + return; + } + + MutexLocker ml_Compile_lock(Compile_lock); + MutexLocker ml_CompiledIC_lock(CompiledIC_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); + + // Verify that nmethod address is still valid + CodeBlob* blob = CodeCache::find_blob(address); + if (blob != nullptr && blob->is_nmethod()) { + nmethod* code = blob->as_nmethod(); + if (code->is_in_use()) { + CompiledICLocker ic_locker(code); + code->relocate(static_cast(blob_type)); + } + } +WB_END + CodeBlob* WhiteBox::allocate_code_blob(int size, CodeBlobType blob_type) { guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled"); BufferBlob* blob; @@ -2510,7 +2561,7 @@ WB_END // Available memory of the host machine (container-aware) WB_ENTRY(jlong, WB_HostAvailableMemory(JNIEnv* env, jobject o)) - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); return static_cast(avail_mem); @@ -2659,7 +2710,7 @@ WB_ENTRY(void, WB_WaitUnsafe(JNIEnv* env, jobject wb, jint time)) os::naked_short_sleep(time); WB_END -WB_ENTRY(void, WB_BusyWait(JNIEnv* env, jobject wb, jint time)) +WB_ENTRY(void, WB_BusyWaitCPUTime(JNIEnv* env, jobject wb, jint time)) ThreadToNativeFromVM ttn(thread); u8 start = os::current_thread_cpu_time(); u8 target_duration = time * (u8)1000000; @@ -2670,21 +2721,12 @@ WB_END WB_ENTRY(jboolean, WB_CPUSamplerSetOutOfStackWalking(JNIEnv* env, jobject wb, jboolean enable)) #if defined(ASSERT) && INCLUDE_JFR && defined(LINUX) - JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(enable == JNI_TRUE); - return JNI_TRUE; + return JfrCPUTimeThreadSampling::set_out_of_stack_walking_enabled(enable == JNI_TRUE) ? JNI_TRUE : JNI_FALSE; #else return JNI_FALSE; #endif WB_END -WB_ENTRY(jlong, WB_CPUSamplerOutOfStackWalkingIterations(JNIEnv* env, jobject wb)) - #if defined(ASSERT) && INCLUDE_JFR && defined(LINUX) - return (jlong)JfrCPUTimeThreadSampling::out_of_stack_walking_iterations(); - #else - return 0; - #endif -WB_END - WB_ENTRY(jstring, WB_GetLibcName(JNIEnv* env, jobject o)) ThreadToNativeFromVM ttn(thread); jstring info_string = env->NewStringUTF(XSTR(LIBC)); @@ -2916,6 +2958,9 @@ static JNINativeMethod methods[] = { {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, {CC"getNMethod0", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, + {CC"relocateNMethodFromMethod0", CC"(Ljava/lang/reflect/Executable;I)V", + (void*)&WB_RelocateNMethodFromMethod }, + {CC"relocateNMethodFromAddr", CC"(JI)V", (void*)&WB_RelocateNMethodFromAddr }, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, @@ -3038,9 +3083,8 @@ static JNINativeMethod methods[] = { {CC"isJVMTIIncluded", CC"()Z", (void*)&WB_IsJVMTIIncluded}, {CC"waitUnsafe", CC"(I)V", (void*)&WB_WaitUnsafe}, - {CC"busyWait", CC"(I)V", (void*)&WB_BusyWait}, + {CC"busyWaitCPUTime", CC"(I)V", (void*)&WB_BusyWaitCPUTime}, {CC"cpuSamplerSetOutOfStackWalking", CC"(Z)Z", (void*)&WB_CPUSamplerSetOutOfStackWalking}, - {CC"cpuSamplerOutOfStackWalkingIterations", CC"()J",(void*)&WB_CPUSamplerOutOfStackWalkingIterations}, {CC"getLibcName", CC"()Ljava/lang/String;", (void*)&WB_GetLibcName}, {CC"pinObject", CC"(Ljava/lang/Object;)V", (void*)&WB_PinObject}, diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index b7ab68e143c..8b703cb442a 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -31,6 +31,7 @@ #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "compiler/compilerDefinitions.hpp" +#include "gc/shared/gc_globals.hpp" #include "gc/shared/gcArguments.hpp" #include "gc/shared/gcConfig.hpp" #include "gc/shared/genArguments.hpp" @@ -1506,49 +1507,59 @@ size_t Arguments::limit_heap_by_allocatable_memory(size_t limit) { // Use static initialization to get the default before parsing static const size_t DefaultHeapBaseMinAddress = HeapBaseMinAddress; +static size_t clamp_by_size_t_max(uint64_t value) { + return (size_t)MIN2(value, (uint64_t)std::numeric_limits::max()); +} + void Arguments::set_heap_size() { - julong phys_mem; - - // If the user specified one of these options, they - // want specific memory sizing so do not limit memory - // based on compressed oops addressability. - // Also, memory limits will be calculated based on - // available os physical memory, not our MaxRAM limit, - // unless MaxRAM is also specified. - bool override_coop_limit = (!FLAG_IS_DEFAULT(MaxRAMPercentage) || - !FLAG_IS_DEFAULT(MinRAMPercentage) || - !FLAG_IS_DEFAULT(InitialRAMPercentage) || - !FLAG_IS_DEFAULT(MaxRAM)); - if (override_coop_limit) { - if (FLAG_IS_DEFAULT(MaxRAM)) { - phys_mem = static_cast(os::physical_memory()); - FLAG_SET_ERGO(MaxRAM, (uint64_t)phys_mem); + uint64_t physical_memory; + + // Check if the user has configured any limit on the amount of RAM we may use. + bool has_ram_limit = !FLAG_IS_DEFAULT(MaxRAMPercentage) || + !FLAG_IS_DEFAULT(MinRAMPercentage) || + !FLAG_IS_DEFAULT(InitialRAMPercentage) || + !FLAG_IS_DEFAULT(MaxRAM); + + if (has_ram_limit) { + if (!FLAG_IS_DEFAULT(MaxRAM)) { + // The user has configured MaxRAM, use that instead of physical memory + // reported by the OS. + physical_memory = MaxRAM; } else { - phys_mem = (julong)MaxRAM; + // The user has configured a limit, make sure MaxRAM reflects the physical + // memory limit that heap sizing takes into account. + physical_memory = os::physical_memory(); + FLAG_SET_ERGO(MaxRAM, physical_memory); } } else { - phys_mem = FLAG_IS_DEFAULT(MaxRAM) ? MIN2(static_cast(os::physical_memory()), (julong)MaxRAM) - : (julong)MaxRAM; + // If the user did not specify any limit, choose the lowest of the available + // physical memory and MaxRAM. MaxRAM is typically set to 128GB on 64-bit + // architecture. + physical_memory = MIN2(os::physical_memory(), MaxRAM); } - // If the maximum heap size has not been set with -Xmx, - // then set it as fraction of the size of physical memory, - // respecting the maximum and minimum sizes of the heap. + // If the maximum heap size has not been set with -Xmx, then set it as + // fraction of the size of physical memory, respecting the maximum and + // minimum sizes of the heap. if (FLAG_IS_DEFAULT(MaxHeapSize)) { - julong reasonable_max = (julong)(((double)phys_mem * MaxRAMPercentage) / 100); - const julong reasonable_min = (julong)(((double)phys_mem * MinRAMPercentage) / 100); + uint64_t min_memory = (uint64_t)(((double)physical_memory * MinRAMPercentage) / 100); + uint64_t max_memory = (uint64_t)(((double)physical_memory * MaxRAMPercentage) / 100); + + const size_t reasonable_min = clamp_by_size_t_max(min_memory); + size_t reasonable_max = clamp_by_size_t_max(max_memory); + if (reasonable_min < MaxHeapSize) { // Small physical memory, so use a minimum fraction of it for the heap reasonable_max = reasonable_min; } else { // Not-small physical memory, so require a heap at least // as large as MaxHeapSize - reasonable_max = MAX2(reasonable_max, (julong)MaxHeapSize); + reasonable_max = MAX2(reasonable_max, MaxHeapSize); } if (!FLAG_IS_DEFAULT(ErgoHeapSizeLimit) && ErgoHeapSizeLimit != 0) { // Limit the heap size to ErgoHeapSizeLimit - reasonable_max = MIN2(reasonable_max, (julong)ErgoHeapSizeLimit); + reasonable_max = MIN2(reasonable_max, ErgoHeapSizeLimit); } reasonable_max = limit_heap_by_allocatable_memory(reasonable_max); @@ -1558,9 +1569,9 @@ void Arguments::set_heap_size() { // so be sure that the maximum size is consistent. Done // after call to limit_heap_by_allocatable_memory because that // method might reduce the allocation size. - reasonable_max = MAX2(reasonable_max, (julong)InitialHeapSize); + reasonable_max = MAX2(reasonable_max, InitialHeapSize); } else if (!FLAG_IS_DEFAULT(MinHeapSize)) { - reasonable_max = MAX2(reasonable_max, (julong)MinHeapSize); + reasonable_max = MAX2(reasonable_max, MinHeapSize); } #ifdef _LP64 @@ -1569,8 +1580,8 @@ void Arguments::set_heap_size() { if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) { if (HeapBaseMinAddress < DefaultHeapBaseMinAddress) { // matches compressed oops printing flags - log_debug(gc, heap, coops)("HeapBaseMinAddress must be at least %zu" - " (%zuG) which is greater than value given %zu", + log_debug(gc, heap, coops)("HeapBaseMinAddress must be at least %zu " + "(%zuG) which is greater than value given %zu", DefaultHeapBaseMinAddress, DefaultHeapBaseMinAddress/G, HeapBaseMinAddress); @@ -1578,61 +1589,62 @@ void Arguments::set_heap_size() { } } } + if (UseCompressedOops) { - // Limit the heap size to the maximum possible when using compressed oops - julong max_coop_heap = (julong)max_heap_for_compressed_oops(); + size_t heap_end = HeapBaseMinAddress + MaxHeapSize; + size_t max_coop_heap = max_heap_for_compressed_oops(); - if (HeapBaseMinAddress + MaxHeapSize < max_coop_heap) { - // Heap should be above HeapBaseMinAddress to get zero based compressed oops - // but it should be not less than default MaxHeapSize. + // Limit the heap size to the maximum possible when using compressed oops + if (heap_end < max_coop_heap) { + // Heap should be above HeapBaseMinAddress to get zero based compressed + // oops but it should be not less than default MaxHeapSize. max_coop_heap -= HeapBaseMinAddress; } - // If user specified flags prioritizing os physical - // memory limits, then disable compressed oops if - // limits exceed max_coop_heap and UseCompressedOops - // was not specified. + // If the user has configured any limit on the amount of RAM we may use, + // then disable compressed oops if the calculated max exceeds max_coop_heap + // and UseCompressedOops was not specified. if (reasonable_max > max_coop_heap) { - if (FLAG_IS_ERGO(UseCompressedOops) && override_coop_limit) { - aot_log_info(aot)("UseCompressedOops disabled due to" - " max heap %zu > compressed oop heap %zu. " - "Please check the setting of MaxRAMPercentage %5.2f." - ,(size_t)reasonable_max, (size_t)max_coop_heap, MaxRAMPercentage); + if (FLAG_IS_ERGO(UseCompressedOops) && has_ram_limit) { + aot_log_info(aot)("UseCompressedOops disabled due to " + "max heap %zu > compressed oop heap %zu. " + "Please check the setting of MaxRAMPercentage %5.2f.", + reasonable_max, max_coop_heap, MaxRAMPercentage); FLAG_SET_ERGO(UseCompressedOops, false); } else { - reasonable_max = MIN2(reasonable_max, max_coop_heap); + reasonable_max = max_coop_heap; } } } #endif // _LP64 - log_trace(gc, heap)(" Maximum heap size %zu", (size_t) reasonable_max); - FLAG_SET_ERGO(MaxHeapSize, (size_t)reasonable_max); + log_trace(gc, heap)(" Maximum heap size %zu", reasonable_max); + FLAG_SET_ERGO(MaxHeapSize, reasonable_max); } // If the minimum or initial heap_size have not been set or requested to be set // ergonomically, set them accordingly. if (InitialHeapSize == 0 || MinHeapSize == 0) { - julong reasonable_minimum = (julong)(OldSize + NewSize); - - reasonable_minimum = MIN2(reasonable_minimum, (julong)MaxHeapSize); - + size_t reasonable_minimum = clamp_by_size_t_max((uint64_t)OldSize + (uint64_t)NewSize); + reasonable_minimum = MIN2(reasonable_minimum, MaxHeapSize); reasonable_minimum = limit_heap_by_allocatable_memory(reasonable_minimum); if (InitialHeapSize == 0) { - julong reasonable_initial = (julong)(((double)phys_mem * InitialRAMPercentage) / 100); + uint64_t initial_memory = (uint64_t)(((double)physical_memory * InitialRAMPercentage) / 100); + size_t reasonable_initial = clamp_by_size_t_max(initial_memory); reasonable_initial = limit_heap_by_allocatable_memory(reasonable_initial); - reasonable_initial = MAX3(reasonable_initial, reasonable_minimum, (julong)MinHeapSize); - reasonable_initial = MIN2(reasonable_initial, (julong)MaxHeapSize); + reasonable_initial = MAX3(reasonable_initial, reasonable_minimum, MinHeapSize); + reasonable_initial = MIN2(reasonable_initial, MaxHeapSize); FLAG_SET_ERGO(InitialHeapSize, (size_t)reasonable_initial); log_trace(gc, heap)(" Initial heap size %zu", InitialHeapSize); } + // If the minimum heap size has not been set (via -Xms or -XX:MinHeapSize), // synchronize with InitialHeapSize to avoid errors with the default value. if (MinHeapSize == 0) { - FLAG_SET_ERGO(MinHeapSize, MIN2((size_t)reasonable_minimum, InitialHeapSize)); + FLAG_SET_ERGO(MinHeapSize, MIN2(reasonable_minimum, InitialHeapSize)); log_trace(gc, heap)(" Minimum heap size %zu", MinHeapSize); } } @@ -1649,7 +1661,7 @@ jint Arguments::set_aggressive_heap_flags() { // Thus, we need to make sure we're using a julong for intermediate // calculations. julong initHeapSize; - size_t phys_mem = os::physical_memory(); + physical_memory_size_type phys_mem = os::physical_memory(); julong total_memory = static_cast(phys_mem); if (total_memory < (julong) 256 * M) { diff --git a/src/hotspot/share/runtime/basicLock.cpp b/src/hotspot/share/runtime/basicLock.cpp index 71082e24bb9..4a6e7402dfa 100644 --- a/src/hotspot/share/runtime/basicLock.cpp +++ b/src/hotspot/share/runtime/basicLock.cpp @@ -74,7 +74,7 @@ void BasicLock::move_to(oop obj, BasicLock* dest) { } #ifdef ASSERT else { - dest->set_bad_metadata_deopt(); + dest->set_bad_monitor_deopt(); } #endif } diff --git a/src/hotspot/share/runtime/basicLock.hpp b/src/hotspot/share/runtime/basicLock.hpp index c22416a1c06..479748f51a4 100644 --- a/src/hotspot/share/runtime/basicLock.hpp +++ b/src/hotspot/share/runtime/basicLock.hpp @@ -37,23 +37,21 @@ class BasicLock { private: // Used as a cache of the ObjectMonitor* used when locking. Must either // be nullptr or the ObjectMonitor* used when locking. - volatile uintptr_t _metadata; + ObjectMonitor* volatile _monitor; - uintptr_t get_metadata() const { return AtomicAccess::load(&_metadata); } - void set_metadata(uintptr_t value) { AtomicAccess::store(&_metadata, value); } - static int metadata_offset_in_bytes() { return (int)offset_of(BasicLock, _metadata); } + ObjectMonitor* get_monitor() const { return AtomicAccess::load(&_monitor); } + void set_monitor(ObjectMonitor* mon) { AtomicAccess::store(&_monitor, mon); } + static int monitor_offset_in_bytes() { return (int)offset_of(BasicLock, _monitor); } public: - BasicLock() : _metadata(0) {} + BasicLock() : _monitor(nullptr) {} - void set_bad_metadata_deopt() { set_metadata(badDispHeaderDeopt); } - - static int displaced_header_offset_in_bytes() { return metadata_offset_in_bytes(); } + void set_bad_monitor_deopt() { set_monitor(reinterpret_cast(badDispHeaderDeopt)); } inline ObjectMonitor* object_monitor_cache() const; inline void clear_object_monitor_cache(); inline void set_object_monitor_cache(ObjectMonitor* mon); - static int object_monitor_cache_offset_in_bytes() { return metadata_offset_in_bytes(); } + static int object_monitor_cache_offset_in_bytes() { return monitor_offset_in_bytes(); } void print_on(outputStream* st, oop owner) const; diff --git a/src/hotspot/share/runtime/basicLock.inline.hpp b/src/hotspot/share/runtime/basicLock.inline.hpp index 2ea1fe2371c..9f0f26ee957 100644 --- a/src/hotspot/share/runtime/basicLock.inline.hpp +++ b/src/hotspot/share/runtime/basicLock.inline.hpp @@ -32,23 +32,23 @@ inline ObjectMonitor* BasicLock::object_monitor_cache() const { assert(UseObjectMonitorTable, "must be"); #if !defined(ZERO) && (defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64) || defined(S390)) - return reinterpret_cast(get_metadata()); + return reinterpret_cast(get_monitor()); #else // Other platforms do not make use of the cache yet, // and are not as careful with maintaining the invariant - // that the metadata either is nullptr or ObjectMonitor*. + // that the monitor either is nullptr or a valid ObjectMonitor*. return nullptr; #endif } inline void BasicLock::clear_object_monitor_cache() { assert(UseObjectMonitorTable, "must be"); - set_metadata(0); + set_monitor(nullptr); } inline void BasicLock::set_object_monitor_cache(ObjectMonitor* mon) { assert(UseObjectMonitorTable, "must be"); - set_metadata(reinterpret_cast(mon)); + set_monitor(mon); } #endif // SHARE_RUNTIME_BASICLOCK_INLINE_HPP diff --git a/src/hotspot/share/runtime/continuation.hpp b/src/hotspot/share/runtime/continuation.hpp index e678e0bd42b..0cfd484361d 100644 --- a/src/hotspot/share/runtime/continuation.hpp +++ b/src/hotspot/share/runtime/continuation.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,10 +53,9 @@ enum freeze_result { freeze_ok_bottom = 1, freeze_pinned_cs = 2, freeze_pinned_native = 3, - freeze_pinned_monitor = 4, - freeze_exception = 5, - freeze_not_mounted = 6, - freeze_unsupported = 7 + freeze_exception = 4, + freeze_not_mounted = 5, + freeze_unsupported = 6 }; class Continuation : AllStatic { diff --git a/src/hotspot/share/runtime/continuationEntry.cpp b/src/hotspot/share/runtime/continuationEntry.cpp index 4551bfa7cc8..69a20808798 100644 --- a/src/hotspot/share/runtime/continuationEntry.cpp +++ b/src/hotspot/share/runtime/continuationEntry.cpp @@ -107,7 +107,6 @@ void ContinuationEntry::describe(FrameValues& values, int frame_no) const { values.describe(frame_no, (intptr_t*)(usp + in_bytes(ContinuationEntry::argsize_offset())), "argsize"); values.describe(frame_no, (intptr_t*)(usp + in_bytes(ContinuationEntry::pin_count_offset())), "pin_count"); values.describe(frame_no, (intptr_t*)(usp + in_bytes(ContinuationEntry::parent_cont_fastpath_offset())), "parent fastpath"); - values.describe(frame_no, (intptr_t*)(usp + in_bytes(ContinuationEntry::parent_held_monitor_count_offset())), "parent held monitor count"); } #endif diff --git a/src/hotspot/share/runtime/continuationEntry.hpp b/src/hotspot/share/runtime/continuationEntry.hpp index 3c8532b9e87..8361f2f912b 100644 --- a/src/hotspot/share/runtime/continuationEntry.hpp +++ b/src/hotspot/share/runtime/continuationEntry.hpp @@ -79,11 +79,6 @@ class ContinuationEntry { // The caller (if there is one) is the still frozen top frame in the StackChunk. int _argsize; intptr_t* _parent_cont_fastpath; -#ifdef _LP64 - int64_t _parent_held_monitor_count; -#else - int32_t _parent_held_monitor_count; -#endif uint32_t _pin_count; public: @@ -94,7 +89,6 @@ class ContinuationEntry { static ByteSize argsize_offset() { return byte_offset_of(ContinuationEntry, _argsize); } static ByteSize pin_count_offset(){ return byte_offset_of(ContinuationEntry, _pin_count); } static ByteSize parent_cont_fastpath_offset() { return byte_offset_of(ContinuationEntry, _parent_cont_fastpath); } - static ByteSize parent_held_monitor_count_offset() { return byte_offset_of(ContinuationEntry, _parent_held_monitor_count); } static address return_pc() { return _return_pc; } static address return_pc_address() { return (address)&_return_pc; } @@ -103,7 +97,6 @@ class ContinuationEntry { static size_t size() { return align_up((int)sizeof(ContinuationEntry), 2*wordSize); } ContinuationEntry* parent() const { return _parent; } - int64_t parent_held_monitor_count() const { return (int64_t)_parent_held_monitor_count; } static address entry_pc() { return _return_pc; } intptr_t* entry_sp() const { return (intptr_t*)this; } diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 64f9d2b9994..33b4f2bf488 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -1619,15 +1619,14 @@ static int num_java_frames(ContinuationWrapper& cont) { } static void invalidate_jvmti_stack(JavaThread* thread) { - if (thread->is_interp_only_mode()) { - JvmtiThreadState *state = thread->jvmti_thread_state(); - if (state != nullptr) - state->invalidate_cur_stack_depth(); + JvmtiThreadState *state = thread->jvmti_thread_state(); + if (state != nullptr) { + state->invalidate_cur_stack_depth(); } } static void jvmti_yield_cleanup(JavaThread* thread, ContinuationWrapper& cont) { - if (JvmtiExport::can_post_frame_pop()) { + if (JvmtiExport::has_frame_pops(thread)) { int num_frames = num_java_frames(cont); ContinuationWrapper::SafepointOp so(Thread::current(), cont); @@ -1737,13 +1736,10 @@ static inline freeze_result freeze_internal(JavaThread* current, intptr_t* const assert(entry->is_virtual_thread() == (entry->scope(current) == java_lang_VirtualThread::vthread_scope()), ""); - assert((current->held_monitor_count() == 0 && current->jni_monitor_count() == 0), - "Held monitor count should not be used for lightweight locking: " INT64_FORMAT " JNI: " INT64_FORMAT, (int64_t)current->held_monitor_count(), (int64_t)current->jni_monitor_count()); - - if (entry->is_pinned() || current->held_monitor_count() > 0) { - log_develop_debug(continuations)("PINNED due to critical section/hold monitor"); + if (entry->is_pinned()) { + log_develop_debug(continuations)("PINNED due to critical section"); verify_continuation(cont.continuation()); - freeze_result res = entry->is_pinned() ? freeze_pinned_cs : freeze_pinned_monitor; + const freeze_result res = freeze_pinned_cs; if (!preempt) { JFR_ONLY(current->set_last_freeze_fail_result(res);) } @@ -1800,8 +1796,6 @@ static freeze_result is_pinned0(JavaThread* thread, oop cont_scope, bool safepoi } if (entry->is_pinned()) { return freeze_pinned_cs; - } else if (thread->held_monitor_count() > 0) { - return freeze_pinned_monitor; } RegisterMap map(thread, @@ -1837,15 +1831,12 @@ static freeze_result is_pinned0(JavaThread* thread, oop cont_scope, bool safepoi if (scope == cont_scope) { break; } - intx monitor_count = entry->parent_held_monitor_count(); entry = entry->parent(); if (entry == nullptr) { break; } if (entry->is_pinned()) { return freeze_pinned_cs; - } else if (monitor_count > 0) { - return freeze_pinned_monitor; } } } diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index d14db6ad0ed..853c6554022 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -589,12 +589,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread // Verify we have the right vframeArray assert(cb->frame_size() >= 0, "Unexpected frame size"); intptr_t* unpack_sp = stub_frame.sp() + cb->frame_size(); - - // If the deopt call site is a MethodHandle invoke call site we have - // to adjust the unpack_sp. - nmethod* deoptee_nm = deoptee.cb()->as_nmethod_or_null(); - if (deoptee_nm != nullptr && deoptee_nm->is_method_handle_return(deoptee.pc())) - unpack_sp = deoptee.unextended_sp(); + assert(unpack_sp == deoptee.unextended_sp(), "must be"); #ifdef ASSERT assert(cb->is_deoptimization_stub() || @@ -1656,7 +1651,7 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArraylock()->set_bad_metadata_deopt(); + mon_info->lock()->set_bad_monitor_deopt(); } #endif JvmtiDeferredUpdates::inc_relock_count_after_wait(deoptee_thread); diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp index 4e28135dccf..d0141c2e6cc 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -355,10 +355,8 @@ JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { } int minimum_alignment = 16; -#if defined(X86) && !defined(AMD64) +#if (defined(X86) && !defined(AMD64)) || defined(S390) minimum_alignment = 4; -#elif defined(S390) - minimum_alignment = 2; #endif if (InteriorEntryAlignment < minimum_alignment) { diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 75c6e388b0d..e578e614440 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -206,10 +206,7 @@ address frame::raw_pc() const { if (is_deoptimized_frame()) { nmethod* nm = cb()->as_nmethod_or_null(); assert(nm != nullptr, "only nmethod is expected here"); - if (nm->is_method_handle_return(pc())) - return nm->deopt_mh_handler_begin() - pc_return_offset; - else - return nm->deopt_handler_begin() - pc_return_offset; + return nm->deopt_handler_begin() - pc_return_offset; } else { return (pc() - pc_return_offset); } @@ -358,9 +355,7 @@ void frame::deoptimize(JavaThread* thread) { // If the call site is a MethodHandle call site use the MH deopt handler. nmethod* nm = _cb->as_nmethod(); - address deopt = nm->is_method_handle_return(pc()) ? - nm->deopt_mh_handler_begin() : - nm->deopt_handler_begin(); + address deopt = nm->deopt_handler_begin(); NativePostCallNop* inst = nativePostCallNop_at(pc()); diff --git a/src/hotspot/share/runtime/frame.inline.hpp b/src/hotspot/share/runtime/frame.inline.hpp index 449abddd443..cbf01dd5763 100644 --- a/src/hotspot/share/runtime/frame.inline.hpp +++ b/src/hotspot/share/runtime/frame.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,7 +76,10 @@ inline address frame::get_deopt_original_pc() const { nmethod* nm = _cb->as_nmethod_or_null(); if (nm != nullptr && nm->is_deopt_pc(_pc)) { - return nm->get_original_pc(this); + address original_pc = nm->get_original_pc(this); + assert(nm->insts_contains_inclusive(original_pc), + "original PC must be in the main code section of the compiled method (or must be immediately following it)"); + return original_pc; } return nullptr; } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index dac01d018bf..513edaf6588 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1565,6 +1565,9 @@ const int ObjectAlignmentInBytes = 8; "Start aggressive sweeping if less than X[%] of the total code cache is free.")\ range(0, 100) \ \ + product(bool, NMethodRelocation, false, EXPERIMENTAL, \ + "Enables use of experimental function nmethod::relocate()") \ + \ /* interpreter debugging */ \ develop(intx, BinarySwitchThreshold, 5, \ "Minimal number of lookupswitch entries for rewriting to binary " \ diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 9363f9055ba..6fda21ac86c 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -747,29 +747,19 @@ int JDK_Version::compare(const JDK_Version& other) const { /* See JEP 223 */ void JDK_Version::to_string(char* buffer, size_t buflen) const { - assert(buffer && buflen > 0, "call with useful buffer"); - size_t index = 0; - + assert((buffer != nullptr) && (buflen > 0), "call with useful buffer"); + stringStream ss{buffer, buflen}; if (!is_valid()) { - jio_snprintf(buffer, buflen, "%s", "(uninitialized)"); + ss.print_raw("(uninitialized)"); } else { - int rc = jio_snprintf( - &buffer[index], buflen - index, "%d.%d", _major, _minor); - if (rc == -1) return; - index += rc; + ss.print("%d.%d", _major, _minor); if (_patch > 0) { - rc = jio_snprintf(&buffer[index], buflen - index, ".%d.%d", _security, _patch); - if (rc == -1) return; - index += rc; + ss.print(".%d.%d", _security, _patch); } else if (_security > 0) { - rc = jio_snprintf(&buffer[index], buflen - index, ".%d", _security); - if (rc == -1) return; - index += rc; + ss.print(".%d", _security); } if (_build > 0) { - rc = jio_snprintf(&buffer[index], buflen - index, "+%d", _build); - if (rc == -1) return; - index += rc; + ss.print("+%d", _build); } } } diff --git a/src/hotspot/share/runtime/java.hpp b/src/hotspot/share/runtime/java.hpp index 21cbd76431f..67cf3fb686a 100644 --- a/src/hotspot/share/runtime/java.hpp +++ b/src/hotspot/share/runtime/java.hpp @@ -68,7 +68,6 @@ extern bool is_vm_statically_linked(); * string prior to JDK 1.6 was removed (partial initialization) */ class JDK_Version { - friend class VMStructs; friend class Universe; friend void JDK_Version_init(); private: diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index f5cd43b1769..8bb8095878f 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -476,7 +476,6 @@ JavaThread::JavaThread(MemTag mem_tag) : _exception_oop(oop()), _exception_pc(nullptr), _exception_handler_pc(nullptr), - _is_method_handle_return(0), _jni_active_critical(0), _pending_jni_exception_check_fn(nullptr), @@ -489,8 +488,6 @@ JavaThread::JavaThread(MemTag mem_tag) : _cont_entry(nullptr), _cont_fastpath(nullptr), _cont_fastpath_thread_state(1), - _held_monitor_count(0), - _jni_monitor_count(0), _unlocked_inflated_monitor(nullptr), _preempt_alternate_return(nullptr), @@ -928,27 +925,6 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { "should not have a Java frame when detaching or exiting"); ObjectSynchronizer::release_monitors_owned_by_thread(this); assert(!this->has_pending_exception(), "release_monitors should have cleared"); - // Check for monitor counts being out of sync. - assert(held_monitor_count() == jni_monitor_count(), - "held monitor count should be equal to jni: %zd != %zd", - held_monitor_count(), jni_monitor_count()); - // All in-use monitors, including JNI-locked ones, should have been released above. - assert(held_monitor_count() == 0, "Failed to unlock %zd object monitors", - held_monitor_count()); - } else { - // Check for monitor counts being out of sync. - assert(held_monitor_count() == jni_monitor_count(), - "held monitor count should be equal to jni: %zd != %zd", - held_monitor_count(), jni_monitor_count()); - // It is possible that a terminating thread failed to unlock monitors it locked - // via JNI so we don't assert the count is zero. - } - - if (CheckJNICalls && jni_monitor_count() > 0) { - // We would like a fatal here, but due to we never checked this before there - // is a lot of tests which breaks, even with an error log. - log_debug(jni)("JavaThread %s (tid: %zu) with Objects still locked by JNI MonitorEnter.", - exit_type == JavaThread::normal_exit ? "exiting" : "detaching", os::current_thread_id()); } // These things needs to be done while we are still a Java Thread. Make sure that thread @@ -1989,26 +1965,6 @@ void JavaThread::trace_stack() { #endif // PRODUCT -// Slow-path increment of the held monitor counts. JNI locking is always -// this slow-path. -void JavaThread::inc_held_monitor_count(intx i, bool jni) { -#ifdef SUPPORT_MONITOR_COUNT - // Nothing to do. Just do some sanity check. - assert(_held_monitor_count == 0, "counter should not be used"); - assert(_jni_monitor_count == 0, "counter should not be used"); -#endif // SUPPORT_MONITOR_COUNT -} - -// Slow-path decrement of the held monitor counts. JNI unlocking is always -// this slow-path. -void JavaThread::dec_held_monitor_count(intx i, bool jni) { -#ifdef SUPPORT_MONITOR_COUNT - // Nothing to do. Just do some sanity check. - assert(_held_monitor_count == 0, "counter should not be used"); - assert(_jni_monitor_count == 0, "counter should not be used"); -#endif // SUPPORT_MONITOR_COUNT -} - frame JavaThread::vthread_last_frame() { assert (is_vthread_mounted(), "Virtual thread not mounted"); return last_frame(); diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 00bc5969196..c8be1594a69 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -450,7 +450,6 @@ class JavaThread: public Thread { volatile oop _exception_oop; // Exception thrown in compiled code volatile address _exception_pc; // PC where exception happened volatile address _exception_handler_pc; // PC for handler of exception - volatile int _is_method_handle_return; // true (== 1) if the current exception PC is a MethodHandle call site. private: // support for JNI critical regions @@ -477,9 +476,6 @@ class JavaThread: public Thread { // frame inside the continuation that we know about int _cont_fastpath_thread_state; // whether global thread state allows continuation fastpath (JVMTI) - // It's signed for error detection. - intx _held_monitor_count; // used by continuations for fast lock detection - intx _jni_monitor_count; ObjectMonitor* _unlocked_inflated_monitor; // This is the field we poke in the interpreter and native @@ -663,13 +659,6 @@ class JavaThread: public Thread { bool cont_fastpath() const { return _cont_fastpath == nullptr && _cont_fastpath_thread_state != 0; } bool cont_fastpath_thread_state() const { return _cont_fastpath_thread_state != 0; } - void inc_held_monitor_count(intx i = 1, bool jni = false); - void dec_held_monitor_count(intx i = 1, bool jni = false); - - intx held_monitor_count() { return _held_monitor_count; } - intx jni_monitor_count() { return _jni_monitor_count; } - void clear_jni_monitor_count() { _jni_monitor_count = 0; } - // Support for SharedRuntime::monitor_exit_helper() ObjectMonitor* unlocked_inflated_monitor() const { return _unlocked_inflated_monitor; } void clear_unlocked_inflated_monitor() { @@ -817,7 +806,6 @@ class JavaThread: public Thread { void set_exception_oop(oop o); void set_exception_pc(address a) { _exception_pc = a; } void set_exception_handler_pc(address a) { _exception_handler_pc = a; } - void set_is_method_handle_return(bool value) { _is_method_handle_return = value ? 1 : 0; } void clear_exception_oop_and_pc() { set_exception_oop(nullptr); @@ -866,7 +854,6 @@ class JavaThread: public Thread { static ByteSize exception_oop_offset() { return byte_offset_of(JavaThread, _exception_oop); } static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc); } static ByteSize exception_handler_pc_offset() { return byte_offset_of(JavaThread, _exception_handler_pc); } - static ByteSize is_method_handle_return_offset() { return byte_offset_of(JavaThread, _is_method_handle_return); } static ByteSize active_handles_offset() { return byte_offset_of(JavaThread, _active_handles); } @@ -900,8 +887,6 @@ class JavaThread: public Thread { static ByteSize cont_entry_offset() { return byte_offset_of(JavaThread, _cont_entry); } static ByteSize cont_fastpath_offset() { return byte_offset_of(JavaThread, _cont_fastpath); } - static ByteSize held_monitor_count_offset() { return byte_offset_of(JavaThread, _held_monitor_count); } - static ByteSize jni_monitor_count_offset() { return byte_offset_of(JavaThread, _jni_monitor_count); } static ByteSize preemption_cancelled_offset() { return byte_offset_of(JavaThread, _preemption_cancelled); } static ByteSize preempt_alternate_return_offset() { return byte_offset_of(JavaThread, _preempt_alternate_return); } static ByteSize unlocked_inflated_monitor_offset() { return byte_offset_of(JavaThread, _unlocked_inflated_monitor); } diff --git a/src/hotspot/share/runtime/monitorDeflationThread.hpp b/src/hotspot/share/runtime/monitorDeflationThread.hpp index c0ae9dd2d6f..6b681617a4c 100644 --- a/src/hotspot/share/runtime/monitorDeflationThread.hpp +++ b/src/hotspot/share/runtime/monitorDeflationThread.hpp @@ -30,7 +30,6 @@ // A hidden from external view JavaThread for deflating idle monitors. class MonitorDeflationThread : public JavaThread { - friend class VMStructs; private: static void monitor_deflation_thread_entry(JavaThread* thread, TRAPS); diff --git a/src/hotspot/share/runtime/nonJavaThread.cpp b/src/hotspot/share/runtime/nonJavaThread.cpp index 2fb4c2dce02..cb0c3f8910d 100644 --- a/src/hotspot/share/runtime/nonJavaThread.cpp +++ b/src/hotspot/share/runtime/nonJavaThread.cpp @@ -50,15 +50,19 @@ class NonJavaThread::List { List() : _head(nullptr), _protect() {} }; -NonJavaThread::List NonJavaThread::_the_list; +DeferredStatic NonJavaThread::_the_list; + +void NonJavaThread::init() { + _the_list.initialize(); +} NonJavaThread::Iterator::Iterator() : - _protect_enter(_the_list._protect.enter()), - _current(AtomicAccess::load_acquire(&_the_list._head)) + _protect_enter(_the_list->_protect.enter()), + _current(AtomicAccess::load_acquire(&_the_list->_head)) {} NonJavaThread::Iterator::~Iterator() { - _the_list._protect.exit(_protect_enter); + _the_list->_protect.exit(_protect_enter); } void NonJavaThread::Iterator::step() { @@ -76,8 +80,8 @@ void NonJavaThread::add_to_the_list() { MutexLocker ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag); // Initialize BarrierSet-related data before adding to list. BarrierSet::barrier_set()->on_thread_attach(this); - AtomicAccess::release_store(&_next, _the_list._head); - AtomicAccess::release_store(&_the_list._head, this); + AtomicAccess::release_store(&_next, _the_list->_head); + AtomicAccess::release_store(&_the_list->_head, this); } void NonJavaThread::remove_from_the_list() { @@ -85,7 +89,7 @@ void NonJavaThread::remove_from_the_list() { MutexLocker ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag); // Cleanup BarrierSet-related data before removing from list. BarrierSet::barrier_set()->on_thread_detach(this); - NonJavaThread* volatile* p = &_the_list._head; + NonJavaThread* volatile* p = &_the_list->_head; for (NonJavaThread* t = *p; t != nullptr; p = &t->_next, t = *p) { if (t == this) { *p = _next; @@ -97,7 +101,7 @@ void NonJavaThread::remove_from_the_list() { // allowed, so do it while holding a dedicated lock. Outside and distinct // from NJTList_lock in case an iteration attempts to lock it. MutexLocker ml(NonJavaThreadsListSync_lock, Mutex::_no_safepoint_check_flag); - _the_list._protect.synchronize(); + _the_list->_protect.synchronize(); _next = nullptr; // Safe to drop the link now. } @@ -344,4 +348,3 @@ void WatcherThread::print_on(outputStream* st) const { Thread::print_on(st); st->cr(); } - diff --git a/src/hotspot/share/runtime/nonJavaThread.hpp b/src/hotspot/share/runtime/nonJavaThread.hpp index 6d9095924d9..aaf0dcdfa2d 100644 --- a/src/hotspot/share/runtime/nonJavaThread.hpp +++ b/src/hotspot/share/runtime/nonJavaThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, 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 @@ -26,14 +26,18 @@ #define SHARE_RUNTIME_NONJAVATHREAD_HPP #include "runtime/thread.hpp" +#include "utilities/deferredStatic.hpp" class NonJavaThread: public Thread { - friend class VMStructs; - - NonJavaThread* volatile _next; + friend class Threads; class List; - static List _the_list; + static DeferredStatic _the_list; + + // Deferred static initialization + static void init(); + + NonJavaThread* volatile _next; void add_to_the_list(); void remove_from_the_list(); @@ -103,7 +107,6 @@ class NamedThread: public NonJavaThread { // A single WatcherThread is used for simulating timer interrupts. class WatcherThread: public NonJavaThread { - friend class VMStructs; protected: virtual void run(); diff --git a/src/hotspot/share/runtime/notificationThread.hpp b/src/hotspot/share/runtime/notificationThread.hpp index 17977e93539..e8e72052e4a 100644 --- a/src/hotspot/share/runtime/notificationThread.hpp +++ b/src/hotspot/share/runtime/notificationThread.hpp @@ -33,7 +33,6 @@ // breakpoints inside registered MXBean notification listeners. class NotificationThread : public JavaThread { - friend class VMStructs; private: static void notification_thread_entry(JavaThread* thread, TRAPS); diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 8859f6e7f5f..4c00ecac697 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -1952,7 +1952,6 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { int relock_count = JvmtiDeferredUpdates::get_and_reset_relock_count_after_wait(current); _recursions = save // restore the old recursion count + relock_count; // increased by the deferred relock count - current->inc_held_monitor_count(relock_count); // Deopt never entered these counts. _waiters--; // decrement the number of waiters // Verify a few postconditions diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index 3c925928be2..50aec549045 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -32,6 +32,7 @@ #include "oops/weakHandle.hpp" #include "runtime/javaThread.hpp" #include "utilities/checkedCast.hpp" +#include "utilities/globalDefinitions.hpp" class ObjectMonitor; class ObjectMonitorContentionMark; @@ -72,20 +73,19 @@ class ObjectWaiter : public CHeapObj { void wait_reenter_begin(ObjectMonitor *mon); void wait_reenter_end(ObjectMonitor *mon); - ObjectWaiter* const badObjectWaiterPtr = (ObjectWaiter*) 0xBAD; void set_bad_pointers() { #ifdef ASSERT - this->_prev = badObjectWaiterPtr; - this->_next = badObjectWaiterPtr; + this->_prev = (ObjectWaiter*) badAddressVal; + this->_next = (ObjectWaiter*) badAddressVal; this->TState = ObjectWaiter::TS_RUN; #endif } ObjectWaiter* next() { - assert (_next != badObjectWaiterPtr, "corrupted list!"); + assert (_next != (ObjectWaiter*) badAddressVal, "corrupted list!"); return _next; } ObjectWaiter* prev() { - assert (_prev != badObjectWaiterPtr, "corrupted list!"); + assert (_prev != (ObjectWaiter*) badAddressVal, "corrupted list!"); return _prev; } }; diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 4f00ff17269..674b0a55841 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1184,13 +1184,13 @@ void os::print_summary_info(outputStream* st, char* buf, size_t buflen) { #endif // PRODUCT get_summary_cpu_info(buf, buflen); st->print("%s, ", buf); - size_t phys_mem = physical_memory(); - size_t mem = phys_mem/G; + physical_memory_size_type phys_mem = physical_memory(); + physical_memory_size_type mem = phys_mem/G; if (mem == 0) { // for low memory systems mem = phys_mem/M; - st->print("%d cores, %zuM, ", processor_count(), mem); + st->print("%d cores, " PHYS_MEM_TYPE_FORMAT "M, ", processor_count(), mem); } else { - st->print("%d cores, %zuG, ", processor_count(), mem); + st->print("%d cores, " PHYS_MEM_TYPE_FORMAT "G, ", processor_count(), mem); } get_summary_os_info(buf, buflen); st->print_raw(buf); @@ -1935,17 +1935,17 @@ bool os::is_server_class_machine() { return true; } // Then actually look at the machine - bool result = false; - const unsigned int server_processors = 2; - const julong server_memory = 2UL * G; + bool result = false; + const unsigned int server_processors = 2; + const physical_memory_size_type server_memory = 2UL * G; // We seem not to get our full complement of memory. // We allow some part (1/8?) of the memory to be "missing", // based on the sizes of DIMMs, and maybe graphics cards. - const julong missing_memory = 256UL * M; - size_t phys_mem = os::physical_memory(); + const physical_memory_size_type missing_memory = 256UL * M; + physical_memory_size_type phys_mem = os::physical_memory(); /* Is this a server class machine? */ if ((os::active_processor_count() >= (int)server_processors) && - (phys_mem >= (server_memory - missing_memory))) { + (phys_mem >= server_memory - missing_memory)) { const unsigned int logical_processors = VM_Version::logical_processors_per_package(); if (logical_processors > 1) { @@ -2204,22 +2204,22 @@ static void assert_nonempty_range(const char* addr, size_t bytes) { p2i(addr), p2i(addr) + bytes); } -bool os::used_memory(size_t& value) { +bool os::used_memory(physical_memory_size_type& value) { #ifdef LINUX if (OSContainer::is_containerized()) { jlong mem_usage = OSContainer::memory_usage_in_bytes(); if (mem_usage > 0) { - value = static_cast(mem_usage); + value = static_cast(mem_usage); return true; } else { return false; } } #endif - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); - size_t phys_mem = os::physical_memory(); + physical_memory_size_type phys_mem = os::physical_memory(); value = phys_mem - avail_mem; return true; } diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 626970fa4fb..e008f29eecc 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -168,7 +168,6 @@ class ErrnoPreserver { }; class os: AllStatic { - friend class VMStructs; friend class JVMCIVMStructs; friend class MallocTracker; @@ -332,14 +331,14 @@ class os: AllStatic { // For example, on Linux, "available" memory (`MemAvailable` in `/proc/meminfo`) is greater // than "free" memory (`MemFree` in `/proc/meminfo`) because Linux can free memory // aggressively (e.g. clear caches) so that it becomes available. - [[nodiscard]] static bool available_memory(size_t& value); - [[nodiscard]] static bool used_memory(size_t& value); - [[nodiscard]] static bool free_memory(size_t& value); + [[nodiscard]] static bool available_memory(physical_memory_size_type& value); + [[nodiscard]] static bool used_memory(physical_memory_size_type& value); + [[nodiscard]] static bool free_memory(physical_memory_size_type& value); - [[nodiscard]] static bool total_swap_space(size_t& value); - [[nodiscard]] static bool free_swap_space(size_t& value); + [[nodiscard]] static bool total_swap_space(physical_memory_size_type& value); + [[nodiscard]] static bool free_swap_space(physical_memory_size_type& value); - static size_t physical_memory(); + static physical_memory_size_type physical_memory(); static bool is_server_class_machine(); static size_t rss(); @@ -535,7 +534,6 @@ class os: AllStatic { static void realign_memory(char *addr, size_t bytes, size_t alignment_hint); // NUMA-specific interface - static bool numa_has_group_homing(); static void numa_make_local(char *addr, size_t bytes, int lgrp_hint); static void numa_make_global(char *addr, size_t bytes); static size_t numa_get_groups_num(); diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index a1922612bd6..051cc6261f8 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -30,7 +30,6 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/gcLocker.hpp" #include "gc/shared/oopStorage.hpp" -#include "gc/shared/strongRootsScope.hpp" #include "gc/shared/workerThread.hpp" #include "gc/shared/workerUtils.hpp" #include "interpreter/interpreter.hpp" diff --git a/src/hotspot/share/runtime/serviceThread.hpp b/src/hotspot/share/runtime/serviceThread.hpp index d029c64590e..f65847ece00 100644 --- a/src/hotspot/share/runtime/serviceThread.hpp +++ b/src/hotspot/share/runtime/serviceThread.hpp @@ -34,7 +34,6 @@ class JvmtiDeferredEvent; class ServiceThread : public JavaThread { - friend class VMStructs; private: DEBUG_ONLY(static JavaThread* _instance;) static JvmtiDeferredEvent* _jvmti_event; diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index c3a6e0a4dc3..a8c9a64d63a 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -264,6 +264,46 @@ void SharedRuntime::print_ic_miss_histogram() { tty->print_cr("Total IC misses: %7d", tot_misses); } } + +#ifdef COMPILER2 +// Runtime methods for printf-style debug nodes (same printing format as fieldDescriptor::print_on_for) +void SharedRuntime::debug_print_value(jboolean x) { + tty->print_cr("boolean %d", x); +} + +void SharedRuntime::debug_print_value(jbyte x) { + tty->print_cr("byte %d", x); +} + +void SharedRuntime::debug_print_value(jshort x) { + tty->print_cr("short %d", x); +} + +void SharedRuntime::debug_print_value(jchar x) { + tty->print_cr("char %c %d", isprint(x) ? x : ' ', x); +} + +void SharedRuntime::debug_print_value(jint x) { + tty->print_cr("int %d", x); +} + +void SharedRuntime::debug_print_value(jlong x) { + tty->print_cr("long " JLONG_FORMAT, x); +} + +void SharedRuntime::debug_print_value(jfloat x) { + tty->print_cr("float %f", x); +} + +void SharedRuntime::debug_print_value(jdouble x) { + tty->print_cr("double %lf", x); +} + +void SharedRuntime::debug_print_value(oopDesc* x) { + x->print(); +} +#endif // COMPILER2 + #endif // PRODUCT @@ -525,9 +565,6 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* curr assert(frame::verify_return_pc(return_address), "must be a return address: " INTPTR_FORMAT, p2i(return_address)); assert(current->frames_to_pop_failed_realloc() == 0 || Interpreter::contains(return_address), "missed frames to pop?"); - // Reset method handle flag. - current->set_is_method_handle_return(false); - #if INCLUDE_JVMCI // JVMCI's ExceptionHandlerStub expects the thread local exception PC to be clear // and other exception handler continuations do not read it @@ -542,8 +579,6 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* curr CodeBlob* blob = CodeCache::find_blob(return_address); nmethod* nm = (blob != nullptr) ? blob->as_nmethod_or_null() : nullptr; if (nm != nullptr) { - // Set flag if return address is a method handle call site. - current->set_is_method_handle_return(nm->is_method_handle_return(return_address)); // native nmethods don't have exception handlers assert(!nm->is_native_method() || nm->method()->is_continuation_enter_intrinsic(), "no exception handler"); assert(nm->header_begin() != nm->exception_begin(), "no exception handler"); @@ -1985,7 +2020,6 @@ void SharedRuntime::monitor_exit_helper(oopDesc* obj, BasicLock* lock, JavaThrea if (!m->try_enter(current, /*check_for_recursion*/ false)) { // Some other thread acquired the lock (or the monitor was // deflated). Either way we are done. - current->dec_held_monitor_count(); return; } } @@ -2007,20 +2041,6 @@ JRT_LEAF(void, SharedRuntime::complete_monitor_unlocking_C(oopDesc* obj, BasicLo SharedRuntime::monitor_exit_helper(obj, lock, current); JRT_END -// This is only called when CheckJNICalls is true, and only -// for virtual thread termination. -JRT_LEAF(void, SharedRuntime::log_jni_monitor_still_held()) - assert(CheckJNICalls, "Only call this when checking JNI usage"); - if (log_is_enabled(Debug, jni)) { - JavaThread* current = JavaThread::current(); - int64_t vthread_id = java_lang_Thread::thread_id(current->vthread()); - int64_t carrier_id = java_lang_Thread::thread_id(current->threadObj()); - log_debug(jni)("VirtualThread (tid: " INT64_FORMAT ", carrier id: " INT64_FORMAT - ") exiting with Objects still locked by JNI MonitorEnter.", - vthread_id, carrier_id); - } -JRT_END - #ifndef PRODUCT void SharedRuntime::print_statistics() { @@ -2520,6 +2540,7 @@ ArchivedAdapterTable AdapterHandlerLibrary::_aot_adapter_handler_table; #endif // INCLUDE_CDS static const int AdapterHandlerLibrary_size = 16*K; BufferBlob* AdapterHandlerLibrary::_buffer = nullptr; +volatile uint AdapterHandlerLibrary::_id_counter = 0; BufferBlob* AdapterHandlerLibrary::buffer_blob() { assert(_buffer != nullptr, "should be initialized"); @@ -2600,7 +2621,9 @@ void AdapterHandlerLibrary::initialize() { } AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint) { - return AdapterHandlerEntry::allocate(fingerprint); + uint id = (uint)AtomicAccess::add((int*)&_id_counter, 1); + assert(id > 0, "we can never overflow because AOT cache cannot contain more than 2^32 methods"); + return AdapterHandlerEntry::allocate(id, fingerprint); } AdapterHandlerEntry* AdapterHandlerLibrary::get_simple_adapter(const methodHandle& method) { @@ -2754,8 +2777,8 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& meth void AdapterHandlerLibrary::lookup_aot_cache(AdapterHandlerEntry* handler) { ResourceMark rm; - const char* name = AdapterHandlerLibrary::name(handler->fingerprint()); - const uint32_t id = AdapterHandlerLibrary::id(handler->fingerprint()); + const char* name = AdapterHandlerLibrary::name(handler); + const uint32_t id = AdapterHandlerLibrary::id(handler); CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::Adapter, id, name); if (blob != nullptr) { @@ -2850,8 +2873,8 @@ bool AdapterHandlerLibrary::generate_adapter_code(AdapterHandlerEntry* handler, handler->set_adapter_blob(adapter_blob); if (!is_transient && AOTCodeCache::is_dumping_adapter()) { // try to save generated code - const char* name = AdapterHandlerLibrary::name(handler->fingerprint()); - const uint32_t id = AdapterHandlerLibrary::id(handler->fingerprint()); + const char* name = AdapterHandlerLibrary::name(handler); + const uint32_t id = AdapterHandlerLibrary::id(handler); bool success = AOTCodeCache::store_code_blob(*adapter_blob, AOTCodeEntry::Adapter, id, name); assert(success || !AOTCodeCache::is_dumping_adapter(), "caching of adapter must be disabled"); } @@ -2991,11 +3014,22 @@ void AdapterHandlerEntry::link() { } void AdapterHandlerLibrary::link_aot_adapters() { + uint max_id = 0; assert(AOTCodeCache::is_using_adapter(), "AOT adapters code should be available"); - _aot_adapter_handler_table.iterate([](AdapterHandlerEntry* entry) { + /* It is possible that some adapters generated in assembly phase are not stored in the cache. + * That implies adapter ids of the adapters in the cache may not be contiguous. + * If the size of the _aot_adapter_handler_table is used to initialize _id_counter, then it may + * result in collision of adapter ids between AOT stored handlers and runtime generated handlers. + * To avoid such situation, initialize the _id_counter with the largest adapter id among the AOT stored handlers. + */ + _aot_adapter_handler_table.iterate([&](AdapterHandlerEntry* entry) { assert(!entry->is_linked(), "AdapterHandlerEntry is already linked!"); entry->link(); + max_id = MAX2(max_id, entry->id()); }); + // Set adapter id to the maximum id found in the AOTCache + assert(_id_counter == 0, "Did not expect new AdapterHandlerEntry to be created at this stage"); + _id_counter = max_id; } // This method is called during production run to lookup simple adapters @@ -3360,13 +3394,12 @@ bool AdapterHandlerLibrary::contains(const CodeBlob* b) { return found; } -const char* AdapterHandlerLibrary::name(AdapterFingerPrint* fingerprint) { - return fingerprint->as_basic_args_string(); +const char* AdapterHandlerLibrary::name(AdapterHandlerEntry* handler) { + return handler->fingerprint()->as_basic_args_string(); } -uint32_t AdapterHandlerLibrary::id(AdapterFingerPrint* fingerprint) { - unsigned int hash = fingerprint->compute_hash(); - return hash; +uint32_t AdapterHandlerLibrary::id(AdapterHandlerEntry* handler) { + return handler->id(); } void AdapterHandlerLibrary::print_handler_on(outputStream* st, const CodeBlob* b) { diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 374985ad921..93cd92b3a32 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -32,6 +32,7 @@ #include "memory/allStatic.hpp" #include "memory/metaspaceClosure.hpp" #include "memory/resourceArea.hpp" +#include "runtime/safepointVerifiers.hpp" #include "runtime/stubInfo.hpp" #include "utilities/macros.hpp" @@ -404,9 +405,6 @@ class SharedRuntime: AllStatic { static void monitor_exit_helper(oopDesc* obj, BasicLock* lock, JavaThread* current); - // Issue UL warning for unlocked JNI monitor on virtual thread termination - static void log_jni_monitor_still_held(); - private: static Handle find_callee_info(Bytecodes::Code& bc, CallInfo& callinfo, TRAPS); static Handle find_callee_info_helper(vframeStream& vfst, Bytecodes::Code& bc, CallInfo& callinfo, TRAPS); @@ -638,6 +636,39 @@ class SharedRuntime: AllStatic { static void print_call_statistics(uint64_t comp_total); static void print_ic_miss_histogram(); +#ifdef COMPILER2 + // Runtime methods for printf-style debug nodes + static void debug_print_value(jboolean x); + static void debug_print_value(jbyte x); + static void debug_print_value(jshort x); + static void debug_print_value(jchar x); + static void debug_print_value(jint x); + static void debug_print_value(jlong x); + static void debug_print_value(jfloat x); + static void debug_print_value(jdouble x); + static void debug_print_value(oopDesc* x); + + template + static void debug_print_rec(T arg, Rest... args) { + debug_print_value(arg); + debug_print_rec(args...); + } + + static void debug_print_rec() {} + + // template is required here as we need to know the exact signature at compile-time + template + static void debug_print(const char *str, TT... args) { + // these three lines are the manual expansion of JRT_LEAF ... JRT_END, does not work well with templates + DEBUG_ONLY(NoHandleMark __hm;) + os::verify_stack_alignment(); + DEBUG_ONLY(NoSafepointVerifier __nsv;) + + tty->print_cr("%s", str); + debug_print_rec(args...); + } +#endif // COMPILER2 + #endif // PRODUCT static void print_statistics() PRODUCT_RETURN; @@ -686,6 +717,7 @@ class AdapterHandlerEntry : public MetaspaceObj { private: AdapterFingerPrint* _fingerprint; AdapterBlob* _adapter_blob; + uint _id; bool _linked; static const char *_entry_names[]; @@ -697,9 +729,10 @@ class AdapterHandlerEntry : public MetaspaceObj { int _saved_code_length; #endif - AdapterHandlerEntry(AdapterFingerPrint* fingerprint) : + AdapterHandlerEntry(int id, AdapterFingerPrint* fingerprint) : _fingerprint(fingerprint), _adapter_blob(nullptr), + _id(id), _linked(false) #ifdef ASSERT , _saved_code(nullptr), @@ -720,8 +753,8 @@ class AdapterHandlerEntry : public MetaspaceObj { } public: - static AdapterHandlerEntry* allocate(AdapterFingerPrint* fingerprint) { - return new(0) AdapterHandlerEntry(fingerprint); + static AdapterHandlerEntry* allocate(uint id, AdapterFingerPrint* fingerprint) { + return new(0) AdapterHandlerEntry(id, fingerprint); } static void deallocate(AdapterHandlerEntry *handler) { @@ -772,6 +805,7 @@ class AdapterHandlerEntry : public MetaspaceObj { AdapterBlob* adapter_blob() const { return _adapter_blob; } bool is_linked() const { return _linked; } + uint id() const { return _id; } AdapterFingerPrint* fingerprint() const { return _fingerprint; } #ifdef ASSERT @@ -798,6 +832,7 @@ class ArchivedAdapterTable; class AdapterHandlerLibrary: public AllStatic { friend class SharedRuntime; private: + static volatile uint _id_counter; // counter for generating unique adapter ids, range = [1,UINT_MAX] static BufferBlob* _buffer; // the temporary code buffer in CodeCache static AdapterHandlerEntry* _no_arg_handler; static AdapterHandlerEntry* _int_arg_handler; @@ -837,8 +872,8 @@ class AdapterHandlerLibrary: public AllStatic { static void print_handler(const CodeBlob* b) { print_handler_on(tty, b); } static void print_handler_on(outputStream* st, const CodeBlob* b); static bool contains(const CodeBlob* b); - static const char* name(AdapterFingerPrint* fingerprint); - static uint32_t id(AdapterFingerPrint* fingerprint); + static const char* name(AdapterHandlerEntry* handler); + static uint32_t id(AdapterHandlerEntry* handler); #ifndef PRODUCT static void print_statistics(); #endif // PRODUCT diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index ff4e09e741f..e513c57fe06 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -452,7 +452,6 @@ void ObjectSynchronizer::jni_enter(Handle obj, JavaThread* current) { while (true) { BasicLock lock; if (LightweightSynchronizer::inflate_and_enter(obj(), &lock, inflate_cause_jni_enter, current, current) != nullptr) { - current->inc_held_monitor_count(1, true); break; } } @@ -470,7 +469,6 @@ void ObjectSynchronizer::jni_exit(oop obj, TRAPS) { // monitor even if an exception was already pending. if (monitor->check_owner(THREAD)) { monitor->exit(current); - current->dec_held_monitor_count(1, true); } } @@ -1263,8 +1261,7 @@ class ReleaseJavaMonitorsClosure: public MonitorClosure { public: ReleaseJavaMonitorsClosure(JavaThread* thread) : _thread(thread) {} void do_monitor(ObjectMonitor* mid) { - intx rec = mid->complete_exit(_thread); - _thread->dec_held_monitor_count(rec + 1); + mid->complete_exit(_thread); } }; @@ -1290,9 +1287,6 @@ void ObjectSynchronizer::release_monitors_owned_by_thread(JavaThread* current) { ObjectSynchronizer::owned_monitors_iterate(&rjmc, current); assert(!current->has_pending_exception(), "Should not be possible"); current->clear_pending_exception(); - assert(current->held_monitor_count() == 0, "Should not be possible"); - // All monitors (including entered via JNI) have been unlocked above, so we need to clear jni count. - current->clear_jni_monitor_count(); } const char* ObjectSynchronizer::inflate_cause_name(const InflateCause cause) { diff --git a/src/hotspot/share/runtime/synchronizer.inline.hpp b/src/hotspot/share/runtime/synchronizer.inline.hpp index a44fe817276..cdbeb1daf5b 100644 --- a/src/hotspot/share/runtime/synchronizer.inline.hpp +++ b/src/hotspot/share/runtime/synchronizer.inline.hpp @@ -45,7 +45,7 @@ inline ObjectMonitor* ObjectSynchronizer::read_monitor(Thread* current, oop obj, inline void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) { assert(current == Thread::current(), "must be"); - LightweightSynchronizer::enter(obj, lock, current); + LightweightSynchronizer::enter(obj, lock, current); } inline bool ObjectSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread* current) { @@ -61,8 +61,6 @@ inline bool ObjectSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread } inline void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) { - current->dec_held_monitor_count(); - LightweightSynchronizer::exit(object, lock, current); } diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 361743f83e8..32c99320bdf 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -65,7 +65,7 @@ Thread::Thread(MemTag mem_tag) { // stack and get_thread set_stack_base(nullptr); set_stack_size(0); - set_lgrp_id(-1); + _lgrp_id = -1; DEBUG_ONLY(clear_suspendible_thread();) DEBUG_ONLY(clear_indirectly_suspendible_thread();) DEBUG_ONLY(clear_indirectly_safepoint_thread();) diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index fe2b997f94c..f752ce87644 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -537,8 +537,8 @@ class Thread: public ThreadShadow { void register_thread_stack_with_NMT(); void unregister_thread_stack_with_NMT(); - int lgrp_id() const { return _lgrp_id; } - void set_lgrp_id(int value) { _lgrp_id = value; } + int lgrp_id() const { return _lgrp_id; } + void update_lgrp_id() { _lgrp_id = os::numa_get_group_id(); } // Printing void print_on(outputStream* st, bool print_extended_info) const; diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 0172fe4d69b..ffe1a86cda5 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -1,4 +1,3 @@ - /* * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. @@ -447,6 +446,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // Check version if (!is_supported_jni_version(args->version)) return JNI_EVERSION; + // Deferred "static" initialization + NonJavaThread::init(); + // Initialize library-based TLS ThreadLocalStorage::init(); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 86874a967e3..dee0a5d4eb7 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1,4 +1,3 @@ - /* * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -59,11 +58,8 @@ #include "oops/constMethod.hpp" #include "oops/cpCache.hpp" #include "oops/fieldInfo.hpp" -#include "oops/instanceClassLoaderKlass.hpp" #include "oops/instanceKlass.hpp" -#include "oops/instanceMirrorKlass.hpp" #include "oops/instanceOop.hpp" -#include "oops/instanceStackChunkKlass.hpp" #include "oops/klass.hpp" #include "oops/klassVtable.hpp" #include "oops/markWord.hpp" @@ -85,7 +81,6 @@ #include "runtime/deoptimization.hpp" #include "runtime/flags/jvmFlag.hpp" #include "runtime/globals.hpp" -#include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/javaThread.hpp" #include "runtime/jniHandles.hpp" @@ -541,7 +536,6 @@ nonstatic_field(nmethod, _state, volatile signed char) \ nonstatic_field(nmethod, _exception_offset, int) \ nonstatic_field(nmethod, _deopt_handler_offset, int) \ - nonstatic_field(nmethod, _deopt_mh_handler_offset, int) \ nonstatic_field(nmethod, _orig_pc_offset, int) \ nonstatic_field(nmethod, _stub_offset, int) \ nonstatic_field(nmethod, _scopes_pcs_offset, int) \ @@ -613,7 +607,6 @@ volatile_nonstatic_field(JavaThread, _suspend_flags, uint32_t) \ volatile_nonstatic_field(JavaThread, _exception_oop, oop) \ volatile_nonstatic_field(JavaThread, _exception_pc, address) \ - volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \ nonstatic_field(JavaThread, _saved_exception_pc, address) \ volatile_nonstatic_field(JavaThread, _thread_state, JavaThreadState) \ nonstatic_field(JavaThread, _stack_base, address) \ @@ -682,7 +675,6 @@ unchecked_nonstatic_field(ObjectMonitor, _object, sizeof(void *)) /* NOTE: no type */ \ volatile_nonstatic_field(ObjectMonitor, _owner, int64_t) \ volatile_nonstatic_field(ObjectMonitor, _next_om, ObjectMonitor*) \ - volatile_nonstatic_field(BasicLock, _metadata, uintptr_t) \ nonstatic_field(ObjectMonitor, _contentions, int) \ volatile_nonstatic_field(ObjectMonitor, _waiters, int) \ volatile_nonstatic_field(ObjectMonitor, _recursions, intx) \ @@ -1717,7 +1709,6 @@ /**********************/ \ \ declare_constant(PcDesc::PCDESC_reexecute) \ - declare_constant(PcDesc::PCDESC_is_method_handle_invoke) \ declare_constant(PcDesc::PCDESC_return_oop) \ \ /**********************/ \ diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 626434b08a7..bfb4546a8a1 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -2610,7 +2610,7 @@ int HeapDumper::dump(const char* path, outputStream* out, int compression, bool // (DumpWriter buffer, DumperClassCacheTable, GZipCompressor buffers). // For the OOM handling we may already be limited in memory. // Lets ensure we have at least 20MB per thread. - size_t free_memory = 0; + physical_memory_size_type free_memory = 0; // Return value ignored - defaulting to 0 on failure. (void)os::free_memory(free_memory); julong max_threads = free_memory / (20 * M); diff --git a/src/hotspot/share/services/threadIdTable.cpp b/src/hotspot/share/services/threadIdTable.cpp index 24ea28abaf6..1604927a0ac 100644 --- a/src/hotspot/share/services/threadIdTable.cpp +++ b/src/hotspot/share/services/threadIdTable.cpp @@ -1,4 +1,3 @@ - /* * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/src/hotspot/share/services/threadIdTable.hpp b/src/hotspot/share/services/threadIdTable.hpp index 12772aed88c..b295cec2514 100644 --- a/src/hotspot/share/services/threadIdTable.hpp +++ b/src/hotspot/share/services/threadIdTable.hpp @@ -1,4 +1,3 @@ - /* * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp index 04d39bf9cf2..547ca4e51d5 100644 --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -1161,9 +1161,11 @@ class GetThreadSnapshotHandshakeClosure: public HandshakeClosure { Type _type; // park blocker or an object the thread waiting on/trying to lock OopHandle _obj; + // thread that owns park blocker object when park blocker is AbstractOwnableSynchronizer + OopHandle _owner; - Blocker(Type type, OopHandle obj): _type(type), _obj(obj) {} - Blocker(): _type(NOTHING), _obj(nullptr) {} + Blocker(Type type, OopHandle obj): _type(type), _obj(obj), _owner() {} + Blocker(): _type(NOTHING), _obj(), _owner() {} bool is_empty() const { return _type == NOTHING; @@ -1198,6 +1200,7 @@ class GetThreadSnapshotHandshakeClosure: public HandshakeClosure { delete _locks; } _blocker._obj.release(oop_storage()); + _blocker._owner.release(oop_storage()); } private: @@ -1300,6 +1303,13 @@ class GetThreadSnapshotHandshakeClosure: public HandshakeClosure { oop park_blocker = java_lang_Thread::park_blocker(_thread_h()); if (park_blocker != nullptr) { _blocker = Blocker(Blocker::PARK_BLOCKER, OopHandle(oop_storage(), park_blocker)); + if (park_blocker->is_a(vmClasses::java_util_concurrent_locks_AbstractOwnableSynchronizer_klass())) { + // could be stale (unlikely in practice), but it's good enough to see deadlocks + oop ownerObj = java_util_concurrent_locks_AbstractOwnableSynchronizer::get_owner_threadObj(park_blocker); + if (ownerObj != nullptr) { + _blocker._owner = OopHandle(oop_storage(), ownerObj); + } + } } ResourceMark rm(current); @@ -1381,6 +1391,7 @@ class jdk_internal_vm_ThreadSnapshot: AllStatic { static int _locks_offset; static int _blockerTypeOrdinal_offset; static int _blockerObject_offset; + static int _parkBlockerOwner_offset; static void compute_offsets(InstanceKlass* klass, TRAPS) { JavaClasses::compute_offset(_name_offset, klass, "name", vmSymbols::string_signature(), false); @@ -1390,6 +1401,7 @@ class jdk_internal_vm_ThreadSnapshot: AllStatic { JavaClasses::compute_offset(_locks_offset, klass, "locks", vmSymbols::jdk_internal_vm_ThreadLock_array(), false); JavaClasses::compute_offset(_blockerTypeOrdinal_offset, klass, "blockerTypeOrdinal", vmSymbols::int_signature(), false); JavaClasses::compute_offset(_blockerObject_offset, klass, "blockerObject", vmSymbols::object_signature(), false); + JavaClasses::compute_offset(_parkBlockerOwner_offset, klass, "parkBlockerOwner", vmSymbols::thread_signature(), false); } public: static void init(InstanceKlass* klass, TRAPS) { @@ -1420,9 +1432,10 @@ class jdk_internal_vm_ThreadSnapshot: AllStatic { static void set_locks(oop snapshot, oop locks) { snapshot->obj_field_put(_locks_offset, locks); } - static void set_blocker(oop snapshot, int type_ordinal, oop lock) { + static void set_blocker(oop snapshot, int type_ordinal, oop lock, oop owner) { snapshot->int_field_put(_blockerTypeOrdinal_offset, type_ordinal); snapshot->obj_field_put(_blockerObject_offset, lock); + snapshot->obj_field_put(_parkBlockerOwner_offset, owner); } }; @@ -1434,6 +1447,7 @@ int jdk_internal_vm_ThreadSnapshot::_stackTrace_offset; int jdk_internal_vm_ThreadSnapshot::_locks_offset; int jdk_internal_vm_ThreadSnapshot::_blockerTypeOrdinal_offset; int jdk_internal_vm_ThreadSnapshot::_blockerObject_offset; +int jdk_internal_vm_ThreadSnapshot::_parkBlockerOwner_offset; oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) { ThreadsListHandle tlh(THREAD); @@ -1559,7 +1573,8 @@ oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) { jdk_internal_vm_ThreadSnapshot::set_stack_trace(snapshot(), trace()); jdk_internal_vm_ThreadSnapshot::set_locks(snapshot(), locks()); if (!cl._blocker.is_empty()) { - jdk_internal_vm_ThreadSnapshot::set_blocker(snapshot(), cl._blocker._type, cl._blocker._obj.resolve()); + jdk_internal_vm_ThreadSnapshot::set_blocker(snapshot(), + cl._blocker._type, cl._blocker._obj.resolve(), cl._blocker._owner.resolve()); } return snapshot(); } diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index ea684368888..0d6e3bb2d76 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -135,6 +135,7 @@ class oopDesc; #define UINT64_FORMAT_X_0 "0x%016" PRIx64 #define UINT64_FORMAT_W(width) "%" #width PRIu64 #define UINT64_FORMAT_0 "%016" PRIx64 +#define PHYS_MEM_TYPE_FORMAT "%" PRIu64 // Format jlong, if necessary #ifndef JLONG_FORMAT @@ -417,6 +418,11 @@ const uintx max_uintx = (uintx)-1; typedef unsigned int uint; NEEDS_CLEANUP +// This typedef is to address the issue of running a 32-bit VM. In this case the amount +// of physical memory may not fit in size_t, so we have to have a larger type. Once 32-bit +// is deprecated, one can use size_t. +typedef uint64_t physical_memory_size_type; + //---------------------------------------------------------------------------------------------------- // Java type definitions diff --git a/src/hotspot/share/utilities/growableArray.hpp b/src/hotspot/share/utilities/growableArray.hpp index 53403ca5cf1..1fef271c8c0 100644 --- a/src/hotspot/share/utilities/growableArray.hpp +++ b/src/hotspot/share/utilities/growableArray.hpp @@ -317,8 +317,6 @@ class GrowableArrayFromArray : public GrowableArrayView { // - void Derived::deallocate(E*) - member function responsible for deallocation template class GrowableArrayWithAllocator : public GrowableArrayView { - friend class VMStructs; - void expand_to(int j); void grow(int j); @@ -714,6 +712,7 @@ class GrowableArrayMetadata { template class GrowableArray : public GrowableArrayWithAllocator> { + friend class VMStructs; friend class GrowableArrayWithAllocator; friend class GrowableArrayTest; diff --git a/src/hotspot/share/utilities/stringUtils.cpp b/src/hotspot/share/utilities/stringUtils.cpp index cd4c2d6c33b..0872ce43d4b 100644 --- a/src/hotspot/share/utilities/stringUtils.cpp +++ b/src/hotspot/share/utilities/stringUtils.cpp @@ -24,6 +24,7 @@ #include "jvm_io.h" #include "memory/allocation.hpp" +#include "runtime/os.hpp" #include "utilities/debug.hpp" #include "utilities/stringUtils.hpp" diff --git a/src/hotspot/share/utilities/stringUtils.hpp b/src/hotspot/share/utilities/stringUtils.hpp index f30c9c3ea78..c3d21233808 100644 --- a/src/hotspot/share/utilities/stringUtils.hpp +++ b/src/hotspot/share/utilities/stringUtils.hpp @@ -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 diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 5341249e085..fd3fe3ac2c0 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -84,12 +84,11 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; +import sun.invoke.util.BytecodeDescriptor; import sun.invoke.util.Wrapper; import sun.reflect.generics.factory.CoreReflectionFactory; import sun.reflect.generics.factory.GenericsFactory; import sun.reflect.generics.repository.ClassRepository; -import sun.reflect.generics.repository.MethodRepository; -import sun.reflect.generics.repository.ConstructorRepository; import sun.reflect.generics.scope.ClassScope; import sun.reflect.annotation.*; @@ -1447,17 +1446,10 @@ public Method getEnclosingMethod() { if (!enclosingInfo.isMethod()) return null; - MethodRepository typeInfo = MethodRepository.make(enclosingInfo.getDescriptor(), - getFactory()); - Class returnType = toClass(typeInfo.getReturnType()); - Type [] parameterTypes = typeInfo.getParameterTypes(); - Class[] parameterClasses = new Class[parameterTypes.length]; - - // Convert Types to Classes; returned types *should* - // be class objects since the methodDescriptor's used - // don't have generics information - for(int i = 0; i < parameterClasses.length; i++) - parameterClasses[i] = toClass(parameterTypes[i]); + // Descriptor already validated by VM + List> types = BytecodeDescriptor.parseMethod(enclosingInfo.getDescriptor(), getClassLoader()); + Class returnType = types.removeLast(); + Class[] parameterClasses = types.toArray(EMPTY_CLASS_ARRAY); final Class enclosingCandidate = enclosingInfo.getEnclosingClass(); Method[] candidates = enclosingCandidate.privateGetDeclaredMethods(false); @@ -1576,17 +1568,10 @@ public Constructor getEnclosingConstructor() { if (!enclosingInfo.isConstructor()) return null; - ConstructorRepository typeInfo = ConstructorRepository.make(enclosingInfo.getDescriptor(), - getFactory()); - Type [] parameterTypes = typeInfo.getParameterTypes(); - Class[] parameterClasses = new Class[parameterTypes.length]; - - // Convert Types to Classes; returned types *should* - // be class objects since the methodDescriptor's used - // don't have generics information - for (int i = 0; i < parameterClasses.length; i++) - parameterClasses[i] = toClass(parameterTypes[i]); - + // Descriptor already validated by VM + List> types = BytecodeDescriptor.parseMethod(enclosingInfo.getDescriptor(), getClassLoader()); + types.removeLast(); + Class[] parameterClasses = types.toArray(EMPTY_CLASS_ARRAY); final Class enclosingCandidate = enclosingInfo.getEnclosingClass(); Constructor[] candidates = enclosingCandidate @@ -1892,7 +1877,7 @@ public Class[] getClasses() { } currentClass = currentClass.getSuperclass(); } - return list.toArray(new Class[0]); + return list.toArray(EMPTY_CLASS_ARRAY); } diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index da3acbe5f0a..61c62d049bc 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -41,61 +41,49 @@ import static java.lang.String.checkOffset; final class StringLatin1 { - public static char charAt(byte[] value, int index) { + static char charAt(byte[] value, int index) { checkIndex(index, value.length); return (char)(value[index] & 0xff); } - public static boolean canEncode(char cp) { + static boolean canEncode(char cp) { return cp <= 0xff; } - public static boolean canEncode(int cp) { + static boolean canEncode(int cp) { return cp >=0 && cp <= 0xff; } - public static byte coderFromChar(char cp) { + static byte coderFromChar(char cp) { return (byte)((0xff - cp) >>> (Integer.SIZE - 1)); } - public static int length(byte[] value) { + static int length(byte[] value) { return value.length; } - public static int codePointAt(byte[] value, int index, int end) { - return value[index] & 0xff; - } - - public static int codePointBefore(byte[] value, int index) { - return value[index - 1] & 0xff; - } - - public static int codePointCount(byte[] value, int beginIndex, int endIndex) { - return endIndex - beginIndex; - } - - public static char[] toChars(byte[] value) { + static char[] toChars(byte[] value) { char[] dst = new char[value.length]; inflate(value, 0, dst, 0, value.length); return dst; } - public static byte[] inflate(byte[] value, int off, int len) { + static byte[] inflate(byte[] value, int off, int len) { byte[] ret = StringUTF16.newBytesFor(len); inflate(value, off, ret, 0, len); return ret; } - public static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, int dstBegin) { + static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, int dstBegin) { inflate(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); } - public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte[] dst, int dstBegin) { + static void getBytes(byte[] value, int srcBegin, int srcEnd, byte[] dst, int dstBegin) { System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); } @IntrinsicCandidate - public static boolean equals(byte[] value, byte[] other) { + static boolean equals(byte[] value, byte[] other) { if (value.length == other.length) { for (int i = 0; i < value.length; i++) { if (value[i] != other[i]) { @@ -108,20 +96,20 @@ public static boolean equals(byte[] value, byte[] other) { } @IntrinsicCandidate - public static int compareTo(byte[] value, byte[] other) { + static int compareTo(byte[] value, byte[] other) { int len1 = value.length; int len2 = other.length; return compareTo(value, other, len1, len2); } - public static int compareTo(byte[] value, byte[] other, int len1, int len2) { + static int compareTo(byte[] value, byte[] other, int len1, int len2) { int lim = Math.min(len1, len2); int k = ArraysSupport.mismatch(value, other, lim); return (k < 0) ? len1 - len2 : getChar(value, k) - getChar(other, k); } @IntrinsicCandidate - public static int compareToUTF16(byte[] value, byte[] other) { + static int compareToUTF16(byte[] value, byte[] other) { int len1 = length(value); int len2 = StringUTF16.length(other); return compareToUTF16Values(value, other, len1, len2); @@ -130,7 +118,7 @@ public static int compareToUTF16(byte[] value, byte[] other) { /* * Checks the boundary and then compares the byte arrays. */ - public static int compareToUTF16(byte[] value, byte[] other, int len1, int len2) { + static int compareToUTF16(byte[] value, byte[] other, int len1, int len2) { checkOffset(len1, length(value)); checkOffset(len2, StringUTF16.length(other)); @@ -149,7 +137,7 @@ private static int compareToUTF16Values(byte[] value, byte[] other, int len1, in return len1 - len2; } - public static int compareToCI(byte[] value, byte[] other) { + static int compareToCI(byte[] value, byte[] other) { int len1 = value.length; int len2 = other.length; int lim = Math.min(len1, len2); @@ -169,7 +157,7 @@ public static int compareToCI(byte[] value, byte[] other) { return len1 - len2; } - public static int compareToCI_UTF16(byte[] value, byte[] other) { + static int compareToCI_UTF16(byte[] value, byte[] other) { int len1 = length(value); int len2 = StringUTF16.length(other); int lim = Math.min(len1, len2); @@ -191,12 +179,12 @@ public static int compareToCI_UTF16(byte[] value, byte[] other) { return len1 - len2; } - public static int hashCode(byte[] value) { + static int hashCode(byte[] value) { return ArraysSupport.hashCodeOfUnsigned(value, 0, value.length, 0); } // Caller must ensure that from- and toIndex are within bounds - public static int indexOf(byte[] value, int ch, int fromIndex, int toIndex) { + static int indexOf(byte[] value, int ch, int fromIndex, int toIndex) { if (!canEncode(ch)) { return -1; } @@ -215,7 +203,7 @@ private static int indexOfChar(byte[] value, int ch, int fromIndex, int max) { } @IntrinsicCandidate - public static int indexOf(byte[] value, byte[] str) { + static int indexOf(byte[] value, byte[] str) { if (str.length == 0) { return 0; } @@ -226,7 +214,7 @@ public static int indexOf(byte[] value, byte[] str) { } @IntrinsicCandidate - public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { + static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { byte first = str[0]; int max = (valueCount - strCount); for (int i = fromIndex; i <= max; i++) { @@ -248,8 +236,8 @@ public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount return -1; } - public static int lastIndexOf(byte[] src, int srcCount, - byte[] tgt, int tgtCount, int fromIndex) { + static int lastIndexOf(byte[] src, int srcCount, + byte[] tgt, int tgtCount, int fromIndex) { int min = tgtCount - 1; int i = min + fromIndex; int strLastIndex = tgtCount - 1; @@ -276,7 +264,7 @@ public static int lastIndexOf(byte[] src, int srcCount, } } - public static int lastIndexOf(final byte[] value, int ch, int fromIndex) { + static int lastIndexOf(final byte[] value, int ch, int fromIndex) { if (!canEncode(ch)) { return -1; } @@ -289,7 +277,7 @@ public static int lastIndexOf(final byte[] value, int ch, int fromIndex) { return -1; } - public static String replace(byte[] value, char oldChar, char newChar) { + static String replace(byte[] value, char oldChar, char newChar) { if (canEncode(oldChar)) { int len = value.length; int i = -1; @@ -326,8 +314,8 @@ public static String replace(byte[] value, char oldChar, char newChar) { return null; // for string to return this; } - public static String replace(byte[] value, int valLen, byte[] targ, - int targLen, byte[] repl, int replLen) + static String replace(byte[] value, int valLen, byte[] targ, + int targLen, byte[] repl, int replLen) { assert targLen > 0; int i, j, p = 0; @@ -377,8 +365,8 @@ public static String replace(byte[] value, int valLen, byte[] targ, } // case insensitive - public static boolean regionMatchesCI(byte[] value, int toffset, - byte[] other, int ooffset, int len) { + static boolean regionMatchesCI(byte[] value, int toffset, + byte[] other, int ooffset, int len) { int last = toffset + len; while (toffset < last) { byte b1 = value[toffset++]; @@ -391,8 +379,8 @@ public static boolean regionMatchesCI(byte[] value, int toffset, return true; } - public static boolean regionMatchesCI_UTF16(byte[] value, int toffset, - byte[] other, int ooffset, int len) { + static boolean regionMatchesCI_UTF16(byte[] value, int toffset, + byte[] other, int ooffset, int len) { int last = toffset + len; while (toffset < last) { char c1 = (char)(value[toffset++] & 0xff); @@ -413,7 +401,7 @@ public static boolean regionMatchesCI_UTF16(byte[] value, int toffset, return true; } - public static String toLowerCase(String str, byte[] value, Locale locale) { + static String toLowerCase(String str, byte[] value, Locale locale) { if (locale == null) { throw new NullPointerException(); } @@ -480,7 +468,7 @@ private static String toLowerCaseEx(String str, byte[] value, return StringUTF16.newString(result, 0, resultOffset); } - public static String toUpperCase(String str, byte[] value, Locale locale) { + static String toUpperCase(String str, byte[] value, Locale locale) { if (locale == null) { throw new NullPointerException(); } @@ -560,7 +548,7 @@ private static String toUpperCaseEx(String str, byte[] value, return StringUTF16.newString(result, 0, resultOffset); } - public static String trim(byte[] value) { + static String trim(byte[] value) { int len = value.length; int st = 0; while ((st < len) && ((value[st] & 0xff) <= ' ')) { @@ -573,7 +561,7 @@ public static String trim(byte[] value) { newString(value, st, len - st) : null; } - public static int indexOfNonWhitespace(byte[] value) { + static int indexOfNonWhitespace(byte[] value) { int length = value.length; int left = 0; while (left < length) { @@ -586,9 +574,8 @@ public static int indexOfNonWhitespace(byte[] value) { return left; } - public static int lastIndexOfNonWhitespace(byte[] value) { - int length = value.length; - int right = length; + static int lastIndexOfNonWhitespace(byte[] value) { + int right = value.length; while (0 < right) { char ch = getChar(value, right - 1); if (ch != ' ' && ch != '\t' && !CharacterDataLatin1.instance.isWhitespace(ch)) { @@ -599,7 +586,7 @@ public static int lastIndexOfNonWhitespace(byte[] value) { return right; } - public static String strip(byte[] value) { + static String strip(byte[] value) { int left = indexOfNonWhitespace(value); if (left == value.length) { return ""; @@ -609,12 +596,12 @@ public static String strip(byte[] value) { return ifChanged ? newString(value, left, right - left) : null; } - public static String stripLeading(byte[] value) { + static String stripLeading(byte[] value) { int left = indexOfNonWhitespace(value); return (left != 0) ? newString(value, left, value.length - left) : null; } - public static String stripTrailing(byte[] value) { + static String stripTrailing(byte[] value) { int right = lastIndexOfNonWhitespace(value); return (right != value.length) ? newString(value, 0, right) : null; } @@ -713,14 +700,14 @@ static Stream lines(byte[] value) { return StreamSupport.stream(LinesSpliterator.spliterator(value), false); } - public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { + static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { value[i] = (byte)c1; value[i + 1] = (byte)c2; value[i + 2] = (byte)c3; value[i + 3] = (byte)c4; } - public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { + static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { value[i] = (byte)c1; value[i + 1] = (byte)c2; value[i + 2] = (byte)c3; @@ -728,32 +715,15 @@ public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, ch value[i + 4] = (byte)c5; } - public static void putChar(byte[] val, int index, int c) { - //assert (canEncode(c)); - val[index] = (byte)(c); - } - - public static char getChar(byte[] val, int index) { + static char getChar(byte[] val, int index) { return (char)(val[index] & 0xff); } - public static byte[] toBytes(int[] val, int off, int len) { - byte[] ret = new byte[len]; - for (int i = 0; i < len; i++) { - int cp = val[off++]; - if (!canEncode(cp)) { - return null; - } - ret[i] = (byte)cp; - } - return ret; - } - - public static byte[] toBytes(char c) { + static byte[] toBytes(char c) { return new byte[] { (byte)c }; } - public static String newString(byte[] val, int index, int len) { + static String newString(byte[] val, int index, int len) { if (len == 0) { return ""; } @@ -763,7 +733,7 @@ public static String newString(byte[] val, int index, int len) { // inflatedCopy byte[] -> char[] @IntrinsicCandidate - public static void inflate(byte[] src, int srcOff, char[] dst, int dstOff, int len) { + static void inflate(byte[] src, int srcOff, char[] dst, int dstOff, int len) { for (int i = 0; i < len; i++) { dst[dstOff++] = (char)(src[srcOff++] & 0xff); } @@ -771,7 +741,7 @@ public static void inflate(byte[] src, int srcOff, char[] dst, int dstOff, int l // inflatedCopy byte[] -> byte[] @IntrinsicCandidate - public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { + static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { StringUTF16.inflate(src, srcOff, dst, dstOff, len); } @@ -824,7 +794,7 @@ public boolean tryAdvance(IntConsumer action) { } @Override - public long estimateSize() { return (long)(fence - index); } + public long estimateSize() { return fence - index; } @Override public int characteristics() { diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 08b4072fc35..4e31c9728e9 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -54,13 +54,13 @@ final class StringUTF16 { // Return a new byte array for a UTF16-coded string for len chars // Throw an exception if out of range - public static byte[] newBytesFor(int len) { + static byte[] newBytesFor(int len) { return new byte[newBytesLength(len)]; } // Check the size of a UTF16-coded string // Throw an exception if out of range - public static int newBytesLength(int len) { + static int newBytesLength(int len) { if (len < 0) { throw new NegativeArraySizeException(); } @@ -89,7 +89,7 @@ static char getChar(byte[] val, int index) { ((val[index] & 0xff) << LO_BYTE_SHIFT)); } - public static int length(byte[] value) { + static int length(byte[] value) { return value.length >> 1; } @@ -111,7 +111,7 @@ private static int codePointAt(byte[] value, int index, int end, boolean checked return c1; } - public static int codePointAt(byte[] value, int index, int end) { + static int codePointAt(byte[] value, int index, int end) { return codePointAt(value, index, end, false /* unchecked */); } @@ -134,7 +134,7 @@ private static int codePointBefore(byte[] value, int index, boolean checked) { return c2; } - public static int codePointBefore(byte[] value, int index) { + static int codePointBefore(byte[] value, int index) { return codePointBefore(value, index, false /* unchecked */); } @@ -155,11 +155,11 @@ private static int codePointCount(byte[] value, int beginIndex, int endIndex, bo return count; } - public static int codePointCount(byte[] value, int beginIndex, int endIndex) { + static int codePointCount(byte[] value, int beginIndex, int endIndex) { return codePointCount(value, beginIndex, endIndex, false /* unchecked */); } - public static char[] toChars(byte[] value) { + static char[] toChars(byte[] value) { char[] dst = new char[value.length >> 1]; getChars(value, 0, dst.length, dst, 0); return dst; @@ -173,7 +173,7 @@ public static char[] toChars(byte[] value) { * @param len a length */ @IntrinsicCandidate - public static byte[] toBytes(char[] value, int off, int len) { + static byte[] toBytes(char[] value, int off, int len) { byte[] val = newBytesFor(len); for (int i = 0; i < len; i++) { putChar(val, i, value[off]); @@ -218,7 +218,7 @@ static byte coderFromArrayLen(byte[] value, int len) { * @param count count of chars to be compressed, {@code count} > 0 */ @ForceInline - public static byte[] compress(final char[] val, final int off, final int count) { + static byte[] compress(final char[] val, final int off, final int count) { byte[] latin1 = new byte[count]; int ndx = compress(val, off, latin1, 0, count); if (ndx != count) { @@ -245,7 +245,7 @@ public static byte[] compress(final char[] val, final int off, final int count) * @param off starting offset * @param count count of chars to be compressed, {@code count} > 0 */ - public static byte[] compress(final byte[] val, final int off, final int count) { + static byte[] compress(final byte[] val, final int off, final int count) { byte[] latin1 = new byte[count]; int ndx = compress(val, off, latin1, 0, count); if (ndx != count) {// Switch to UTF16 @@ -279,7 +279,7 @@ public static byte[] compress(final byte[] val, final int off, final int count) * @param off starting offset * @param count length of code points to be compressed, length > 0 */ - public static byte[] compress(final int[] val, int off, final int count) { + static byte[] compress(final int[] val, int off, final int count) { // Optimistically copy all latin1 code points to the destination byte[] latin1 = new byte[count]; final int end = off + count; @@ -389,7 +389,7 @@ private static int computeCodePointSize(int[] val, int off, int end) { // compressedCopy char[] -> byte[] @IntrinsicCandidate - public static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) { + static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) { for (int i = 0; i < len; i++) { char c = src[srcOff]; if (c > 0xff) { @@ -404,7 +404,7 @@ public static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int l // compressedCopy byte[] -> byte[] @IntrinsicCandidate - public static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { + static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { // We need a range check here because 'getChar' has no checks checkBoundsOffCount(srcOff, len, src); for (int i = 0; i < len; i++) { @@ -420,7 +420,7 @@ public static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int l } // Create the UTF16 buffer for !COMPACT_STRINGS - public static byte[] toBytes(int[] val, int index, int len) { + static byte[] toBytes(int[] val, int index, int len) { final int end = index + len; int n = computeCodePointSize(val, index, end); @@ -428,7 +428,7 @@ public static byte[] toBytes(int[] val, int index, int len) { return extractCodepoints(val, index, end, buf, 0); } - public static byte[] toBytes(char c) { + static byte[] toBytes(char c) { byte[] result = new byte[2]; putChar(result, 0, c); return result; @@ -442,7 +442,7 @@ static byte[] toBytesSupplementary(int cp) { } @IntrinsicCandidate - public static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, int dstBegin) { + static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, int dstBegin) { // We need a range check here because 'getChar' has no checks if (srcBegin < srcEnd) { checkBoundsOffCount(srcBegin, srcEnd - srcBegin, value); @@ -453,7 +453,7 @@ public static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, } /* @see java.lang.String.getBytes(int, int, byte[], int) */ - public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte[] dst, int dstBegin) { + static void getBytes(byte[] value, int srcBegin, int srcEnd, byte[] dst, int dstBegin) { srcBegin <<= 1; srcEnd <<= 1; for (int i = srcBegin + (1 >> LO_BYTE_SHIFT); i < srcEnd; i += 2) { @@ -462,7 +462,7 @@ public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte[] dst, } @IntrinsicCandidate - public static int compareTo(byte[] value, byte[] other) { + static int compareTo(byte[] value, byte[] other) { int len1 = length(value); int len2 = length(other); return compareValues(value, other, len1, len2); @@ -471,7 +471,7 @@ public static int compareTo(byte[] value, byte[] other) { /* * Checks the boundary and then compares the byte arrays. */ - public static int compareTo(byte[] value, byte[] other, int len1, int len2) { + static int compareTo(byte[] value, byte[] other, int len1, int len2) { checkOffset(len1, value); checkOffset(len2, other); @@ -491,15 +491,15 @@ private static int compareValues(byte[] value, byte[] other, int len1, int len2) } @IntrinsicCandidate - public static int compareToLatin1(byte[] value, byte[] other) { + static int compareToLatin1(byte[] value, byte[] other) { return -StringLatin1.compareToUTF16(other, value); } - public static int compareToLatin1(byte[] value, byte[] other, int len1, int len2) { + static int compareToLatin1(byte[] value, byte[] other, int len1, int len2) { return -StringLatin1.compareToUTF16(other, value, len2, len1); } - public static int compareToCI(byte[] value, byte[] other) { + static int compareToCI(byte[] value, byte[] other) { return compareToCIImpl(value, 0, length(value), other, 0, length(other)); } @@ -512,8 +512,8 @@ private static int compareToCIImpl(byte[] value, int toffset, int tlen, assert olast <= length(other); for (int k1 = toffset, k2 = ooffset; k1 < tlast && k2 < olast; k1++, k2++) { - int cp1 = (int)getChar(value, k1); - int cp2 = (int)getChar(other, k2); + int cp1 = getChar(value, k1); + int cp2 = getChar(other, k2); if (cp1 == cp2 || compareCodePointCI(cp1, cp2) == 0) { continue; @@ -588,16 +588,16 @@ private static int codePointIncluding(byte[] ba, int cp, int index, int start, i return cp; } - public static int compareToCI_Latin1(byte[] value, byte[] other) { + static int compareToCI_Latin1(byte[] value, byte[] other) { return -StringLatin1.compareToCI_UTF16(other, value); } - public static int hashCode(byte[] value) { + static int hashCode(byte[] value) { return ArraysSupport.hashCodeOfUTF16(value, 0, value.length >> 1, 0); } // Caller must ensure that from- and toIndex are within bounds - public static int indexOf(byte[] value, int ch, int fromIndex, int toIndex) { + static int indexOf(byte[] value, int ch, int fromIndex, int toIndex) { if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { // handle most cases here (ch is a BMP code point or a // negative value (invalid code point)) @@ -608,7 +608,7 @@ public static int indexOf(byte[] value, int ch, int fromIndex, int toIndex) { } @IntrinsicCandidate - public static int indexOf(byte[] value, byte[] str) { + static int indexOf(byte[] value, byte[] str) { if (str.length == 0) { return 0; } @@ -619,7 +619,7 @@ public static int indexOf(byte[] value, byte[] str) { } @IntrinsicCandidate - public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { + static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) { checkBoundsBeginEnd(fromIndex, valueCount, value); checkBoundsBeginEnd(0, strCount, str); return indexOfUnsafe(value, valueCount, str, strCount, fromIndex); @@ -657,7 +657,7 @@ private static int indexOfUnsafe(byte[] value, int valueCount, byte[] str, int s * Handles indexOf Latin1 substring in UTF16 string. */ @IntrinsicCandidate - public static int indexOfLatin1(byte[] value, byte[] str) { + static int indexOfLatin1(byte[] value, byte[] str) { if (str.length == 0) { return 0; } @@ -668,13 +668,13 @@ public static int indexOfLatin1(byte[] value, byte[] str) { } @IntrinsicCandidate - public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { + static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { checkBoundsBeginEnd(fromIndex, srcCount, src); String.checkBoundsBeginEnd(0, tgtCount, tgt.length); return indexOfLatin1Unsafe(src, srcCount, tgt, tgtCount, fromIndex); } - public static int indexOfLatin1Unsafe(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { + static int indexOfLatin1Unsafe(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { assert fromIndex >= 0; assert tgtCount > 0; assert tgtCount <= tgt.length; @@ -730,8 +730,8 @@ private static int indexOfSupplementary(byte[] value, int ch, int fromIndex, int } // srcCoder == UTF16 && tgtCoder == UTF16 - public static int lastIndexOf(byte[] src, int srcCount, - byte[] tgt, int tgtCount, int fromIndex) { + static int lastIndexOf(byte[] src, int srcCount, + byte[] tgt, int tgtCount, int fromIndex) { assert fromIndex >= 0; assert tgtCount > 0; assert tgtCount <= length(tgt); @@ -765,7 +765,7 @@ public static int lastIndexOf(byte[] src, int srcCount, } } - public static int lastIndexOf(byte[] value, int ch, int fromIndex) { + static int lastIndexOf(byte[] value, int ch, int fromIndex) { if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { // handle most cases here (ch is a BMP code point or a // negative value (invalid code point)) @@ -798,7 +798,7 @@ private static int lastIndexOfSupplementary(final byte[] value, int ch, int from return -1; } - public static String replace(byte[] value, char oldChar, char newChar) { + static String replace(byte[] value, char oldChar, char newChar) { int len = value.length >> 1; int i = -1; while (++i < len) { @@ -829,9 +829,9 @@ public static String replace(byte[] value, char oldChar, char newChar) { return null; } - public static String replace(byte[] value, int valLen, boolean valLat1, - byte[] targ, int targLen, boolean targLat1, - byte[] repl, int replLen, boolean replLat1) + static String replace(byte[] value, int valLen, boolean valLat1, + byte[] targ, int targLen, boolean targLat1, + byte[] repl, int replLen, boolean replLat1) { assert targLen > 0; assert !valLat1 || !targLat1 || !replLat1; @@ -944,18 +944,18 @@ public static String replace(byte[] value, int valLen, boolean valLat1, return new String(result, UTF16); } - public static boolean regionMatchesCI(byte[] value, int toffset, - byte[] other, int ooffset, int len) { + static boolean regionMatchesCI(byte[] value, int toffset, + byte[] other, int ooffset, int len) { return compareToCIImpl(value, toffset, len, other, ooffset, len) == 0; } - public static boolean regionMatchesCI_Latin1(byte[] value, int toffset, - byte[] other, int ooffset, - int len) { + static boolean regionMatchesCI_Latin1(byte[] value, int toffset, + byte[] other, int ooffset, + int len) { return StringLatin1.regionMatchesCI_UTF16(other, ooffset, value, toffset, len); } - public static String toLowerCase(String str, byte[] value, Locale locale) { + static String toLowerCase(String str, byte[] value, Locale locale) { if (locale == null) { throw new NullPointerException(); } @@ -965,7 +965,7 @@ public static String toLowerCase(String str, byte[] value, Locale locale) { // Now check if there are any characters that need to be changed, or are surrogate for (first = 0 ; first < len; first++) { - int cp = (int)getChar(value, first); + int cp = getChar(value, first); if (Character.isSurrogate((char)cp)) { hasSurr = true; break; @@ -988,7 +988,7 @@ public static String toLowerCase(String str, byte[] value, Locale locale) { } int bits = 0; for (int i = first; i < len; i++) { - int cp = (int)getChar(value, i); + int cp = getChar(value, i); if (cp == '\u03A3' || // GREEK CAPITAL LETTER SIGMA Character.isSurrogate((char)cp)) { return toLowerCaseEx(str, value, result, i, locale, false); @@ -1003,7 +1003,7 @@ public static String toLowerCase(String str, byte[] value, Locale locale) { bits |= cp; putChar(result, i, cp); } - if (bits < 0 || bits > 0xff) { + if (bits > 0xff) { return new String(result, UTF16); } else { return newString(result, 0, len); @@ -1059,7 +1059,7 @@ private static String toLowerCaseEx(String str, byte[] value, return newString(result, 0, resultOffset); } - public static String toUpperCase(String str, byte[] value, Locale locale) { + static String toUpperCase(String str, byte[] value, Locale locale) { if (locale == null) { throw new NullPointerException(); } @@ -1069,7 +1069,7 @@ public static String toUpperCase(String str, byte[] value, Locale locale) { // Now check if there are any characters that need to be changed, or are surrogate for (first = 0 ; first < len; first++) { - int cp = (int)getChar(value, first); + int cp = getChar(value, first); if (Character.isSurrogate((char)cp)) { hasSurr = true; break; @@ -1093,7 +1093,7 @@ public static String toUpperCase(String str, byte[] value, Locale locale) { } int bits = 0; for (int i = first; i < len; i++) { - int cp = (int)getChar(value, i); + int cp = getChar(value, i); if (Character.isSurrogate((char)cp)) { return toUpperCaseEx(str, value, result, i, locale, false); } @@ -1104,7 +1104,7 @@ public static String toUpperCase(String str, byte[] value, Locale locale) { bits |= cp; putChar(result, i, cp); } - if (bits < 0 || bits > 0xff) { + if (bits > 0xff) { return new String(result, UTF16); } else { return newString(result, 0, len); @@ -1164,7 +1164,7 @@ private static String toUpperCaseEx(String str, byte[] value, return newString(result, 0, resultOffset); } - public static String trim(byte[] value) { + static String trim(byte[] value) { int length = value.length >> 1; int len = length; int st = 0; @@ -1179,7 +1179,7 @@ public static String trim(byte[] value) { null; } - public static int indexOfNonWhitespace(byte[] value) { + static int indexOfNonWhitespace(byte[] value) { int length = value.length >> 1; int left = 0; while (left < length) { @@ -1192,9 +1192,8 @@ public static int indexOfNonWhitespace(byte[] value) { return left; } - public static int lastIndexOfNonWhitespace(byte[] value) { - int length = value.length >>> 1; - int right = length; + static int lastIndexOfNonWhitespace(byte[] value) { + int right = value.length >>> 1; while (0 < right) { int codepoint = codePointBefore(value, right); if (codepoint != ' ' && codepoint != '\t' && !Character.isWhitespace(codepoint)) { @@ -1205,7 +1204,7 @@ public static int lastIndexOfNonWhitespace(byte[] value) { return right; } - public static String strip(byte[] value) { + static String strip(byte[] value) { int length = value.length >>> 1; int left = indexOfNonWhitespace(value); if (left == length) { @@ -1216,13 +1215,13 @@ public static String strip(byte[] value) { return ifChanged ? newString(value, left, right - left) : null; } - public static String stripLeading(byte[] value) { + static String stripLeading(byte[] value) { int length = value.length >>> 1; int left = indexOfNonWhitespace(value); return (left != 0) ? newString(value, left, length - left) : null; } - public static String stripTrailing(byte[] value) { + static String stripTrailing(byte[] value) { int length = value.length >>> 1; int right = lastIndexOfNonWhitespace(value); return (right != length) ? newString(value, 0, right) : null; @@ -1322,7 +1321,7 @@ static Stream lines(byte[] value) { return StreamSupport.stream(LinesSpliterator.spliterator(value), false); } - public static String newString(byte[] val, int index, int len) { + static String newString(byte[] val, int index, int len) { if (len == 0) { return ""; } @@ -1388,7 +1387,7 @@ public boolean tryAdvance(IntConsumer action) { } @Override - public long estimateSize() { return (long)(fence - index); } + public long estimateSize() { return fence - index; } @Override public int characteristics() { @@ -1473,7 +1472,7 @@ private static int advance(byte[] a, int i, int hi, IntConsumer action) { } @Override - public long estimateSize() { return (long)(fence - index); } + public long estimateSize() { return fence - index; } @Override public int characteristics() { @@ -1483,12 +1482,12 @@ public int characteristics() { //////////////////////////////////////////////////////////////// - public static void putCharSB(byte[] val, int index, int c) { + static void putCharSB(byte[] val, int index, int c) { checkIndex(index, val); putChar(val, index, c); } - public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) { + static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) { checkBoundsBeginEnd(index, index + end - off, val); String.checkBoundsBeginEnd(off, end, ca.length); Unsafe.getUnsafe().copyMemory( @@ -1499,26 +1498,26 @@ public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end (long) (end - off) << 1); } - public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) { + static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) { checkBoundsBeginEnd(index, index + end - off, val); for (int i = off; i < end; i++) { putChar(val, index++, s.charAt(i)); } } - public static int codePointAtSB(byte[] val, int index, int end) { + static int codePointAtSB(byte[] val, int index, int end) { return codePointAt(val, index, end, true /* checked */); } - public static int codePointBeforeSB(byte[] val, int index) { + static int codePointBeforeSB(byte[] val, int index) { return codePointBefore(val, index, true /* checked */); } - public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) { + static int codePointCountSB(byte[] val, int beginIndex, int endIndex) { return codePointCount(val, beginIndex, endIndex, true /* checked */); } - public static boolean contentEquals(byte[] v1, byte[] v2, int len) { + static boolean contentEquals(byte[] v1, byte[] v2, int len) { checkBoundsOffCount(0, len, v2); for (int i = 0; i < len; i++) { if ((char)(v1[i] & 0xff) != getChar(v2, i)) { @@ -1528,7 +1527,7 @@ public static boolean contentEquals(byte[] v1, byte[] v2, int len) { return true; } - public static boolean contentEquals(byte[] value, CharSequence cs, int len) { + static boolean contentEquals(byte[] value, CharSequence cs, int len) { checkOffset(len, value); for (int i = 0; i < len; i++) { if (getChar(value, i) != cs.charAt(i)) { @@ -1538,7 +1537,7 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { return true; } - public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { + static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { int end = i + 4; checkBoundsBeginEnd(i, end, value); putChar(value, i, c1); @@ -1547,7 +1546,7 @@ public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, ch putChar(value, i + 3, c4); } - public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { + static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { int end = i + 5; checkBoundsBeginEnd(i, end, value); putChar(value, i, c1); @@ -1557,12 +1556,12 @@ public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, ch putChar(value, i + 4, c5); } - public static char charAt(byte[] value, int index) { + static char charAt(byte[] value, int index) { checkIndex(index, value); return getChar(value, index); } - public static void reverse(byte[] val, int count) { + static void reverse(byte[] val, int count) { checkOffset(count, val); int n = count - 1; boolean hasSurrogates = false; @@ -1597,7 +1596,7 @@ private static void reverseAllValidSurrogatePairs(byte[] val, int count) { } // inflatedCopy byte[] -> byte[] - public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { + static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) { // We need a range check here because 'putChar' has no checks checkBoundsOffCount(dstOff, len, dst); for (int i = 0; i < len; i++) { @@ -1606,7 +1605,7 @@ public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int l } // srcCoder == UTF16 && tgtCoder == LATIN1 - public static int lastIndexOfLatin1(byte[] src, int srcCount, + static int lastIndexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) { assert fromIndex >= 0; assert tgtCount > 0; @@ -1659,19 +1658,19 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount, static final int MAX_LENGTH = Integer.MAX_VALUE >> 1; - public static void checkIndex(int off, byte[] val) { + static void checkIndex(int off, byte[] val) { String.checkIndex(off, length(val)); } - public static void checkOffset(int off, byte[] val) { + static void checkOffset(int off, byte[] val) { String.checkOffset(off, length(val)); } - public static void checkBoundsBeginEnd(int begin, int end, byte[] val) { + static void checkBoundsBeginEnd(int begin, int end, byte[] val) { String.checkBoundsBeginEnd(begin, end, length(val)); } - public static void checkBoundsOffCount(int offset, int count, byte[] val) { + static void checkBoundsOffCount(int offset, int count, byte[] val) { String.checkBoundsOffCount(offset, count, length(val)); } diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index f4d82595842..99716baf439 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -165,22 +165,22 @@ private static class StaticHolders { * @param lookup Represents a lookup context with the accessibility * privileges of the caller. When used with {@code invokedynamic}, * this is stacked automatically by the VM. - * @param invocationName unused + * @param invocationName unused, {@code null} is permitted * @param invocationType The invocation type of the {@code CallSite} with two parameters, * a reference type, an {@code int}, and {@code int} as a return type. * @param labels case labels - {@code String} and {@code Integer} constants * and {@code Class} and {@code EnumDesc} instances, in any combination * @return a {@code CallSite} returning the first matching element as described above * - * @throws NullPointerException if any argument is {@code null} + * @throws NullPointerException if any argument is {@code null}, unless noted otherwise * @throws IllegalArgumentException if any element in the labels array is null * @throws IllegalArgumentException if the invocation type is not a method type of first parameter of a reference type, - * second parameter of type {@code int} and with {@code int} as its return type, + * second parameter of type {@code int} and with {@code int} as its return type * @throws IllegalArgumentException if {@code labels} contains an element that is not of type {@code String}, * {@code Integer}, {@code Long}, {@code Float}, {@code Double}, {@code Boolean}, - * {@code Class} or {@code EnumDesc}. + * {@code Class} or {@code EnumDesc} * @throws IllegalArgumentException if {@code labels} contains an element that is not of type {@code Boolean} - * when {@code target} is a {@code Boolean.class}. + * when {@code target} is a {@code Boolean.class} * @jvms 4.4.6 The CONSTANT_NameAndType_info Structure * @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures */ @@ -255,29 +255,36 @@ private static void verifyLabel(Object label, Class selectorType) { * enum constant's {@link Enum#name()}. * *

- * If no element in the {@code labels} array matches the target, then - * the method of the call site return the length of the {@code labels} array. + * If for a given {@code target} there is no element in the {@code labels} + * fulfilling one of the above conditions, then the method of the call + * site returns the length of the {@code labels} array. *

* The value of the {@code restart} index must be between {@code 0} (inclusive) and * the length of the {@code labels} array (inclusive), - * both or an {@link IndexOutOfBoundsException} is thrown. + * or an {@link IndexOutOfBoundsException} is thrown. + * + * @apiNote It is permissible for the {@code labels} array to contain {@code String} + * values that do not represent any enum constants at runtime. * * @param lookup Represents a lookup context with the accessibility * privileges of the caller. When used with {@code invokedynamic}, * this is stacked automatically by the VM. - * @param invocationName unused + * @param invocationName unused, {@code null} is permitted * @param invocationType The invocation type of the {@code CallSite} with two parameters, * an enum type, an {@code int}, and {@code int} as a return type. * @param labels case labels - {@code String} constants and {@code Class} instances, * in any combination * @return a {@code CallSite} returning the first matching element as described above * - * @throws NullPointerException if any argument is {@code null} - * @throws IllegalArgumentException if any element in the labels array is null, if the - * invocation type is not a method type whose first parameter type is an enum type, - * second parameter of type {@code int} and whose return type is {@code int}, - * or if {@code labels} contains an element that is not of type {@code String} or - * {@code Class} of the target enum type. + * @throws NullPointerException if any argument is {@code null}, unless noted otherwise + * @throws IllegalArgumentException if any element in the labels array is null + * @throws IllegalArgumentException if any element in the labels array is an empty {@code String} + * @throws IllegalArgumentException if the invocation type is not a method type + * whose first parameter type is an enum type, + * second parameter of type {@code int} and + * whose return type is {@code int} + * @throws IllegalArgumentException if {@code labels} contains an element that is not of type {@code String} or + * {@code Class} equal to the target enum type * @jvms 4.4.6 The CONSTANT_NameAndType_info Structure * @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures */ diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index 21f8598266f..6253adffb2b 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -4180,6 +4180,10 @@ public String toString(int radix) { if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) radix = 10; + if (fitsIntoLong()) { + return Long.toString(longValue(), radix); + } + BigInteger abs = this.abs(); // Ensure buffer capacity sufficient to contain string representation @@ -5121,12 +5125,16 @@ private byte[] magSerializedForm() { * @since 1.8 */ public long longValueExact() { - if (mag.length <= 2 && bitLength() < Long.SIZE) + if (fitsIntoLong()) return longValue(); throw new ArithmeticException("BigInteger out of long range"); } + private boolean fitsIntoLong() { + return mag.length <= 2 && bitLength() < Long.SIZE; + } + /** * Converts this {@code BigInteger} to an {@code int}, checking * for lost information. If the value of this {@code BigInteger} diff --git a/src/java.base/share/classes/java/net/URL.java b/src/java.base/share/classes/java/net/URL.java index 1435d851f41..c82236b5b85 100644 --- a/src/java.base/share/classes/java/net/URL.java +++ b/src/java.base/share/classes/java/net/URL.java @@ -41,7 +41,6 @@ import jdk.internal.access.JavaNetURLAccess; import jdk.internal.access.SharedSecrets; -import jdk.internal.misc.ThreadTracker; import jdk.internal.misc.VM; import jdk.internal.vm.annotation.AOTRuntimeSetup; import jdk.internal.vm.annotation.AOTSafeClassInitializer; @@ -1394,24 +1393,13 @@ private static URLStreamHandler lookupViaProperty(String protocol) { return handler; } - private static class ThreadTrackHolder { - static final ThreadTracker TRACKER = new ThreadTracker(); - } - - private static Object tryBeginLookup() { - return ThreadTrackHolder.TRACKER.tryBegin(); - } - - private static void endLookup(Object key) { - ThreadTrackHolder.TRACKER.end(key); - } + private static final ScopedValue IN_LOOKUP = ScopedValue.newInstance(); private static URLStreamHandler lookupViaProviders(final String protocol) { - Object key = tryBeginLookup(); - if (key == null) { + if (IN_LOOKUP.isBound()) { throw new Error("Circular loading of URL stream handler providers detected"); } - try { + return ScopedValue.where(IN_LOOKUP, true).call(() -> { final ClassLoader cl = ClassLoader.getSystemClassLoader(); final ServiceLoader sl = ServiceLoader.load(URLStreamHandlerProvider.class, cl); @@ -1423,9 +1411,7 @@ private static URLStreamHandler lookupViaProviders(final String protocol) { return h; } return null; - } finally { - endLookup(key); - } + }); } /** diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java index 7163b2dd63b..74c1eabe970 100644 --- a/src/java.base/share/classes/java/text/CompactNumberFormat.java +++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java @@ -250,38 +250,43 @@ public final class CompactNumberFormat extends NumberFormat { /** * List of positive prefix patterns of this formatter's - * compact number patterns. + * compact number patterns. This field is a read-only + * constant once initialized. */ private transient List positivePrefixPatterns; /** * List of negative prefix patterns of this formatter's - * compact number patterns. + * compact number patterns. This field is a read-only + * constant once initialized. */ private transient List negativePrefixPatterns; /** * List of positive suffix patterns of this formatter's - * compact number patterns. + * compact number patterns. This field is a read-only + * constant once initialized. */ private transient List positiveSuffixPatterns; /** * List of negative suffix patterns of this formatter's - * compact number patterns. + * compact number patterns. This field is a read-only + * constant once initialized. */ private transient List negativeSuffixPatterns; /** * List of divisors of this formatter's compact number patterns. * Divisor can be either Long or BigInteger (if the divisor value goes - * beyond long boundary) + * beyond long boundary). This field is a read-only constant + * once initialized. */ private transient List divisors; /** * List of place holders that represent minimum integer digits at each index - * for each count. + * for each count. This field is a read-only constant once initialized. */ private transient List placeHolderPatterns; @@ -374,7 +379,7 @@ public final class CompactNumberFormat extends NumberFormat { /** * The map for plural rules that maps LDML defined tags (e.g. "one") to - * its rule. + * its rule. This field is a read-only constant once initialized. */ private transient Map rulesMap; @@ -1515,7 +1520,7 @@ private void applyPattern(String count, String pattern, int index) { } } - private final transient DigitList digitList = new DigitList(); + private transient DigitList digitList = new DigitList(); private static final int STATUS_INFINITE = 0; private static final int STATUS_POSITIVE = 1; private static final int STATUS_LENGTH = 2; @@ -2506,8 +2511,14 @@ public String toString() { @Override public CompactNumberFormat clone() { CompactNumberFormat other = (CompactNumberFormat) super.clone(); + + // Cloning reference fields. Other fields (e.g., "positivePrefixPatterns") + // are not cloned since they are read-only constants after initialization. other.compactPatterns = compactPatterns.clone(); other.symbols = (DecimalFormatSymbols) symbols.clone(); + other.decimalFormat = (DecimalFormat) decimalFormat.clone(); + other.defaultDecimalFormat = (DecimalFormat) defaultDecimalFormat.clone(); + other.digitList = (DigitList) digitList.clone(); return other; } diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index 7ace5e136fe..c803a97ad86 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -2335,9 +2335,10 @@ public Number parse(String text, ParsePosition pos) { // (bug 4162852). if (multiplier != 1 && gotDouble) { longResult = (long)doubleResult; - gotDouble = ((doubleResult != (double)longResult) || - (doubleResult == 0.0 && 1/doubleResult < 0.0)) && - !isParseIntegerOnly(); + gotDouble = ((doubleResult >= Long.MAX_VALUE || doubleResult <= Long.MIN_VALUE) || + (doubleResult != (double)longResult) || + (doubleResult == 0.0 && 1/doubleResult < 0.0)) && + !isParseIntegerOnly(); } // cast inside of ?: because of binary numeric promotion, JLS 15.25 diff --git a/src/java.base/share/classes/java/text/DigitList.java b/src/java.base/share/classes/java/text/DigitList.java index 2895126f93b..ce098bd8800 100644 --- a/src/java.base/share/classes/java/text/DigitList.java +++ b/src/java.base/share/classes/java/text/DigitList.java @@ -46,6 +46,7 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.math.FloatingDecimal; import jdk.internal.util.ArraysSupport; +import jdk.internal.vm.annotation.Stable; /** * Digit List. Private to DecimalFormat. @@ -108,7 +109,6 @@ final class DigitList implements Cloneable { public int count = 0; public byte[] digits = new byte[MAX_COUNT]; - private byte[] data; private RoundingMode roundingMode = RoundingMode.HALF_EVEN; private boolean isNegative = false; @@ -320,15 +320,18 @@ void set(boolean isNegative, double source, int maximumFractionDigits) { * fractional digits to be converted. If false, total digits. */ void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) { + assert Double.isFinite(source); + FloatingDecimal.BinaryToASCIIConverter fdConverter = FloatingDecimal.getBinaryToASCIIConverter(source, COMPAT); boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp(); boolean valueExactAsDecimal = fdConverter.decimalDigitsExact(); - assert !fdConverter.isExceptional(); - byte[] chars = getDataChars(26); - int len = fdConverter.getChars(chars); - set(isNegative, chars, len, + count = fdConverter.getDigits(digits); + + int exp = fdConverter.getDecimalExponent() - count; + + set(isNegative, exp, hasBeenRoundedUp, valueExactAsDecimal, maximumDigits, fixedPoint); } @@ -340,44 +343,18 @@ void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoin * @param valueExactAsDecimal whether or not collected digits provide * an exact decimal representation of the value. */ - private void set(boolean isNegative, byte[] source, int len, + private void set(boolean isNegative, int exp, boolean roundedUp, boolean valueExactAsDecimal, int maximumDigits, boolean fixedPoint) { this.isNegative = isNegative; - decimalAt = -1; - count = 0; - int exponent = 0; - // Number of zeros between decimal point and first non-zero digit after - // decimal point, for numbers < 1. - int leadingZerosAfterDecimal = 0; - boolean nonZeroDigitSeen = false; - - for (int i = 0; i < len; ) { - byte c = source[i++]; - if (c == '.') { - decimalAt = count; - } else if (c == 'e' || c == 'E') { - exponent = parseInt(source, i, len); - break; - } else { - if (!nonZeroDigitSeen) { - nonZeroDigitSeen = (c != '0'); - if (!nonZeroDigitSeen && decimalAt != -1) - ++leadingZerosAfterDecimal; - } - if (nonZeroDigitSeen) { - digits[count++] = c; - } - } - } - if (decimalAt == -1) { - decimalAt = count; - } - if (nonZeroDigitSeen) { - decimalAt += exponent - leadingZerosAfterDecimal; + if (!nonZeroAfterIndex(0)) { + count = 0; + decimalAt = 0; + return; } + decimalAt = count + exp; if (fixedPoint) { // The negative of the exponent represents the number of leading @@ -669,13 +646,13 @@ void set(boolean isNegative, long source, int maximumDigits) { */ @SuppressWarnings("deprecation") void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) { - String s = source.toString(); - extendDigits(s.length()); - + String s = source.unscaledValue().toString(); int len = s.length(); - byte[] chars = getDataChars(len); - s.getBytes(0, len, chars, 0); - set(isNegative, chars, len, + + extendDigits(len); + s.getBytes(0, len, digits, 0); + count = len; + set(isNegative, -source.scale(), false, true, maximumDigits, fixedPoint); } @@ -745,14 +722,7 @@ public int hashCode() { public Object clone() { try { DigitList other = (DigitList) super.clone(); - byte[] newDigits = new byte[digits.length]; - System.arraycopy(digits, 0, newDigits, 0, digits.length); - other.digits = newDigits; - - // Data does not need to be copied because it does - // not carry significant information. It will be recreated on demand. - // Setting it to null is needed to avoid sharing across clones. - other.data = null; + other.digits = digits.clone(); return other; } catch (CloneNotSupportedException e) { @@ -760,29 +730,8 @@ public Object clone() { } } - private static int parseInt(byte[] str, int offset, int strLen) { - byte c; - boolean positive = true; - if ((c = str[offset]) == '-') { - positive = false; - offset++; - } else if (c == '+') { - offset++; - } - - int value = 0; - while (offset < strLen) { - c = str[offset++]; - if (c >= '0' && c <= '9') { - value = value * 10 + (c - '0'); - } else { - break; - } - } - return positive ? value : -value; - } - // The digit part of -9223372036854775808L + @Stable private static final byte[] LONG_MIN_REP = "9223372036854775808".getBytes(StandardCharsets.ISO_8859_1); public String toString() { @@ -798,11 +747,4 @@ private void extendDigits(int len) { digits = new byte[len]; } } - - private byte[] getDataChars(int length) { - if (data == null || data.length < length) { - data = new byte[length]; - } - return data; - } } diff --git a/src/java.base/share/classes/java/time/Duration.java b/src/java.base/share/classes/java/time/Duration.java index 88d49fa9e45..23577a8a634 100644 --- a/src/java.base/share/classes/java/time/Duration.java +++ b/src/java.base/share/classes/java/time/Duration.java @@ -172,7 +172,7 @@ private static class Lazy { * Obtains a {@code Duration} representing a number of standard 24 hour days. *

* The seconds are calculated based on the standard definition of a day, - * where each day is 86400 seconds which implies a 24 hour day. + * where each day is 86,400 seconds which implies a 24 hour day. * The nanosecond in second field is set to zero. * * @param days the number of days, positive or negative @@ -187,7 +187,7 @@ public static Duration ofDays(long days) { * Obtains a {@code Duration} representing a number of standard hours. *

* The seconds are calculated based on the standard definition of an hour, - * where each hour is 3600 seconds. + * where each hour is 3,600 seconds. * The nanosecond in second field is set to zero. * * @param hours the number of hours, positive or negative @@ -375,8 +375,8 @@ public static Duration from(TemporalAmount amount) { *

      *    "PT20.345S" -- parses as "20.345 seconds"
      *    "PT15M"     -- parses as "15 minutes" (where a minute is 60 seconds)
-     *    "PT10H"     -- parses as "10 hours" (where an hour is 3600 seconds)
-     *    "P2D"       -- parses as "2 days" (where a day is 24 hours or 86400 seconds)
+     *    "PT10H"     -- parses as "10 hours" (where an hour is 3,600 seconds)
+     *    "P2D"       -- parses as "2 days" (where a day is 24 hours or 86,400 seconds)
      *    "P2DT3H4M"  -- parses as "2 days, 3 hours and 4 minutes"
      *    "PT-6H3M"    -- parses as "-6 hours and +3 minutes"
      *    "-PT6H3M"    -- parses as "-6 hours and -3 minutes"
@@ -477,7 +477,7 @@ private static Duration create(boolean negate, long daysAsSecs, long hoursAsSecs
      * {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field should be supported.
      * 

* The result of this method can be a negative duration if the end is before the start. - * To guarantee to obtain a positive duration call {@link #abs()} on the result. + * To guarantee a positive duration, call {@link #abs()} on the result. * * @param startInclusive the start instant, inclusive, not null * @param endExclusive the end instant, exclusive, not null @@ -752,7 +752,7 @@ public Duration plus(long amountToAdd, TemporalUnit unit) { /** * Returns a copy of this duration with the specified duration in standard 24 hour days added. *

- * The number of days is multiplied by 86400 to obtain the number of seconds to add. + * The number of days is multiplied by 86,400 to obtain the number of seconds to add. * This is based on the standard definition of a day as 24 hours. *

* This instance is immutable and unaffected by this method call. @@ -893,7 +893,7 @@ public Duration minus(long amountToSubtract, TemporalUnit unit) { /** * Returns a copy of this duration with the specified duration in standard 24 hour days subtracted. *

- * The number of days is multiplied by 86400 to obtain the number of seconds to subtract. + * The number of days is multiplied by 86,400 to obtain the number of seconds to subtract. * This is based on the standard definition of a day as 24 hours. *

* This instance is immutable and unaffected by this method call. @@ -909,7 +909,7 @@ public Duration minusDays(long daysToSubtract) { /** * Returns a copy of this duration with the specified duration in hours subtracted. *

- * The number of hours is multiplied by 3600 to obtain the number of seconds to subtract. + * The number of hours is multiplied by 3,600 to obtain the number of seconds to subtract. *

* This instance is immutable and unaffected by this method call. * @@ -924,7 +924,7 @@ public Duration minusHours(long hoursToSubtract) { /** * Returns a copy of this duration with the specified duration in minutes subtracted. *

- * The number of hours is multiplied by 60 to obtain the number of seconds to subtract. + * The number of minutes is multiplied by 60 to obtain the number of seconds to subtract. *

* This instance is immutable and unaffected by this method call. * @@ -1165,7 +1165,7 @@ public Temporal subtractFrom(Temporal temporal) { * Gets the number of days in this duration. *

* This returns the total number of days in the duration by dividing the - * number of seconds by 86400. + * number of seconds by 86,400. * This is based on the standard definition of a day as 24 hours. *

* This instance is immutable and unaffected by this method call. @@ -1180,7 +1180,7 @@ public long toDays() { * Gets the number of hours in this duration. *

* This returns the total number of hours in the duration by dividing the - * number of seconds by 3600. + * number of seconds by 3,600. *

* This instance is immutable and unaffected by this method call. * @@ -1272,7 +1272,7 @@ public long toNanos() { * Extracts the number of days in the duration. *

* This returns the total number of days in the duration by dividing the - * number of seconds by 86400. + * number of seconds by 86,400. * This is based on the standard definition of a day as 24 hours. *

* This instance is immutable and unaffected by this method call. @@ -1476,10 +1476,10 @@ public int hashCode() { *

* Examples: *

-     *    "20.345 seconds"                 -- "PT20.345S
+     *    "20.345 seconds"                 -- "PT20.345S"
      *    "15 minutes" (15 * 60 seconds)   -- "PT15M"
-     *    "10 hours" (10 * 3600 seconds)   -- "PT10H"
-     *    "2 days" (2 * 86400 seconds)     -- "PT48H"
+     *    "10 hours" (10 * 3,600 seconds)  -- "PT10H"
+     *    "2 days" (2 * 86,400 seconds)    -- "PT48H"
      * 
* Note that multiples of 24 hours are not output as days to avoid confusion * with {@code Period}. diff --git a/src/java.base/share/classes/java/time/Instant.java b/src/java.base/share/classes/java/time/Instant.java index 1c7a41d7f0e..db8db4aaa38 100644 --- a/src/java.base/share/classes/java/time/Instant.java +++ b/src/java.base/share/classes/java/time/Instant.java @@ -114,15 +114,15 @@ *

* The length of the solar day is the standard way that humans measure time. * This has traditionally been subdivided into 24 hours of 60 minutes of 60 seconds, - * forming a 86400 second day. + * forming an 86,400 second day. *

* Modern timekeeping is based on atomic clocks which precisely define an SI second * relative to the transitions of a Caesium atom. The length of an SI second was defined - * to be very close to the 86400th fraction of a day. + * to be very close to the 86,400th fraction of a day. *

* Unfortunately, as the Earth rotates the length of the day varies. * In addition, over time the average length of the day is getting longer as the Earth slows. - * As a result, the length of a solar day in 2012 is slightly longer than 86400 SI seconds. + * As a result, the length of a solar day in 2012 is slightly longer than 86,400 SI seconds. * The actual length of any given day and the amount by which the Earth is slowing * are not predictable and can only be determined by measurement. * The UT1 time-scale captures the accurate length of day, but is only available some @@ -131,7 +131,7 @@ * The UTC time-scale is a standard approach to bundle up all the additional fractions * of a second from UT1 into whole seconds, known as leap-seconds. * A leap-second may be added or removed depending on the Earth's rotational changes. - * As such, UTC permits a day to have 86399 SI seconds or 86401 SI seconds where + * As such, UTC permits a day to have 86,399 SI seconds or 86,401 SI seconds where * necessary in order to keep the day aligned with the Sun. *

* The modern UTC time-scale was introduced in 1972, introducing the concept of whole leap-seconds. @@ -143,7 +143,7 @@ * Given the complexity of accurate timekeeping described above, this Java API defines * its own time-scale, the Java Time-Scale. *

- * The Java Time-Scale divides each calendar day into exactly 86400 + * The Java Time-Scale divides each calendar day into exactly 86,400 * subdivisions, known as seconds. These seconds may differ from the * SI second. It closely matches the de facto international civil time * scale, the definition of which changes from time to time. @@ -171,7 +171,7 @@ * This is identical to UTC on days that do not have a leap second. * On days that do have a leap second, the leap second is spread equally * over the last 1000 seconds of the day, maintaining the appearance of - * exactly 86400 seconds per day. + * exactly 86,400 seconds per day. *

* For the segment prior to 1972-11-03, extending back arbitrarily far, * the consensus international time scale is defined to be UT1, applied diff --git a/src/java.base/share/classes/java/time/Period.java b/src/java.base/share/classes/java/time/Period.java index 5ee80710edb..745714788c3 100644 --- a/src/java.base/share/classes/java/time/Period.java +++ b/src/java.base/share/classes/java/time/Period.java @@ -765,7 +765,7 @@ public Period minusMonths(long monthsToSubtract) { *

* This instance is immutable and unaffected by this method call. * - * @param daysToSubtract the months to subtract, positive or negative + * @param daysToSubtract the days to subtract, positive or negative * @return a {@code Period} based on this period with the specified days subtracted, not null * @throws ArithmeticException if numeric overflow occurs */ diff --git a/src/java.base/share/classes/java/time/ZoneOffset.java b/src/java.base/share/classes/java/time/ZoneOffset.java index d93c6e2d46d..4199d17735c 100644 --- a/src/java.base/share/classes/java/time/ZoneOffset.java +++ b/src/java.base/share/classes/java/time/ZoneOffset.java @@ -417,9 +417,9 @@ private static int totalSeconds(int hours, int minutes, int seconds) { /** * Obtains an instance of {@code ZoneOffset} specifying the total offset in seconds *

- * The offset must be in the range {@code -18:00} to {@code +18:00}, which corresponds to -64800 to +64800. + * The offset must be in the range {@code -18:00} to {@code +18:00}, which corresponds to -64,800 to +64,800. * - * @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800 + * @param totalSeconds the total time-zone offset in seconds, from -64,800 to +64,800 * @return the ZoneOffset, not null * @throws DateTimeException if the offset is not in the required range */ @@ -450,7 +450,7 @@ public static ZoneOffset ofTotalSeconds(int totalSeconds) { /** * Constructor. * - * @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800 + * @param totalSeconds the total time-zone offset in seconds, from -64,800 to +64,800 */ private ZoneOffset(int totalSeconds) { this.totalSeconds = totalSeconds; diff --git a/src/java.base/share/classes/java/time/ZonedDateTime.java b/src/java.base/share/classes/java/time/ZonedDateTime.java index 962469b3225..57dc98d5c68 100644 --- a/src/java.base/share/classes/java/time/ZonedDateTime.java +++ b/src/java.base/share/classes/java/time/ZonedDateTime.java @@ -136,7 +136,7 @@ * For Overlaps, the general strategy is that if the local date-time falls in the * middle of an Overlap, then the previous offset will be retained. If there is no * previous offset, or the previous offset is invalid, then the earlier offset is - * used, typically "summer" time.. Two additional methods, + * used, typically "summer" time. Two additional methods, * {@link #withEarlierOffsetAtOverlap()} and {@link #withLaterOffsetAtOverlap()}, * help manage the case of an overlap. *

@@ -246,7 +246,7 @@ public static ZonedDateTime now(Clock clock) { * Time-zone rules, such as daylight savings, mean that not every local date-time * is valid for the specified zone, thus the local date-time may be adjusted. *

- * The local date time and first combined to form a local date-time. + * The local date and time are first combined to form a local date-time. * The local date-time is then resolved to a single instant on the time-line. * This is achieved by finding a valid offset from UTC/Greenwich for the local * date-time as defined by the {@link ZoneRules rules} of the zone ID. @@ -263,7 +263,7 @@ public static ZonedDateTime now(Clock clock) { * @param date the local date, not null * @param time the local time, not null * @param zone the time-zone, not null - * @return the offset date-time, not null + * @return the zoned date-time, not null */ public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone) { return of(LocalDateTime.of(date, time), zone); @@ -333,7 +333,7 @@ public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone) { * @param second the second-of-minute to represent, from 0 to 59 * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999 * @param zone the time-zone, not null - * @return the offset date-time, not null + * @return the zoned date-time, not null * @throws DateTimeException if the value of any field is out of range, or * if the day-of-month is invalid for the month-year */ diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 7a2142e5113..9f5b82775b9 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -1937,7 +1937,7 @@ private void parsePattern(String pattern) { padNext(pad); // pad and continue parsing } // main rules - TemporalField field = FIELD_MAP.get(cur); + TemporalField field = getField(cur); if (field != null) { parseField(cur, count, field); } else if (cur == 'z') { @@ -2185,48 +2185,55 @@ private void parseField(char cur, int count, TemporalField field) { } } - /** Map of letters to fields. */ - private static final Map FIELD_MAP = new HashMap<>(); - static { + /** + * Returns the TemporalField for the given pattern character. + * + * @param ch the pattern character + * @return the TemporalField for the given pattern character, or null if not applicable + */ + private static TemporalField getField(char ch) { // SDF = SimpleDateFormat - FIELD_MAP.put('G', ChronoField.ERA); // SDF, LDML (different to both for 1/2 chars) - FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA); // SDF, LDML - FIELD_MAP.put('u', ChronoField.YEAR); // LDML (different in SDF) - FIELD_MAP.put('Q', IsoFields.QUARTER_OF_YEAR); // LDML (removed quarter from 310) - FIELD_MAP.put('q', IsoFields.QUARTER_OF_YEAR); // LDML (stand-alone) - FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR); // SDF, LDML - FIELD_MAP.put('L', ChronoField.MONTH_OF_YEAR); // SDF, LDML (stand-alone) - FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR); // SDF, LDML - FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH); // SDF, LDML - FIELD_MAP.put('F', ChronoField.ALIGNED_WEEK_OF_MONTH); // SDF, LDML - FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK); // SDF, LDML (different to both for 1/2 chars) - FIELD_MAP.put('c', ChronoField.DAY_OF_WEEK); // LDML (stand-alone) - FIELD_MAP.put('e', ChronoField.DAY_OF_WEEK); // LDML (needs localized week number) - FIELD_MAP.put('a', ChronoField.AMPM_OF_DAY); // SDF, LDML - FIELD_MAP.put('H', ChronoField.HOUR_OF_DAY); // SDF, LDML - FIELD_MAP.put('k', ChronoField.CLOCK_HOUR_OF_DAY); // SDF, LDML - FIELD_MAP.put('K', ChronoField.HOUR_OF_AMPM); // SDF, LDML - FIELD_MAP.put('h', ChronoField.CLOCK_HOUR_OF_AMPM); // SDF, LDML - FIELD_MAP.put('m', ChronoField.MINUTE_OF_HOUR); // SDF, LDML - FIELD_MAP.put('s', ChronoField.SECOND_OF_MINUTE); // SDF, LDML - FIELD_MAP.put('S', ChronoField.NANO_OF_SECOND); // LDML (SDF uses milli-of-second number) - FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY); // LDML - FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND); // 310 (proposed for LDML) - FIELD_MAP.put('N', ChronoField.NANO_OF_DAY); // 310 (proposed for LDML) - FIELD_MAP.put('g', JulianFields.MODIFIED_JULIAN_DAY); - // 310 - z - time-zone names, matches LDML and SimpleDateFormat 1 to 4 - // 310 - Z - matches SimpleDateFormat and LDML - // 310 - V - time-zone id, matches LDML - // 310 - v - general timezone names, not matching exactly with LDML because LDML specify to fall back - // to 'VVVV' if general-nonlocation unavailable but here it's not falling back because of lack of data - // 310 - p - prefix for padding - // 310 - X - matches LDML, almost matches SDF for 1, exact match 2&3, extended 4&5 - // 310 - x - matches LDML - // 310 - w, W, and Y are localized forms matching LDML - // LDML - B - day periods - // LDML - U - cycle year name, not supported by 310 yet - // LDML - l - deprecated - // LDML - j - not relevant + return switch (ch) { + case 'G' -> ChronoField.ERA; // SDF, LDML (different to both for 1/2 chars) + case 'y' -> ChronoField.YEAR_OF_ERA; // SDF, LDML + case 'u' -> ChronoField.YEAR; // LDML (different in SDF) + case 'Q' -> IsoFields.QUARTER_OF_YEAR; // LDML (removed quarter from 310) + case 'q' -> IsoFields.QUARTER_OF_YEAR; // LDML (stand-alone) + case 'M' -> ChronoField.MONTH_OF_YEAR; // SDF, LDML + case 'L' -> ChronoField.MONTH_OF_YEAR; // SDF, LDML (stand-alone) + case 'D' -> ChronoField.DAY_OF_YEAR; // SDF, LDML + case 'd' -> ChronoField.DAY_OF_MONTH; // SDF, LDML + case 'F' -> ChronoField.ALIGNED_WEEK_OF_MONTH; // SDF, LDML + case 'E' -> ChronoField.DAY_OF_WEEK; // SDF, LDML (different to both for 1/2 chars) + case 'c' -> ChronoField.DAY_OF_WEEK; // LDML (stand-alone) + case 'e' -> ChronoField.DAY_OF_WEEK; // LDML (needs localized week number) + case 'a' -> ChronoField.AMPM_OF_DAY; // SDF, LDML + case 'H' -> ChronoField.HOUR_OF_DAY; // SDF, LDML + case 'k' -> ChronoField.CLOCK_HOUR_OF_DAY; // SDF, LDML + case 'K' -> ChronoField.HOUR_OF_AMPM; // SDF, LDML + case 'h' -> ChronoField.CLOCK_HOUR_OF_AMPM; // SDF, LDML + case 'm' -> ChronoField.MINUTE_OF_HOUR; // SDF, LDML + case 's' -> ChronoField.SECOND_OF_MINUTE; // SDF, LDML + case 'S' -> ChronoField.NANO_OF_SECOND; // LDML (SDF uses milli-of-second number) + case 'A' -> ChronoField.MILLI_OF_DAY; // LDML + case 'n' -> ChronoField.NANO_OF_SECOND; // 310 (proposed for LDML) + case 'N' -> ChronoField.NANO_OF_DAY; // 310 (proposed for LDML) + case 'g' -> JulianFields.MODIFIED_JULIAN_DAY; + default -> null; + // 310 - z - time-zone names, matches LDML and SimpleDateFormat 1 to 4 + // 310 - Z - matches SimpleDateFormat and LDML + // 310 - V - time-zone id, matches LDML + // 310 - v - general timezone names, not matching exactly with LDML because LDML specify to fall back + // to 'VVVV' if general-nonlocation unavailable but here it's not falling back because of lack of data + // 310 - p - prefix for padding + // 310 - X - matches LDML, almost matches SDF for 1, exact match 2&3, extended 4&5 + // 310 - x - matches LDML + // 310 - w, W, and Y are localized forms matching LDML + // LDML - B - day periods + // LDML - U - cycle year name, not supported by 310 yet + // LDML - l - deprecated + // LDML - j - not relevant + }; } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/package-info.java b/src/java.base/share/classes/java/time/package-info.java index 8a4fbe44d8b..d0fb7a6c2bc 100644 --- a/src/java.base/share/classes/java/time/package-info.java +++ b/src/java.base/share/classes/java/time/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -65,7 +65,7 @@ * The main API for dates, times, instants, and durations. *

*

- * The classes defined here represent the principle date-time concepts, + * The classes defined here represent the principal date-time concepts, * including instants, durations, dates, times, time-zones and periods. * They are based on the ISO calendar system, which is the de facto world * calendar following the proleptic Gregorian rules. @@ -150,7 +150,7 @@ *

*

* {@link java.time.OffsetTime} stores a time and offset from UTC without a date. - * This stores a date like '11:30+01:00'. + * This stores a time like '11:30+01:00'. * The {@link java.time.ZoneOffset ZoneOffset} is of the form '+01:00'. *

*

@@ -249,7 +249,7 @@ *

* Multiple calendar systems is an awkward addition to the design challenges. * The first principle is that most users want the standard ISO calendar system. - * As such, the main classes are ISO-only. The second principle is that most of those that want a + * As such, the main classes are ISO-only. The second principle is that most of those who want a * non-ISO calendar system want it for user interaction, thus it is a UI localization issue. * As such, date and time objects should be held as ISO objects in the data model and persistent * storage, only being converted to and from a local calendar for display. diff --git a/src/java.base/share/classes/java/time/temporal/ChronoField.java b/src/java.base/share/classes/java/time/temporal/ChronoField.java index 9e5de367b0e..506737ff268 100644 --- a/src/java.base/share/classes/java/time/temporal/ChronoField.java +++ b/src/java.base/share/classes/java/time/temporal/ChronoField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -599,7 +599,7 @@ public enum ChronoField implements TemporalField { * A {@link ZoneOffset} represents the period of time that local time differs from UTC/Greenwich. * This is usually a fixed number of hours and minutes. * It is equivalent to the {@link ZoneOffset#getTotalSeconds() total amount} of the offset in seconds. - * For example, during the winter Paris has an offset of {@code +01:00}, which is 3600 seconds. + * For example, during the winter, Paris has an offset of {@code +01:00}, which is 3,600 seconds. *

* This field is strictly defined to have the same meaning in all calendar systems. * This is necessary to ensure interoperation between calendars. diff --git a/src/java.base/share/classes/java/time/temporal/ValueRange.java b/src/java.base/share/classes/java/time/temporal/ValueRange.java index 442cf0a2509..27e71e77d66 100644 --- a/src/java.base/share/classes/java/time/temporal/ValueRange.java +++ b/src/java.base/share/classes/java/time/temporal/ValueRange.java @@ -78,7 +78,7 @@ * Only the minimum and maximum values are provided. * It is possible for there to be invalid values within the outer range. * For example, a weird field may have valid values of 1, 2, 4, 6, 7, thus - * have a range of '1 - 7', despite that fact that values 3 and 5 are invalid. + * have a range of '1 - 7', despite the fact that values 3 and 5 are invalid. *

* Instances of this class are not tied to a specific field. * diff --git a/src/java.base/share/classes/javax/crypto/Cipher.java b/src/java.base/share/classes/javax/crypto/Cipher.java index 902c3998fbe..f95917b5c86 100644 --- a/src/java.base/share/classes/javax/crypto/Cipher.java +++ b/src/java.base/share/classes/javax/crypto/Cipher.java @@ -286,7 +286,32 @@ private Cipher(CipherSpi firstSpi, Service firstService, this.lock = new Object(); } - private static final String SHA512TRUNCATED = "SHA512/2"; + // for special handling SHA-512/224, SHA-512/256, SHA512/224, SHA512/256 + static int indexOfRealSlash(String s, int fromIndex) { + while (true) { + int pos = s.indexOf('/', fromIndex); + // 512/2 + if (pos > 3 && pos + 1 < s.length() + && s.charAt(pos - 3) == '5' + && s.charAt(pos - 2) == '1' + && s.charAt(pos - 1) == '2' + && s.charAt(pos + 1) == '2') { + fromIndex = pos + 1; + // see 512/2, find next + } else { + return pos; + } + } + } + + static String reqNonEmpty(String in, String msg) + throws NoSuchAlgorithmException { + in = in.trim(); + if (in.isEmpty()) { + throw new NoSuchAlgorithmException(msg); + } + return in; + } // Parse the specified cipher transformation for algorithm and the // optional mode and padding. If the transformation contains only @@ -305,42 +330,34 @@ private static String[] tokenizeTransformation(String transformation) * 2) feedback component (e.g., CFB) - optional * 3) padding component (e.g., PKCS5Padding) - optional */ - - // check if the transformation contains algorithms with "/" in their - // name which can cause the parsing logic to go wrong - int sha512Idx = transformation.toUpperCase(Locale.ENGLISH) - .indexOf(SHA512TRUNCATED); - int startIdx = (sha512Idx == -1 ? 0 : - sha512Idx + SHA512TRUNCATED.length()); - int endIdx = transformation.indexOf('/', startIdx); - - boolean algorithmOnly = (endIdx == -1); - String algo = (algorithmOnly ? transformation.trim() : - transformation.substring(0, endIdx).trim()); - if (algo.isEmpty()) { - throw new NoSuchAlgorithmException("Invalid transformation: " + - "algorithm not specified-" - + transformation); - } - if (algorithmOnly) { // done - return new String[] { algo }; + int endIdx = indexOfRealSlash(transformation, 0); + if (endIdx == -1) { // algo only, done + return new String[] { reqNonEmpty(transformation, + "Invalid transformation: algorithm not specified") + }; + } + // must be algo/mode/padding + String algo = reqNonEmpty(transformation.substring(0, endIdx), + "Invalid transformation: algorithm not specified"); + + int startIdx = endIdx + 1; + endIdx = indexOfRealSlash(transformation, startIdx); + if (endIdx == -1) { + throw new NoSuchAlgorithmException( + "Invalid transformation format: " + transformation); + } + String mode = reqNonEmpty(transformation.substring(startIdx, + endIdx), "Invalid transformation: missing mode"); + + startIdx = endIdx + 1; + endIdx = indexOfRealSlash(transformation, startIdx); + if (endIdx == -1) { + return new String[] { algo, mode, + reqNonEmpty(transformation.substring(startIdx), + "Invalid transformation: missing padding") }; } else { - // continue parsing mode and padding - startIdx = endIdx+1; - endIdx = transformation.indexOf('/', startIdx); - if (endIdx == -1) { - throw new NoSuchAlgorithmException("Invalid transformation" - + " format:" + transformation); - } - String mode = transformation.substring(startIdx, endIdx).trim(); - String padding = transformation.substring(endIdx+1).trim(); - // ensure mode and padding are specified - if (mode.isEmpty() || padding.isEmpty()) { - throw new NoSuchAlgorithmException("Invalid transformation: " + - "missing mode and/or padding-" - + transformation); - } - return new String[] { algo, mode, padding }; + throw new NoSuchAlgorithmException( + "Invalid transformation format: " + transformation); } } @@ -515,12 +532,12 @@ private static Transform getTransform(Service s, * transformation * * @throws NoSuchAlgorithmException if {@code transformation} - * is {@code null}, empty, in an invalid format, - * or if no provider supports a {@code CipherSpi} - * implementation for the specified algorithm + * is {@code null}, empty or in an invalid format; + * or if a {@code CipherSpi} implementation is not found or + * is found but does not support the mode * - * @throws NoSuchPaddingException if {@code transformation} - * contains a padding scheme that is not available + * @throws NoSuchPaddingException if a {@code CipherSpi} implementation + * is found but does not support the padding scheme * * @see java.security.Provider */ @@ -573,8 +590,12 @@ public static final Cipher getInstance(String transformation) failure = e; } } + if (failure instanceof NoSuchPaddingException nspe) { + throw nspe; + } throw new NoSuchAlgorithmException - ("Cannot find any provider supporting " + transformation, failure); + ("Cannot find any provider supporting " + transformation, + failure); } /** @@ -582,8 +603,8 @@ public static final Cipher getInstance(String transformation) * transformation. * *

A new {@code Cipher} object encapsulating the - * {@code CipherSpi} implementation from the specified provider - * is returned. The specified provider must be registered + * {@code CipherSpi} implementation from the specified {@code provider} + * is returned. The specified {@code provider} must be registered * in the security provider list. * *

Note that the list of registered providers may be retrieved via @@ -625,15 +646,16 @@ public static final Cipher getInstance(String transformation) * is {@code null} or empty * * @throws NoSuchAlgorithmException if {@code transformation} - * is {@code null}, empty, in an invalid format, - * or if a {@code CipherSpi} implementation for the - * specified algorithm is not available from the specified - * provider + * is {@code null}, empty or in an invalid format; + * or if a {@code CipherSpi} implementation from the specified + * {@code provider} is not found or is found but does not support + * the mode * - * @throws NoSuchPaddingException if {@code transformation} - * contains a padding scheme that is not available + * @throws NoSuchPaddingException if a {@code CipherSpi} implementation + * from the specified {@code provider} is found but does not + * support the padding scheme * - * @throws NoSuchProviderException if the specified provider is not + * @throws NoSuchProviderException if the specified {@code provider} is not * registered in the security provider list * * @see java.security.Provider @@ -706,13 +728,14 @@ private String getProviderName() { * is {@code null} * * @throws NoSuchAlgorithmException if {@code transformation} - * is {@code null}, empty, in an invalid format, - * or if a {@code CipherSpi} implementation for the - * specified algorithm is not available from the specified - * {@code provider} object - * - * @throws NoSuchPaddingException if {@code transformation} - * contains a padding scheme that is not available + * is {@code null}, empty or in an invalid format; + * or if a {@code CipherSpi} implementation from the specified + * {@code provider} is not found or is found but does not support + * the mode + * + * @throws NoSuchPaddingException if a {@code CipherSpi} implementation + * from the specified {@code provider} is found but does not + * support the padding scheme * * @see java.security.Provider */ diff --git a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java index 32399310bd3..e90ca4d75f1 100644 --- a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java +++ b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java @@ -27,8 +27,6 @@ import jdk.internal.vm.annotation.Stable; -import java.util.Arrays; - /** * A class for converting between ASCII and decimal representations of a single * or double precision floating point number. Most conversions are provided via @@ -102,7 +100,6 @@ public static double parseDoubleSignlessDigits(int decExp, byte[] digits, int le * values into an ASCII String representation. */ public interface BinaryToASCIIConverter { - int getChars(byte[] result); /** * Retrieves the decimal exponent most closely corresponding to this value. @@ -115,21 +112,7 @@ public interface BinaryToASCIIConverter { * @param digits The digit array. * @return The number of valid digits copied into the array. */ - int getDigits(char[] digits); - - /** - * Indicates the sign of the value. - * @return {@code value < 0.0}. - */ - boolean isNegative(); - - /** - * Indicates whether the value is either infinite or not a number. - * - * @return true if and only if the value is NaN - * or infinite. - */ - boolean isExceptional(); + int getDigits(byte[] digits); /** * Indicates whether the value was rounded up during the binary to ASCII @@ -147,63 +130,9 @@ public interface BinaryToASCIIConverter { boolean decimalDigitsExact(); } - /** - * A BinaryToASCIIConverter which represents NaN - * and infinite values. - */ - private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter { - private final String image; - private final boolean isNegative; - - public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) { - this.image = image; - this.isNegative = isNegative; - } - - @Override - @SuppressWarnings("deprecation") - public int getChars(byte[] chars) { - image.getBytes(0, image.length(), chars, 0); - return image.length(); - } - - @Override - public int getDecimalExponent() { - throw new IllegalArgumentException("Exceptional value does not have an exponent"); - } - - @Override - public int getDigits(char[] digits) { - throw new IllegalArgumentException("Exceptional value does not have digits"); - } - - @Override - public boolean isNegative() { - return isNegative; - } - - @Override - public boolean isExceptional() { - return true; - } - - @Override - public boolean digitsRoundedUp() { - throw new IllegalArgumentException("Exceptional value is not rounded"); - } - - @Override - public boolean decimalDigitsExact() { - throw new IllegalArgumentException("Exceptional value is not exact"); - } - } - private static final String INFINITY_REP = "Infinity"; private static final String NAN_REP = "NaN"; - private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false); - private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true); - private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false); private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new byte[]{'0'}); private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new byte[]{'0'}); @@ -255,21 +184,11 @@ public int getDecimalExponent() { } @Override - public int getDigits(char[] digits) { + public int getDigits(byte[] digits) { System.arraycopy(this.digits, firstDigitIndex, digits, 0, this.nDigits); return this.nDigits; } - @Override - public boolean isNegative() { - return isNegative; - } - - @Override - public boolean isExceptional() { - return false; - } - @Override public boolean digitsRoundedUp() { return decimalDigitsRoundedUp; @@ -826,83 +745,6 @@ private static int insignificantDigitsForPow2(int p2) { 61, }; - /** - * Converts the decimal representation of a floating-point number into its - * ASCII character representation and stores it in the provided byte array. - * - * @param result the byte array to store the ASCII representation, must have length at least 26 - * @return the number of characters written to the result array - */ - public int getChars(byte[] result) { - assert nDigits <= 19 : nDigits; // generous bound on size of nDigits - int i = 0; - if (isNegative) { - result[0] = '-'; - i = 1; - } - if (decExponent > 0 && decExponent < 8) { - // print digits.digits. - int charLength = Math.min(nDigits, decExponent); - System.arraycopy(digits, firstDigitIndex, result, i, charLength); - i += charLength; - if (charLength < decExponent) { - charLength = decExponent - charLength; - Arrays.fill(result, i, i + charLength, (byte) '0'); - i += charLength; - result[i++] = '.'; - result[i++] = '0'; - } else { - result[i++] = '.'; - if (charLength < nDigits) { - int t = nDigits - charLength; - System.arraycopy(digits, firstDigitIndex + charLength, result, i, t); - i += t; - } else { - result[i++] = '0'; - } - } - } else if (decExponent <= 0 && decExponent > -3) { - result[i++] = '0'; - result[i++] = '.'; - if (decExponent != 0) { - Arrays.fill(result, i, i-decExponent, (byte) '0'); - i -= decExponent; - } - System.arraycopy(digits, firstDigitIndex, result, i, nDigits); - i += nDigits; - } else { - result[i++] = digits[firstDigitIndex]; - result[i++] = '.'; - if (nDigits > 1) { - System.arraycopy(digits, firstDigitIndex+1, result, i, nDigits - 1); - i += nDigits - 1; - } else { - result[i++] = '0'; - } - result[i++] = 'E'; - int e; - if (decExponent <= 0) { - result[i++] = '-'; - e = -decExponent + 1; - } else { - e = decExponent - 1; - } - // decExponent has 1, 2, or 3, digits - if (e <= 9) { - result[i++] = (byte) (e + '0'); - } else if (e <= 99) { - result[i++] = (byte) (e / 10 + '0'); - result[i++] = (byte) (e % 10 + '0'); - } else { - result[i++] = (byte) (e / 100 + '0'); - e %= 100; - result[i++] = (byte) (e / 10 + '0'); - result[i++] = (byte) (e % 10 + '0'); - } - } - return i; - } - } private static final ThreadLocal threadLocalBinaryToASCIIBuffer = @@ -1707,9 +1549,9 @@ private static BinaryToASCIIConverter getCompatBinaryToASCIIConverter(double d, // Discover obvious special cases of NaN and Infinity. if ( binExp == (int)(DoubleConsts.EXP_BIT_MASK>>EXP_SHIFT) ) { if ( fractBits == 0L ){ - return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY; + throw new IllegalArgumentException((isNegative ? "-" : "") + INFINITY_REP); } else { - return B2AC_NOT_A_NUMBER; + throw new IllegalArgumentException(NAN_REP); } } // Finish unpacking diff --git a/src/java.base/share/classes/jdk/internal/vm/Continuation.java b/src/java.base/share/classes/jdk/internal/vm/Continuation.java index a97f9ac9ea4..a7eb3ea6a9f 100644 --- a/src/java.base/share/classes/jdk/internal/vm/Continuation.java +++ b/src/java.base/share/classes/jdk/internal/vm/Continuation.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 @@ -57,7 +57,6 @@ public class Continuation { /** Reason for pinning */ public enum Pinned { /** Native frame on stack */ NATIVE, - /** Monitor held */ MONITOR, /** In critical section */ CRITICAL_SECTION, /** Exception (OOME/SOE) */ EXCEPTION } @@ -69,8 +68,7 @@ public enum PreemptStatus { /** Permanent failure: continuation already yielding */ PERM_FAIL_YIELDING(null), /** Permanent failure: continuation not mounted on the thread */ PERM_FAIL_NOT_MOUNTED(null), /** Transient failure: continuation pinned due to a held CS */ TRANSIENT_FAIL_PINNED_CRITICAL_SECTION(Pinned.CRITICAL_SECTION), - /** Transient failure: continuation pinned due to native frame */ TRANSIENT_FAIL_PINNED_NATIVE(Pinned.NATIVE), - /** Transient failure: continuation pinned due to a held monitor */ TRANSIENT_FAIL_PINNED_MONITOR(Pinned.MONITOR); + /** Transient failure: continuation pinned due to native frame */ TRANSIENT_FAIL_PINNED_NATIVE(Pinned.NATIVE); final Pinned pinned; private PreemptStatus(Pinned reason) { this.pinned = reason; } @@ -85,8 +83,7 @@ private static Pinned pinnedReason(int reason) { return switch (reason) { case 2 -> Pinned.CRITICAL_SECTION; case 3 -> Pinned.NATIVE; - case 4 -> Pinned.MONITOR; - case 5 -> Pinned.EXCEPTION; + case 4 -> Pinned.EXCEPTION; default -> throw new AssertionError("Unknown pinned reason: " + reason); }; } diff --git a/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java b/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java index a26003a3afb..276c379a564 100644 --- a/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java +++ b/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java @@ -205,7 +205,10 @@ private static boolean dumpThread(Thread thread, TextWriter writer) { // park blocker Object parkBlocker = snapshot.parkBlocker(); if (parkBlocker != null) { - writer.println(" - parking to wait for " + decorateObject(parkBlocker)); + String suffix = (snapshot.parkBlockerOwner() instanceof Thread owner) + ? ", owner #" + owner.threadId() + : ""; + writer.println(" - parking to wait for " + decorateObject(parkBlocker) + suffix); } // blocked on monitor enter or Object.wait @@ -335,6 +338,9 @@ private static boolean dumpThread(Thread thread, JsonWriter jsonWriter) { // parkBlocker is an object to allow for exclusiveOwnerThread in the future jsonWriter.startObject("parkBlocker"); jsonWriter.writeProperty("object", Objects.toIdentityString(parkBlocker)); + if (snapshot.parkBlockerOwner() instanceof Thread owner) { + jsonWriter.writeProperty("owner", owner.threadId()); + } jsonWriter.endObject(); } diff --git a/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java b/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java index 4fcbaf24d2e..357d38008d1 100644 --- a/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java +++ b/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java @@ -44,6 +44,8 @@ class ThreadSnapshot { // an object the thread is blocked/waiting on, converted to ThreadBlocker by ThreadSnapshot.of() private int blockerTypeOrdinal; private Object blockerObject; + // the owner of the blockerObject when the object is park blocker and is AbstractOwnableSynchronizer + private Thread parkBlockerOwner; // set by ThreadSnapshot.of() private ThreadBlocker blocker; @@ -70,8 +72,11 @@ static ThreadSnapshot of(Thread thread) { snapshot.locks = EMPTY_LOCKS; } if (snapshot.blockerObject != null) { - snapshot.blocker = new ThreadBlocker(snapshot.blockerTypeOrdinal, snapshot.blockerObject); + snapshot.blocker = new ThreadBlocker(snapshot.blockerTypeOrdinal, + snapshot.blockerObject, + snapshot.parkBlockerOwner); snapshot.blockerObject = null; // release + snapshot.parkBlockerOwner = null; } return snapshot; } @@ -104,6 +109,13 @@ Object parkBlocker() { return getBlocker(BlockerLockType.PARK_BLOCKER); } + /** + * Returns the owner of the parkBlocker if the parkBlocker is an AbstractOwnableSynchronizer. + */ + Thread parkBlockerOwner() { + return (blocker != null && blocker.type == BlockerLockType.PARK_BLOCKER) ? blocker.owner : null; + } + /** * Returns the object that the thread is blocked on. * @throws IllegalStateException if not in the blocked state @@ -211,11 +223,11 @@ Object lockObject() { } } - private record ThreadBlocker(BlockerLockType type, Object obj) { + private record ThreadBlocker(BlockerLockType type, Object obj, Thread owner) { private static final BlockerLockType[] lockTypeValues = BlockerLockType.values(); // cache - ThreadBlocker(int typeOrdinal, Object obj) { - this(lockTypeValues[typeOrdinal], obj); + ThreadBlocker(int typeOrdinal, Object obj, Thread owner) { + this(lockTypeValues[typeOrdinal], obj, owner); } } diff --git a/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java b/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java index 76bbff2a610..bd5ea6d7635 100644 --- a/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java +++ b/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java @@ -37,12 +37,33 @@ public class BytecodeDescriptor { private BytecodeDescriptor() { } // cannot instantiate - /** - * @param loader the class loader in which to look up the types (null means - * bootstrap class loader) - */ - public static List> parseMethod(String bytecodeSignature, ClassLoader loader) { - return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader); + /// Parses and validates a field descriptor string in the {@code loader} context. + /// + /// @param descriptor a field descriptor string + /// @param loader the class loader in which to look up the types (null means + /// bootstrap class loader) + /// @throws IllegalArgumentException if the descriptor is invalid + /// @throws TypeNotPresentException if the descriptor is valid, but + /// the class cannot be found by the loader + public static Class parseClass(String descriptor, ClassLoader loader) { + int[] i = {0}; + var ret = parseSig(descriptor, i, descriptor.length(), loader); + if (i[0] != descriptor.length() || ret == null) { + parseError("not a class descriptor", descriptor); + } + return ret; + } + + /// Parses and validates a method descriptor string in the {@code loader} context. + /// + /// @param descriptor a method descriptor string + /// @param loader the class loader in which to look up the types (null means + /// bootstrap class loader) + /// @throws IllegalArgumentException if the descriptor is invalid + /// @throws TypeNotPresentException if a reference type cannot be found by + /// the loader (before the descriptor is found invalid) + public static List> parseMethod(String descriptor, ClassLoader loader) { + return parseMethod(descriptor, 0, descriptor.length(), loader); } /** @@ -77,10 +98,19 @@ private static void parseError(String str, String msg) { throw new IllegalArgumentException("bad signature: "+str+": "+msg); } - /** - * @param loader the class loader in which to look up the types (null means - * bootstrap class loader) - */ + /// Parse a single type in a descriptor. Results can be: + /// + /// - A `Class` for successful parsing + /// - `null` for malformed descriptor format + /// - Throwing a [TypeNotPresentException] for valid class name, + /// but class cannot be found + /// + /// @param str contains the string to parse + /// @param i cursor for the next token in the string, modified in-place + /// @param end the limit for parsing + /// @param loader the class loader in which to look up the types (null means + /// bootstrap class loader) + /// private static Class parseSig(String str, int[] i, int end, ClassLoader loader) { if (i[0] == end) return null; char c = str.charAt(i[0]++); @@ -107,7 +137,14 @@ private static Class parseSig(String str, int[] i, int end, ClassLoader loade } return t; } else { - return Wrapper.forBasicType(c).primitiveType(); + Wrapper w; + try { + w = Wrapper.forBasicType(c); + } catch (IllegalArgumentException ex) { + // Our reporting has better error message + return null; + } + return w.primitiveType(); } } diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java index 82751e3fcd2..74ed1e01553 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.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 @@ -34,12 +34,7 @@ import jdk.internal.reflect.ConstantPool; -import sun.reflect.generics.parser.SignatureParser; -import sun.reflect.generics.tree.TypeSignature; -import sun.reflect.generics.factory.GenericsFactory; -import sun.reflect.generics.factory.CoreReflectionFactory; -import sun.reflect.generics.visitor.Reifier; -import sun.reflect.generics.scope.ClassScope; +import sun.invoke.util.BytecodeDescriptor; /** * Parser for Java programming language annotations. Translates @@ -429,19 +424,11 @@ private static Object parseClassValue(ByteBuffer buf, } private static Class parseSig(String sig, Class container) { - if (sig.equals("V")) return void.class; - SignatureParser parser = SignatureParser.make(); - TypeSignature typeSig = parser.parseTypeSig(sig); - GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container)); - Reifier reify = Reifier.make(factory); - typeSig.accept(reify); - Type result = reify.getResult(); - return toClass(result); - } - static Class toClass(Type o) { - if (o instanceof GenericArrayType gat) - return toClass(gat.getGenericComponentType()).arrayType(); - return (Class) o; + try { + return BytecodeDescriptor.parseClass(sig, container.getClassLoader()); + } catch (IllegalArgumentException ex) { + throw new GenericSignatureFormatError(ex.getMessage()); + } } /** diff --git a/src/java.base/share/classes/sun/security/ssl/Alert.java b/src/java.base/share/classes/sun/security/ssl/Alert.java index 960b3f3b37d..ed5e079bf44 100644 --- a/src/java.base/share/classes/sun/security/ssl/Alert.java +++ b/src/java.base/share/classes/sun/security/ssl/Alert.java @@ -181,6 +181,16 @@ private static final class AlertMessage { AlertMessage(TransportContext context, ByteBuffer m) throws IOException { + // From RFC 8446 "Implementations + // MUST NOT send Handshake and Alert records that have a zero-length + // TLSInnerPlaintext.content; if such a message is received, the + // receiving implementation MUST terminate the connection with an + // "unexpected_message" alert." + if (m.remaining() == 0) { + throw context.fatal(Alert.UNEXPECTED_MESSAGE, + "Alert fragments must not be zero length."); + } + // struct { // AlertLevel level; // AlertDescription description; diff --git a/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java b/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java index b975290d09d..2125a148162 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java @@ -36,6 +36,11 @@ /** * Pack of the "signature_algorithms_cert" extensions. + *

+ * Note: Per RFC 8446, if no "signature_algorithms_cert" extension is + * present, then the "signature_algorithms" extension also applies to + * signatures appearing in certificates. + * See {@code SignatureAlgorithmsExtension} for details. */ final class CertSignAlgsExtension { static final HandshakeProducer chNetworkProducer = diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java index e0196f3009c..101a42a5407 100644 --- a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.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 @@ -801,8 +801,11 @@ void queueUpHandshake(HandshakeFragment hsf) throws SSLProtocolException { // buffer this fragment if (hsf.handshakeType == SSLHandshake.FINISHED.id) { - // Need no status update. - bufferedFragments.add(hsf); + // Make sure it's not a retransmitted message + if (hsf.recordEpoch > handshakeEpoch) { + bufferedFragments.add(hsf); + flightIsReady = holes.isEmpty(); + } } else { bufferFragment(hsf); } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java b/src/java.base/share/classes/sun/security/ssl/SSLCipher.java index d11ffc96b47..4a52a2ea583 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLCipher.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 @@ -1923,9 +1923,9 @@ public Plaintext decrypt(byte contentType, ByteBuffer bb, // remove inner plaintext padding int i = pt.limit() - 1; - for (; i > 0 && pt.get(i) == 0; i--); + for (; i >= pos && pt.get(i) == 0; i--); - if (i < (pos + 1)) { + if (i < pos) { throw new BadPaddingException( "Incorrect inner plaintext: no content type"); } @@ -2441,10 +2441,9 @@ public Plaintext decrypt(byte contentType, ByteBuffer bb, // remove inner plaintext padding int i = pt.limit() - 1; - for (; i > 0 && pt.get(i) == 0; i--) { - // blank - } - if (i < (pos + 1)) { + for (; i >= pos && pt.get(i) == 0; i--); + + if (i < pos) { throw new BadPaddingException( "Incorrect inner plaintext: no content type"); } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java index 1db07c77160..5cb78ed44f7 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java @@ -29,13 +29,11 @@ import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.security.ProviderException; -import java.security.spec.AlgorithmParameterSpec; import javax.crypto.KDF; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.HKDFParameterSpec; import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.SSLHandshakeException; import sun.security.internal.spec.TlsKeyMaterialParameterSpec; import sun.security.internal.spec.TlsKeyMaterialSpec; @@ -191,26 +189,26 @@ private static byte[] createHkdfInfo( private enum KeySchedule { // Note that we use enum name as the key name. - TlsKey ("key", false), - TlsIv ("iv", true), - TlsUpdateNplus1 ("traffic upd", false); + TlsKey ("key"), + TlsIv ("iv"), + TlsUpdateNplus1 ("traffic upd"); private final byte[] label; - private final boolean isIv; - KeySchedule(String label, boolean isIv) { + KeySchedule(String label) { this.label = ("tls13 " + label).getBytes(); - this.isIv = isIv; } int getKeyLength(CipherSuite cs) { - if (this == KeySchedule.TlsUpdateNplus1) - return cs.hashAlg.hashLength; - return isIv ? cs.bulkCipher.ivSize : cs.bulkCipher.keySize; + return switch (this) { + case TlsUpdateNplus1 -> cs.hashAlg.hashLength; + case TlsIv -> cs.bulkCipher.ivSize; + case TlsKey -> cs.bulkCipher.keySize; + }; } String getAlgorithm(CipherSuite cs, String algorithm) { - return isIv ? algorithm : cs.bulkCipher.algorithm; + return this == TlsKey ? cs.bulkCipher.algorithm : algorithm; } } diff --git a/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java b/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java index c0d2bea77ca..444af5d6dae 100644 --- a/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java @@ -278,8 +278,10 @@ ByteBuffer decrypt(HandshakeContext hc) { aad.putInt(keyID).put(compressed); c.updateAAD(aad); + // use getOutputSize to avoid a ShortBufferException + // from providers that require oversized buffers. See JDK-8368514. ByteBuffer out = ByteBuffer.allocate( - data.remaining() - GCM_TAG_LEN / 8); + c.getOutputSize(data.remaining())); c.doFinal(data, out); out.flip(); @@ -291,7 +293,7 @@ ByteBuffer decrypt(HandshakeContext hc) { return out; } catch (Exception e) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { - SSLLogger.fine("Decryption failed." + e.getMessage()); + SSLLogger.fine("Decryption failed." + e); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java index a95b31583bb..b298da05e9a 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java @@ -31,6 +31,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -191,21 +192,9 @@ public byte[] produce(ConnectionContext context, // Produce the extension. SignatureScheme.updateHandshakeLocalSupportedAlgs(chc); - int vectorLen = SignatureScheme.sizeInRecord() * - chc.localSupportedSignAlgs.size(); - byte[] extData = new byte[vectorLen + 2]; - ByteBuffer m = ByteBuffer.wrap(extData); - Record.putInt16(m, vectorLen); - for (SignatureScheme ss : chc.localSupportedSignAlgs) { - Record.putInt16(m, ss.id); - } - - // Update the context. - chc.handshakeExtensions.put( + return produceNetworkLoad(chc, SSLExtension.CH_SIGNATURE_ALGORITHMS, - new SignatureSchemesSpec(chc.localSupportedSignAlgs)); - - return extData; + SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT); } } @@ -391,23 +380,11 @@ public byte[] produce(ConnectionContext context, } // Produce the extension. - // localSupportedSignAlgs has been already updated when we - // set the negotiated protocol. - int vectorLen = SignatureScheme.sizeInRecord() - * shc.localSupportedSignAlgs.size(); - byte[] extData = new byte[vectorLen + 2]; - ByteBuffer m = ByteBuffer.wrap(extData); - Record.putInt16(m, vectorLen); - for (SignatureScheme ss : shc.localSupportedSignAlgs) { - Record.putInt16(m, ss.id); - } - - // Update the context. - shc.handshakeExtensions.put( + // localSupportedSignAlgs and localSupportedCertSignAlgs have been + // already updated when we set the negotiated protocol. + return produceNetworkLoad(shc, SSLExtension.CR_SIGNATURE_ALGORITHMS, - new SignatureSchemesSpec(shc.localSupportedSignAlgs)); - - return extData; + SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT); } } @@ -546,4 +523,45 @@ private static void updateHandshakeContext(HandshakeContext hc, hc.handshakeSession.setPeerSupportedSignatureAlgorithms(certSS); } } + + /** + * Produce network load and update context. + * + * @param hc HandshakeContext + * @param signatureAlgorithmsExt "signature_algorithms" extension + * @param signatureAlgorithmsCertExt "signature_algorithms_cert" + * extension + * @return network load as byte array + */ + private static byte[] produceNetworkLoad( + HandshakeContext hc, SSLExtension signatureAlgorithmsExt, + SSLExtension signatureAlgorithmsCertExt) throws IOException { + + List sigAlgs; + + // If we don't produce "signature_algorithms_cert" extension, then + // the "signature_algorithms" extension should contain signatures + // supported for both: handshake signatures and certificate signatures. + if (hc.sslConfig.isAvailable(signatureAlgorithmsCertExt)) { + sigAlgs = hc.localSupportedSignAlgs; + } else { + sigAlgs = new ArrayList<>(hc.localSupportedSignAlgs); + sigAlgs.retainAll(hc.localSupportedCertSignAlgs); + } + + int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size(); + byte[] extData = new byte[vectorLen + 2]; + ByteBuffer m = ByteBuffer.wrap(extData); + Record.putInt16(m, vectorLen); + + for (SignatureScheme ss : sigAlgs) { + Record.putInt16(m, ss.id); + } + + // Update the context. + hc.handshakeExtensions.put( + signatureAlgorithmsExt, new SignatureSchemesSpec(sigAlgs)); + + return extData; + } } diff --git a/src/java.base/share/classes/sun/util/locale/LanguageTag.java b/src/java.base/share/classes/sun/util/locale/LanguageTag.java index 6036c1dd04f..0b2fee7f2cd 100644 --- a/src/java.base/share/classes/sun/util/locale/LanguageTag.java +++ b/src/java.base/share/classes/sun/util/locale/LanguageTag.java @@ -34,17 +34,21 @@ import java.text.ParsePosition; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.IllformedLocaleException; import java.util.List; import java.util.Locale; -import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.StringJoiner; // List fields are unmodifiable -public record LanguageTag(String language, String script, String region, String privateuse, - List extlangs, List variants, List extensions) { +public record LanguageTag(String language, + String script, + String region, + String privateuse, + List extlangs, + List variants, + List extensions) { public static final String SEP = "-"; public static final String PRIVATEUSE = "x"; @@ -53,78 +57,6 @@ public record LanguageTag(String language, String script, String region, String private static final String EMPTY_SUBTAG = ""; private static final List EMPTY_SUBTAGS = List.of(); - // Map contains legacy language tags and its preferred mappings from - // http://www.ietf.org/rfc/rfc5646.txt - // Keys are lower-case strings. - private static final Map LEGACY; - - static { - // grandfathered = irregular ; non-redundant tags registered - // / regular ; during the RFC 3066 era - // - // irregular = "en-GB-oed" ; irregular tags do not match - // / "i-ami" ; the 'langtag' production and - // / "i-bnn" ; would not otherwise be - // / "i-default" ; considered 'well-formed' - // / "i-enochian" ; These tags are all valid, - // / "i-hak" ; but most are deprecated - // / "i-klingon" ; in favor of more modern - // / "i-lux" ; subtags or subtag - // / "i-mingo" ; combination - // / "i-navajo" - // / "i-pwn" - // / "i-tao" - // / "i-tay" - // / "i-tsu" - // / "sgn-BE-FR" - // / "sgn-BE-NL" - // / "sgn-CH-DE" - // - // regular = "art-lojban" ; these tags match the 'langtag' - // / "cel-gaulish" ; production, but their subtags - // / "no-bok" ; are not extended language - // / "no-nyn" ; or variant subtags: their meaning - // / "zh-guoyu" ; is defined by their registration - // / "zh-hakka" ; and all of these are deprecated - // / "zh-min" ; in favor of a more modern - // / "zh-min-nan" ; subtag or sequence of subtags - // / "zh-xiang" - - final String[][] entries = { - //{"tag", "preferred"}, - {"art-lojban", "jbo"}, - {"cel-gaulish", "xtg-x-cel-gaulish"}, // fallback - {"en-GB-oed", "en-GB-x-oed"}, // fallback - {"i-ami", "ami"}, - {"i-bnn", "bnn"}, - {"i-default", "en-x-i-default"}, // fallback - {"i-enochian", "und-x-i-enochian"}, // fallback - {"i-hak", "hak"}, - {"i-klingon", "tlh"}, - {"i-lux", "lb"}, - {"i-mingo", "see-x-i-mingo"}, // fallback - {"i-navajo", "nv"}, - {"i-pwn", "pwn"}, - {"i-tao", "tao"}, - {"i-tay", "tay"}, - {"i-tsu", "tsu"}, - {"no-bok", "nb"}, - {"no-nyn", "nn"}, - {"sgn-BE-FR", "sfb"}, - {"sgn-BE-NL", "vgt"}, - {"sgn-CH-DE", "sgg"}, - {"zh-guoyu", "cmn"}, - {"zh-hakka", "hak"}, - {"zh-min", "nan-x-zh-min"}, // fallback - {"zh-min-nan", "nan"}, - {"zh-xiang", "hsn"}, - }; - LEGACY = HashMap.newHashMap(entries.length); - for (String[] e : entries) { - LEGACY.put(LocaleUtils.toLowerString(e[0]), e); - } - } - /* * BNF in RFC5646 * @@ -175,14 +107,10 @@ public static LanguageTag parse(String languageTag, ParsePosition pp, StringTokenIterator itr; var errorMsg = new StringBuilder(); - // Check if the tag is a legacy language tag - String[] gfmap = LEGACY.get(LocaleUtils.toLowerString(languageTag)); - if (gfmap != null) { - // use preferred mapping - itr = new StringTokenIterator(gfmap[1], SEP); - } else { - itr = new StringTokenIterator(languageTag, SEP); - } + // Check if the tag is a legacy tag + var pref = legacyToPreferred(LocaleUtils.toLowerString(languageTag)); + // If legacy use preferred mapping, otherwise use the tag as is + itr = new StringTokenIterator(Objects.requireNonNullElse(pref, languageTag), SEP); String language = parseLanguage(itr, pp); List extlangs; @@ -400,15 +328,24 @@ private static String parsePrivateuse(StringTokenIterator itr, ParsePosition pp, public static String caseFoldTag(String tag) { parse(tag, new ParsePosition(0), false); + StringBuilder bldr = new StringBuilder(tag.length()); + String[] subtags = tag.split(SEP); // Legacy tags - String potentialLegacy = tag.toLowerCase(Locale.ROOT); - if (LEGACY.containsKey(potentialLegacy)) { - return LEGACY.get(potentialLegacy)[0]; + if (legacyToPreferred(tag.toLowerCase(Locale.ROOT)) != null) { + // Fold the legacy tag + for (int i = 0; i < subtags.length ; i++) { + // 2 ALPHA Region subtag(s) are upper, all other subtags are lower + if (i > 0 && subtags[i].length() == 2) { + bldr.append(LocaleUtils.toUpperString(subtags[i])).append(SEP); + } else { + bldr.append(LocaleUtils.toLowerString(subtags[i])).append(SEP); + } + } + bldr.setLength(bldr.length() - 1); // Remove trailing '-' + return bldr.toString(); } // Non-legacy tags - StringBuilder bldr = new StringBuilder(tag.length()); - String[] subtags = tag.split("-"); boolean privateFound = false; boolean singletonFound = false; boolean privUseVarFound = false; @@ -435,7 +372,7 @@ public static String caseFoldTag(String tag) { bldr.append(subtag.toLowerCase(Locale.ROOT)); } if (i != subtags.length-1) { - bldr.append("-"); + bldr.append(SEP); } } return bldr.substring(0); @@ -567,6 +504,47 @@ public static LanguageTag parseLocale(BaseLocale baseLocale, LocaleExtensions lo return new LanguageTag(language, script, region, privateuse, EMPTY_SUBTAGS, variants, extensions); } + /* + * Converts a legacy tag to its preferred mapping if it exists, otherwise null. + * The keys are mapped and stored as lower case. (Folded on demand). + * See http://www.ietf.org/rfc/rfc5646.txt Section 2.1 and 2.2.8 for the + * full syntax and case accurate legacy tags. + */ + private static String legacyToPreferred(String tag) { + if (tag.length() < 5) { + return null; + } + return switch (tag) { + case "art-lojban" -> "jbo"; + case "cel-gaulish" -> "xtg-x-cel-gaulish"; // fallback + case "en-gb-oed" -> "en-GB-x-oed"; // fallback + case "i-ami" -> "ami"; + case "i-bnn" -> "bnn"; + case "i-default" -> "en-x-i-default"; // fallback + case "i-enochian" -> "und-x-i-enochian"; // fallback + case "i-hak", + "zh-hakka" -> "hak"; + case "i-klingon" -> "tlh"; + case "i-lux" -> "lb"; + case "i-mingo" -> "see-x-i-mingo"; // fallback + case "i-navajo" -> "nv"; + case "i-pwn" -> "pwn"; + case "i-tao" -> "tao"; + case "i-tay" -> "tay"; + case "i-tsu" -> "tsu"; + case "no-bok" -> "nb"; + case "no-nyn" -> "nn"; + case "sgn-be-fr" -> "sfb"; + case "sgn-be-nl" -> "vgt"; + case "sgn-ch-de" -> "sgg"; + case "zh-guoyu" -> "cmn"; + case "zh-min" -> "nan-x-zh-min"; // fallback + case "zh-min-nan" -> "nan"; + case "zh-xiang" -> "hsn"; + default -> null; + }; + } + // // Language subtag syntax checking methods // diff --git a/src/java.base/share/classes/sun/util/locale/UnicodeLocaleExtension.java b/src/java.base/share/classes/sun/util/locale/UnicodeLocaleExtension.java index 634932e9e19..7f66febf65f 100644 --- a/src/java.base/share/classes/sun/util/locale/UnicodeLocaleExtension.java +++ b/src/java.base/share/classes/sun/util/locale/UnicodeLocaleExtension.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/src/java.base/windows/native/libjava/canonicalize_md.c b/src/java.base/windows/native/libjava/canonicalize_md.c index ecfdf63d091..7e567c7fbb4 100644 --- a/src/java.base/windows/native/libjava/canonicalize_md.c +++ b/src/java.base/windows/native/libjava/canonicalize_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, 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 @@ -41,7 +41,7 @@ /* We should also include jdk_util.h here, for the prototype of JDK_Canonicalize. This isn't possible though because canonicalize_md.c is as well used in different contexts within Oracle. - */ +*/ #include "io_util_md.h" /* Copy bytes to dst, not going past dend; return dst + number of bytes copied, @@ -139,7 +139,8 @@ lastErrorReportable() || (errval == ERROR_ACCESS_DENIED) || (errval == ERROR_NETWORK_UNREACHABLE) || (errval == ERROR_NETWORK_ACCESS_DENIED) - || (errval == ERROR_NO_MORE_FILES)) { + || (errval == ERROR_NO_MORE_FILES) + || (errval == ERROR_NETNAME_DELETED)) { return 0; } return 1; @@ -183,7 +184,7 @@ wcanonicalize(WCHAR *orig_path, WCHAR *result, int size) /* Copy prefix, assuming path is absolute */ c = src[0]; if (((c <= L'z' && c >= L'a') || (c <= L'Z' && c >= L'A')) - && (src[1] == L':') && (src[2] == L'\\')) { + && (src[1] == L':') && (src[2] == L'\\')) { /* Drive specifier */ *src = towupper(*src); /* Canonicalize drive letter */ if (!(dst = wcp(dst, dend, L'\0', src, src + 2))) { @@ -244,9 +245,9 @@ wcanonicalize(WCHAR *orig_path, WCHAR *result, int size) continue; } else { if (!lastErrorReportable()) { - if (!(dst = wcp(dst, dend, L'\0', src, src + wcslen(src)))){ - goto err; - } + if (!(dst = wcp(dst, dend, L'\0', src, src + wcslen(src)))){ + goto err; + } break; } else { goto err; @@ -255,7 +256,7 @@ wcanonicalize(WCHAR *orig_path, WCHAR *result, int size) } if (dst >= dend) { - errno = ENAMETOOLONG; + errno = ENAMETOOLONG; goto err; } *dst = L'\0'; @@ -366,7 +367,7 @@ JDK_Canonicalize(const char *orig, char *out, int len) { // Change return value to success. ret = 0; -finish: + finish: free(wresult); free(wpath); diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterGraphics.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterGraphics.java index c3ed089472b..45fcdfd2c0c 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterGraphics.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterGraphics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 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 @@ -75,4 +75,16 @@ public boolean drawImage(Image img, // needToCopyBgColorImage, is private instead of protected!) return getDelegate().drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer); } + + @Override + public void drawString(String str, int x, int y) { + str = RasterPrinterJob.removeControlChars(str); + super.drawString(str, x, y); + } + + @Override + public void drawString(String str, float x, float y) { + str = RasterPrinterJob.removeControlChars(str); + super.drawString(str, x, y); + } } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CTextPipe.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CTextPipe.m index 9da3b6648fb..f1c12585728 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CTextPipe.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CTextPipe.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, 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 @@ -457,15 +457,17 @@ render using the right font (see bug 7183516) when attribString is not } } if (positions != NULL) { + + CGAffineTransform invTx = CGAffineTransformInvert(strike->fFontTx); + CGPoint prev; prev.x = positions[0]; prev.y = positions[1]; + prev = CGPointApplyAffineTransform(prev, invTx); // take the first point, and move the context to that location CGContextTranslateCTM(qsdo->cgRef, prev.x, prev.y); - CGAffineTransform invTx = CGAffineTransformInvert(strike->fFontTx); - // for each position, figure out the advance (since CG won't take positions directly) size_t i; for (i = 0; i < length - 1; i++) @@ -476,7 +478,7 @@ render using the right font (see bug 7183516) when attribString is not pt.y = positions[i2+1]; pt = CGPointApplyAffineTransform(pt, invTx); advances[i].width = pt.x - prev.x; - advances[i].height = -(pt.y - prev.y); // negative to translate to device space + advances[i].height = pt.y - prev.y; prev.x = pt.x; prev.y = pt.y; } diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java index 8bf09195627..0c2902ba74a 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java @@ -41,6 +41,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamException; @@ -1549,33 +1550,19 @@ private void writeObject(ObjectOutputStream s) throws IOException { private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); - - String csName = (String) s.readObject(); - byte[] data = (byte[]) s.readObject(); - - int cspace = 0; // ColorSpace.CS_* constant if known - boolean isKnownPredefinedCS = false; - if (csName != null) { - isKnownPredefinedCS = true; - if (csName.equals("CS_sRGB")) { - cspace = ColorSpace.CS_sRGB; - } else if (csName.equals("CS_CIEXYZ")) { - cspace = ColorSpace.CS_CIEXYZ; - } else if (csName.equals("CS_PYCC")) { - cspace = ColorSpace.CS_PYCC; - } else if (csName.equals("CS_GRAY")) { - cspace = ColorSpace.CS_GRAY; - } else if (csName.equals("CS_LINEAR_RGB")) { - cspace = ColorSpace.CS_LINEAR_RGB; - } else { - isKnownPredefinedCS = false; - } - } - - if (isKnownPredefinedCS) { - resolvedDeserializedProfile = getInstance(cspace); - } else { - resolvedDeserializedProfile = getInstance(data); + try { + String csName = (String) s.readObject(); + byte[] data = (byte[]) s.readObject(); + resolvedDeserializedProfile = switch (csName) { + case "CS_sRGB" -> getInstance(ColorSpace.CS_sRGB); + case "CS_CIEXYZ" -> getInstance(ColorSpace.CS_CIEXYZ); + case "CS_PYCC" -> getInstance(ColorSpace.CS_PYCC); + case "CS_GRAY" -> getInstance(ColorSpace.CS_GRAY); + case "CS_LINEAR_RGB" -> getInstance(ColorSpace.CS_LINEAR_RGB); + case null, default -> getInstance(data); + }; + } catch (ClassCastException | IllegalArgumentException e) { + throw new InvalidObjectException("Invalid ICC Profile Data", e); } } diff --git a/src/java.desktop/share/classes/java/awt/image/LookupOp.java b/src/java.desktop/share/classes/java/awt/image/LookupOp.java index 5d11f78e76d..c8d8a703a3f 100644 --- a/src/java.desktop/share/classes/java/awt/image/LookupOp.java +++ b/src/java.desktop/share/classes/java/awt/image/LookupOp.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/src/java.desktop/share/classes/java/beans/Beans.java b/src/java.desktop/share/classes/java/beans/Beans.java index 313bfe98515..a95aeb45cbb 100644 --- a/src/java.desktop/share/classes/java/beans/Beans.java +++ b/src/java.desktop/share/classes/java/beans/Beans.java @@ -64,6 +64,22 @@ public Beans() {} *

* Instantiate a JavaBean. *

+ * The bean is created based on a name relative to a class-loader. + * This name should be a {@linkplain ClassLoader##binary-name binary name} of a class such as "a.b.C". + *

+ * The given name can indicate either a serialized object or a class. + * We first try to treat the {@code beanName} as a serialized object + * name then as a class name. + *

+ * When using the {@code beanName} as a serialized object name we convert the + * given {@code beanName} to a resource pathname and add a trailing ".ser" suffix. + * We then try to load a serialized object from that resource. + *

+ * For example, given a {@code beanName} of "x.y", {@code Beans.instantiate} would first + * try to read a serialized object from the resource "x/y.ser" and if + * that failed it would try to load the class "x.y" and create an + * instance of that class. + * * @return a JavaBean * @param cls the class-loader from which we should create * the bean. If this is null, then the system @@ -84,6 +100,22 @@ public static Object instantiate(ClassLoader cls, String beanName) throws IOExce *

* Instantiate a JavaBean. *

+ * The bean is created based on a name relative to a class-loader. + * This name should be a {@linkplain ClassLoader##binary-name binary name} of a class such as "a.b.C". + *

+ * The given name can indicate either a serialized object or a class. + * We first try to treat the {@code beanName} as a serialized object + * name then as a class name. + *

+ * When using the {@code beanName} as a serialized object name we convert the + * given {@code beanName} to a resource pathname and add a trailing ".ser" suffix. + * We then try to load a serialized object from that resource. + *

+ * For example, given a {@code beanName} of "x.y", {@code Beans.instantiate} would first + * try to read a serialized object from the resource "x/y.ser" and if + * that failed it would try to load the class "x.y" and create an + * instance of that class. + * * @return a JavaBean * * @param cls the class-loader from which we should create diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java index e518f509c5a..6fab795e36c 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.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 @@ -377,6 +377,7 @@ public void menuKeyPressed(MenuKeyEvent e) { } else if (item.isEnabled()) { // we have a menu item manager.clearSelectedPath(); + sun.awt.SunToolkit.consumeNextKeyTyped(e); item.doClick(); } e.consume(); diff --git a/src/java.desktop/share/classes/sun/java2d/pipe/OutlineTextRenderer.java b/src/java.desktop/share/classes/sun/java2d/pipe/OutlineTextRenderer.java index b657e434d2f..949a914990b 100644 --- a/src/java.desktop/share/classes/sun/java2d/pipe/OutlineTextRenderer.java +++ b/src/java.desktop/share/classes/sun/java2d/pipe/OutlineTextRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, 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 @@ -73,8 +73,8 @@ public void drawChars(SunGraphics2D g2d, public void drawString(SunGraphics2D g2d, String str, double x, double y) { - if ("".equals(str)) { - return; // TextLayout constructor throws IAE on "". + if (str.length() == 0) { + return; } TextLayout tl = new TextLayout(str, g2d.getFont(), g2d.getFontRenderContext()); diff --git a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index 2a6d45e2ba8..754af87b94e 100644 --- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -2470,13 +2470,16 @@ protected void initPrinterGraphics(Graphics2D g, Rectangle2D clip) { g.setPaint(Color.black); } - /* On-screen drawString renders most control chars as the missing glyph - * and have the non-zero advance of that glyph. - * Exceptions are \t, \n and \r which are considered zero-width. - * This is a utility method used by subclasses to remove them so we - * don't have to worry about platform or font specific handling of them. + /** + * Removes ignorable whitespace from the specified text, so that there + * is no need for platform-specific or font-specific custom whitespace + * handling, and so that these characters are not treated like control + * characters which are printed as the missing glyph. + * + * @param s the text to process + * @return the input text, with ignorable whitespace (if any) removed */ - protected String removeControlChars(String s) { + public static String removeControlChars(String s) { char[] in_chars = s.toCharArray(); int len = in_chars.length; char[] out_chars = new char[len]; diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WPathGraphics.java b/src/java.desktop/windows/classes/sun/awt/windows/WPathGraphics.java index 75e8fa42da0..87b1591c0eb 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WPathGraphics.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WPathGraphics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, 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 @@ -73,6 +73,7 @@ import sun.print.PathGraphics; import sun.print.ProxyGraphics2D; +import sun.print.RasterPrinterJob; final class WPathGraphics extends PathGraphics { @@ -847,7 +848,7 @@ private void textOut(String str, * removed now so the string and positions are the same length. * For other cases we need to pass glyph codes to GDI. */ - str = wPrinterJob.removeControlChars(str); + str = RasterPrinterJob.removeControlChars(str); char[] chars = str.toCharArray(); int len = chars.length; GlyphVector gv = null; diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java b/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java index e50cfcff33b..17d41036bcc 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.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 @@ -1202,14 +1202,6 @@ protected void setTextColor(Color color) { } } - /** - * Remove control characters. - */ - @Override - protected String removeControlChars(String str) { - return super.removeControlChars(str); - } - /** * Draw the string {@code text} to the printer's * device context at the specified position. diff --git a/src/java.scripting/share/classes/javax/script/ScriptException.java b/src/java.scripting/share/classes/javax/script/ScriptException.java index 1037ccde27f..48fb3221914 100644 --- a/src/java.scripting/share/classes/javax/script/ScriptException.java +++ b/src/java.scripting/share/classes/javax/script/ScriptException.java @@ -25,6 +25,8 @@ package javax.script; +import java.io.Serial; + /** * The generic Exception class for the Scripting APIs. Checked * exception types thrown by underlying scripting implementations must be wrapped in instances of @@ -36,6 +38,7 @@ */ public class ScriptException extends Exception { + @Serial private static final long serialVersionUID = 8265071037049225001L; /** @serial */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Const.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Const.java index bca72ab3f95..c6b97db142e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Const.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Const.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -26,12 +26,12 @@ * Constants for the project, mostly defined in the JVM specification. * * @since 6.0 (intended to replace the Constants interface) - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class Const { /** - * Java class file format Magic number (0xCAFEBABE) + * Java class file format Magic number: {@value}. * * @see The ClassFile Structure * in The Java Virtual Machine Specification @@ -39,201 +39,201 @@ public final class Const { public static final int JVM_CLASSFILE_MAGIC = 0xCAFEBABE; /** - * Major version number of class files for Java 1.1. + * Major version number of class files for Java 1.1: {@value}. * * @see #MINOR_1_1 */ public static final short MAJOR_1_1 = 45; /** - * Minor version number of class files for Java 1.1. + * Minor version number of class files for Java 1.1: {@value}. * * @see #MAJOR_1_1 */ public static final short MINOR_1_1 = 3; /** - * Major version number of class files for Java 1.2. + * Major version number of class files for Java 1.2: {@value}. * * @see #MINOR_1_2 */ public static final short MAJOR_1_2 = 46; /** - * Minor version number of class files for Java 1.2. + * Minor version number of class files for Java 1.2: {@value}. * * @see #MAJOR_1_2 */ public static final short MINOR_1_2 = 0; /** - * Major version number of class files for Java 1.2. + * Major version number of class files for Java 1.2: {@value}. * * @see #MINOR_1_2 */ public static final short MAJOR_1_3 = 47; /** - * Minor version number of class files for Java 1.3. + * Minor version number of class files for Java 1.3: {@value}. * * @see #MAJOR_1_3 */ public static final short MINOR_1_3 = 0; /** - * Major version number of class files for Java 1.3. + * Major version number of class files for Java 1.3: {@value}. * * @see #MINOR_1_3 */ public static final short MAJOR_1_4 = 48; /** - * Minor version number of class files for Java 1.4. + * Minor version number of class files for Java 1.4: {@value}. * * @see #MAJOR_1_4 */ public static final short MINOR_1_4 = 0; /** - * Major version number of class files for Java 1.4. + * Major version number of class files for Java 1.4: {@value}. * * @see #MINOR_1_4 */ public static final short MAJOR_1_5 = 49; /** - * Minor version number of class files for Java 1.5. + * Minor version number of class files for Java 1.5: {@value}. * * @see #MAJOR_1_5 */ public static final short MINOR_1_5 = 0; /** - * Major version number of class files for Java 1.6. + * Major version number of class files for Java 1.6: {@value}. * * @see #MINOR_1_6 */ public static final short MAJOR_1_6 = 50; /** - * Minor version number of class files for Java 1.6. + * Minor version number of class files for Java 1.6: {@value}. * * @see #MAJOR_1_6 */ public static final short MINOR_1_6 = 0; /** - * Major version number of class files for Java 1.7. + * Major version number of class files for Java 1.7: {@value}. * * @see #MINOR_1_7 */ public static final short MAJOR_1_7 = 51; /** - * Minor version number of class files for Java 1.7. + * Minor version number of class files for Java 1.7: {@value}. * * @see #MAJOR_1_7 */ public static final short MINOR_1_7 = 0; /** - * Major version number of class files for Java 1.8. + * Major version number of class files for Java 1.8: {@value}. * * @see #MINOR_1_8 */ public static final short MAJOR_1_8 = 52; /** - * Minor version number of class files for Java 1.8. + * Minor version number of class files for Java 1.8: {@value}. * * @see #MAJOR_1_8 */ public static final short MINOR_1_8 = 0; /** - * Major version number of class files for Java 9. + * Major version number of class files for Java 9: {@value}. * * @see #MINOR_9 */ public static final short MAJOR_9 = 53; /** - * Minor version number of class files for Java 9. + * Minor version number of class files for Java 9: {@value}. * * @see #MAJOR_9 */ public static final short MINOR_9 = 0; /** - * @deprecated Use {@link #MAJOR_9} instead + * @deprecated Use {@link #MAJOR_9} ({@value}) instead. */ @Deprecated public static final short MAJOR_1_9 = MAJOR_9; /** - * @deprecated Use {@link #MINOR_9} instead + * @deprecated Use {@link #MINOR_9} ({@value}) instead. */ @Deprecated public static final short MINOR_1_9 = MINOR_9; /** - * Major version number of class files for Java 10. + * Major version number of class files for Java 10: {@value}. * * @see #MINOR_10 */ public static final short MAJOR_10 = 54; /** - * Minor version number of class files for Java 10. + * Minor version number of class files for Java 10: {@value}. * * @see #MAJOR_10 */ public static final short MINOR_10 = 0; /** - * Major version number of class files for Java 11. + * Major version number of class files for Java 11: {@value}. * * @see #MINOR_11 */ public static final short MAJOR_11 = 55; /** - * Minor version number of class files for Java 11. + * Minor version number of class files for Java 11: {@value}. * * @see #MAJOR_11 */ public static final short MINOR_11 = 0; /** - * Major version number of class files for Java 12. + * Major version number of class files for Java 12: {@value}. * * @see #MINOR_12 */ public static final short MAJOR_12 = 56; /** - * Minor version number of class files for Java 12. + * Minor version number of class files for Java 12: {@value}. * * @see #MAJOR_12 */ public static final short MINOR_12 = 0; /** - * Major version number of class files for Java 13. + * Major version number of class files for Java 13: {@value}. * * @see #MINOR_13 */ public static final short MAJOR_13 = 57; /** - * Minor version number of class files for Java 13. + * Minor version number of class files for Java 13: {@value}. * * @see #MAJOR_13 */ public static final short MINOR_13 = 0; /** - * Minor version number of class files for Java 14. + * Minor version number of class files for Java 14: {@value}. * * @see #MAJOR_14 * @since 6.4.0 @@ -241,7 +241,7 @@ public final class Const { public static final short MINOR_14 = 0; /** - * Minor version number of class files for Java 15. + * Minor version number of class files for Java 15: {@value}. * * @see #MAJOR_15 * @since 6.6.0 @@ -249,7 +249,7 @@ public final class Const { public static final short MINOR_15 = 0; /** - * Minor version number of class files for Java 16. + * Minor version number of class files for Java 16: {@value}. * * @see #MAJOR_16 * @since 6.6.0 @@ -257,7 +257,7 @@ public final class Const { public static final short MINOR_16 = 0; /** - * Minor version number of class files for Java 17. + * Minor version number of class files for Java 17: {@value}. * * @see #MAJOR_17 * @since 6.6.0 @@ -265,7 +265,7 @@ public final class Const { public static final short MINOR_17 = 0; /** - * Minor version number of class files for Java 18. + * Minor version number of class files for Java 18: {@value}. * * @see #MAJOR_18 * @since 6.6.0 @@ -273,7 +273,7 @@ public final class Const { public static final short MINOR_18 = 0; /** - * Minor version number of class files for Java 19. + * Minor version number of class files for Java 19: {@value}. * * @see #MAJOR_19 * @since 6.6.0 @@ -281,7 +281,47 @@ public final class Const { public static final short MINOR_19 = 0; /** - * Major version number of class files for Java 14. + * Minor version number of class files for Java 20: {@value}. + * + * @see #MAJOR_20 + * @since 6.8.0 + */ + public static final short MINOR_20 = 0; + + /** + * Minor version number of class files for Java 21: {@value}. + * + * @see #MAJOR_21 + * @since 6.8.0 + */ + public static final short MINOR_21 = 0; + + /** + * Minor version number of class files for Java 22: {@value}. + * + * @see #MAJOR_22 + * @since 6.10.0 + */ + public static final short MINOR_22 = 0; + + /** + * Minor version number of class files for Java 23: {@value}. + * + * @see #MAJOR_23 + * @since 6.10.0 + */ + public static final short MINOR_23 = 0; + + /** + * Minor version number of class files for Java 24: {@value}. + * + * @see #MAJOR_24 + * @since 6.10.0 + */ + public static final short MINOR_24 = 0; + + /** + * Major version number of class files for Java 14: {@value}. * * @see #MINOR_14 * @since 6.4.0 @@ -289,7 +329,7 @@ public final class Const { public static final short MAJOR_14 = 58; /** - * Major version number of class files for Java 15. + * Major version number of class files for Java 15: {@value}. * * @see #MINOR_15 * @since 6.6.0 @@ -297,7 +337,7 @@ public final class Const { public static final short MAJOR_15 = 59; /** - * Major version number of class files for Java 16. + * Major version number of class files for Java 16: {@value}. * * @see #MINOR_16 * @since 6.6.0 @@ -305,7 +345,7 @@ public final class Const { public static final short MAJOR_16 = 60; /** - * Major version number of class files for Java 17. + * Major version number of class files for Java 17: {@value}. * * @see #MINOR_17 * @since 6.6.0 @@ -313,7 +353,7 @@ public final class Const { public static final short MAJOR_17 = 61; /** - * Major version number of class files for Java 18. + * Major version number of class files for Java 18: {@value}. * * @see #MINOR_18 * @since 6.6.0 @@ -321,7 +361,7 @@ public final class Const { public static final short MAJOR_18 = 62; /** - * Major version number of class files for Java 19. + * Major version number of class files for Java 19: {@value}. * * @see #MINOR_19 * @since 6.6.0 @@ -329,31 +369,71 @@ public final class Const { public static final short MAJOR_19 = 63; /** - * Default major version number. Class file is for Java 1.1. + * Major version number of class files for Java 20: {@value}. + * + * @see #MINOR_20 + * @since 6.8.0 + */ + public static final short MAJOR_20 = 64; + + /** + * Major version number of class files for Java 21: {@value}. + * + * @see #MINOR_21 + * @since 6.8.0 + */ + public static final short MAJOR_21 = 65; + + /** + * Major version number of class files for Java 22: {@value}. + * + * @see #MINOR_22 + * @since 6.10.0 + */ + public static final short MAJOR_22 = 66; + + /** + * Major version number of class files for Java 23: {@value}. + * + * @see #MINOR_23 + * @since 6.10.0 + */ + public static final short MAJOR_23 = 67; + + /** + * Major version number of class files for Java 24: {@value}. + * + * @see #MINOR_24 + * @since 6.10.0 + */ + public static final short MAJOR_24 = 68; + + /** + * Default major version number. Class file is for Java 1.1: {@value}. * * @see #MAJOR_1_1 */ public static final short MAJOR = MAJOR_1_1; /** - * Default major version number. Class file is for Java 1.1. + * Default major version number. Class file is for Java 1.1: {@value}. * * @see #MAJOR_1_1 */ public static final short MINOR = MINOR_1_1; /** - * Maximum value for an unsigned short. + * Maximum value for an unsigned short: {@value}. */ public static final int MAX_SHORT = 65535; // 2^16 - 1 /** - * Maximum value for an unsigned byte. + * Maximum value for an unsigned byte: {@value}. */ public static final int MAX_BYTE = 255; // 2^8 - 1 /** - * One of the access flags for fields, methods, or classes. + * One of the access flags for fields, methods, or classes: {@value}. * * @see Flag definitions for * Classes in the Java Virtual Machine Specification (Java SE 9 Edition). @@ -367,140 +447,140 @@ public final class Const { public static final short ACC_PUBLIC = 0x0001; /** - * One of the access flags for fields, methods, or classes. + * One of the access flags for fields, methods, or classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_PRIVATE = 0x0002; /** - * One of the access flags for fields, methods, or classes. + * One of the access flags for fields, methods, or classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_PROTECTED = 0x0004; /** - * One of the access flags for fields, methods, or classes. + * One of the access flags for fields, methods, or classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_STATIC = 0x0008; /** - * One of the access flags for fields, methods, or classes. + * One of the access flags for fields, methods, or classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_FINAL = 0x0010; /** - * One of the access flags for the Module attribute. + * One of the access flags for the Module attribute: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_OPEN = 0x0020; /** - * One of the access flags for classes. + * One of the access flags for classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_SUPER = 0x0020; /** - * One of the access flags for methods. + * One of the access flags for methods: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_SYNCHRONIZED = 0x0020; /** - * One of the access flags for the Module attribute. + * One of the access flags for the Module attribute: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_TRANSITIVE = 0x0020; /** - * One of the access flags for methods. + * One of the access flags for methods: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_BRIDGE = 0x0040; /** - * One of the access flags for the Module attribute. + * One of the access flags for the Module attribute: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_STATIC_PHASE = 0x0040; /** - * One of the access flags for fields. + * One of the access flags for fields: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_VOLATILE = 0x0040; /** - * One of the access flags for fields. + * One of the access flags for fields: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_TRANSIENT = 0x0080; /** - * One of the access flags for methods. + * One of the access flags for methods: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_VARARGS = 0x0080; /** - * One of the access flags for methods. + * One of the access flags for methods: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_NATIVE = 0x0100; /** - * One of the access flags for classes. + * One of the access flags for classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_INTERFACE = 0x0200; /** - * One of the access flags for methods or classes. + * One of the access flags for methods or classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_ABSTRACT = 0x0400; /** - * One of the access flags for methods. + * One of the access flags for methods: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_STRICT = 0x0800; /** - * One of the access flags for fields, methods, classes, MethodParameter attribute, or Module attribute. + * One of the access flags for fields, methods, classes, MethodParameter attribute, or Module attribute: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_SYNTHETIC = 0x1000; /** - * One of the access flags for classes. + * One of the access flags for classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_ANNOTATION = 0x2000; /** - * One of the access flags for fields or classes. + * One of the access flags for fields or classes: {@value}. * * @see #ACC_PUBLIC */ @@ -508,21 +588,21 @@ public final class Const { // Applies to classes compiled by new compilers only /** - * One of the access flags for MethodParameter or Module attributes. + * One of the access flags for MethodParameter or Module attributes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_MANDATED = (short) 0x8000; /** - * One of the access flags for classes. + * One of the access flags for classes: {@value}. * * @see #ACC_PUBLIC */ public static final short ACC_MODULE = (short) 0x8000; /** - * One of the access flags for fields, methods, or classes. + * One of the access flags for fields, methods, or classes: {@value}. * * @see #ACC_PUBLIC * @deprecated Use {@link #MAX_ACC_FLAG_I} @@ -531,7 +611,7 @@ public final class Const { public static final short MAX_ACC_FLAG = ACC_ENUM; /** - * One of the access flags for fields, methods, or classes. ACC_MODULE is negative as a short. + * One of the access flags for fields, methods, or classes. ACC_MODULE is negative as a short: {@value}. * * @see #ACC_PUBLIC * @since 6.4.0 @@ -553,7 +633,7 @@ public final class Const { public static final int ACCESS_NAMES_LENGTH = ACCESS_NAMES.length; /** - * Marks a constant pool entry as type UTF-8. + * Marks a constant pool entry as type UTF-8: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -566,7 +646,7 @@ public final class Const { */ /** - * Marks a constant pool entry as type Integer. + * Marks a constant pool entry as type Integer: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -574,7 +654,7 @@ public final class Const { public static final byte CONSTANT_Integer = 3; /** - * Marks a constant pool entry as type Float. + * Marks a constant pool entry as type Float: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -582,7 +662,7 @@ public final class Const { public static final byte CONSTANT_Float = 4; /** - * Marks a constant pool entry as type Long. + * Marks a constant pool entry as type Long: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -590,7 +670,7 @@ public final class Const { public static final byte CONSTANT_Long = 5; /** - * Marks a constant pool entry as type Double. + * Marks a constant pool entry as type Double: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -598,7 +678,7 @@ public final class Const { public static final byte CONSTANT_Double = 6; /** - * Marks a constant pool entry as a Class + * Marks a constant pool entry as a Class: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -606,7 +686,7 @@ public final class Const { public static final byte CONSTANT_Class = 7; /** - * Marks a constant pool entry as a Field Reference. + * Marks a constant pool entry as a Field Reference: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -614,7 +694,7 @@ public final class Const { public static final byte CONSTANT_Fieldref = 9; /** - * Marks a constant pool entry as type String + * Marks a constant pool entry as type String: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -622,7 +702,7 @@ public final class Const { public static final byte CONSTANT_String = 8; /** - * Marks a constant pool entry as a Method Reference. + * Marks a constant pool entry as a Method Reference: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -630,7 +710,7 @@ public final class Const { public static final byte CONSTANT_Methodref = 10; /** - * Marks a constant pool entry as an Interface Method Reference. + * Marks a constant pool entry as an Interface Method Reference: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -638,7 +718,7 @@ public final class Const { public static final byte CONSTANT_InterfaceMethodref = 11; /** - * Marks a constant pool entry as a name and type. + * Marks a constant pool entry as a name and type: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -646,7 +726,7 @@ public final class Const { public static final byte CONSTANT_NameAndType = 12; /** - * Marks a constant pool entry as a Method Handle. + * Marks a constant pool entry as a Method Handle: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -654,7 +734,7 @@ public final class Const { public static final byte CONSTANT_MethodHandle = 15; /** - * Marks a constant pool entry as a Method Type. + * Marks a constant pool entry as a Method Type: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -662,16 +742,16 @@ public final class Const { public static final byte CONSTANT_MethodType = 16; /** - * Marks a constant pool entry as dynamically computed. + * Marks a constant pool entry as dynamically computed: {@value}. * - * @see Change request for JEP - * 309 + * @see The Constant Pool in The + * Java Virtual Machine Specification * @since 6.3 */ public static final byte CONSTANT_Dynamic = 17; /** - * Marks a constant pool entry as an Invoke Dynamic + * Marks a constant pool entry as an Invoke Dynamic: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -679,7 +759,7 @@ public final class Const { public static final byte CONSTANT_InvokeDynamic = 18; /** - * Marks a constant pool entry as a Module Reference. + * Marks a constant pool entry as a Module Reference: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -688,7 +768,7 @@ public final class Const { public static final byte CONSTANT_Module = 19; /** - * Marks a constant pool entry as a Package Reference. + * Marks a constant pool entry as a Package Reference: {@value}. * * @see The Constant Pool in The * Java Virtual Machine Specification @@ -705,23 +785,23 @@ public final class Const { /** * The name of the static initializer, also called "class initialization method" or "interface - * initialization method". This is "<clinit>". + * initialization method". This is {@value}. */ public static final String STATIC_INITIALIZER_NAME = ""; /** * The name of every constructor method in a class, also called "instance initialization method". This is - * "<init>". + * {@value}. */ public static final String CONSTRUCTOR_NAME = ""; /** - * The names of the interfaces implemented by arrays + * The names of the interfaces implemented by arrays. */ private static final String[] INTERFACES_IMPLEMENTED_BY_ARRAYS = {"java.lang.Cloneable", "java.io.Serializable"}; /** - * Maximum Constant Pool entries. One of the limitations of the Java Virtual Machine. + * Maximum Constant Pool entries: {@value}. One of the limitations of the Java Virtual Machine. * * @see The Java Virtual * Machine Specification, Java SE 8 Edition, page 330, chapter 4.11. @@ -729,21 +809,25 @@ public final class Const { public static final int MAX_CP_ENTRIES = 65535; /** - * Maximum code size (plus one; the code size must be LESS than this) One of the limitations of the Java Virtual - * Machine. Note vmspec2 page 152 ("Limitations") says: "The amount of code per non-native, non-abstract method is - * limited to 65536 bytes by the sizes of the indices in the exception_table of the Code attribute (4.7.3), in the - * LineNumberTable attribute (4.7.8), and in the LocalVariableTable attribute (4.7.9)." However this should be taken - * as an upper limit rather than the defined maximum. On page 134 (4.8.1 Static Constants) of the same spec, it says: - * "The value of the code_length item must be less than 65536." The entry in the Limitations section has been removed - * from later versions of the spec; it is not present in the Java SE 8 edition. + * Maximum code size (plus one; the code size must be LESS than this): {@value}. + *

+ * One of the limitations of the Java Virtual Machine. Note vmspec2 page 152 ("Limitations") says: + *

+ *
"The amount of code per non-native, non-abstract method is limited to 65536 bytes by the sizes of the indices in the exception_table of the Code
+     * attribute (4.7.3), in the LineNumberTable attribute (4.7.8), and in the LocalVariableTable attribute (4.7.9)." However this should be taken as an
+     * upper limit rather than the defined maximum. On page 134 (4.8.1 Static Constants) of the same spec, it says: "The value of the code_length item must be
+     * less than 65536."
+ *

+ * The entry in the Limitations section has been removed from later versions of the specification; it is not present in the Java SE 8 edition. + *

* - * @see The Java Virtual - * Machine Specification, Java SE 8 Edition, page 104, chapter 4.7. + * @see The Java Virtual Machine Specification, Java SE 8 + * Edition, page 104, chapter 4.7. */ public static final int MAX_CODE_SIZE = 65536; // bytes /** - * The maximum number of dimensions in an array ({@value}). One of the limitations of the Java Virtual Machine. + * The maximum number of dimensions in an array: {@value}. One of the limitations of the Java Virtual Machine. * * @see Field Descriptors in * The Java Virtual Machine Specification @@ -751,7 +835,7 @@ public final class Const { public static final int MAX_ARRAY_DIMENSIONS = 255; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -759,7 +843,7 @@ public final class Const { public static final short NOP = 0; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -767,7 +851,7 @@ public final class Const { public static final short ACONST_NULL = 1; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -775,7 +859,7 @@ public final class Const { public static final short ICONST_M1 = 2; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -783,7 +867,7 @@ public final class Const { public static final short ICONST_0 = 3; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -791,7 +875,7 @@ public final class Const { public static final short ICONST_1 = 4; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -799,7 +883,7 @@ public final class Const { public static final short ICONST_2 = 5; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -807,7 +891,7 @@ public final class Const { public static final short ICONST_3 = 6; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -815,7 +899,7 @@ public final class Const { public static final short ICONST_4 = 7; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -823,7 +907,7 @@ public final class Const { public static final short ICONST_5 = 8; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -831,7 +915,7 @@ public final class Const { public static final short LCONST_0 = 9; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -839,7 +923,7 @@ public final class Const { public static final short LCONST_1 = 10; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -847,7 +931,7 @@ public final class Const { public static final short FCONST_0 = 11; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -855,7 +939,7 @@ public final class Const { public static final short FCONST_1 = 12; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -863,7 +947,7 @@ public final class Const { public static final short FCONST_2 = 13; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -871,7 +955,7 @@ public final class Const { public static final short DCONST_0 = 14; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -879,7 +963,7 @@ public final class Const { public static final short DCONST_1 = 15; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -887,7 +971,7 @@ public final class Const { public static final short BIPUSH = 16; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -895,7 +979,7 @@ public final class Const { public static final short SIPUSH = 17; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -903,7 +987,7 @@ public final class Const { public static final short LDC = 18; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -911,7 +995,7 @@ public final class Const { public static final short LDC_W = 19; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -919,7 +1003,7 @@ public final class Const { public static final short LDC2_W = 20; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -927,7 +1011,7 @@ public final class Const { public static final short ILOAD = 21; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -935,7 +1019,7 @@ public final class Const { public static final short LLOAD = 22; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -943,7 +1027,7 @@ public final class Const { public static final short FLOAD = 23; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -951,7 +1035,7 @@ public final class Const { public static final short DLOAD = 24; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -959,7 +1043,7 @@ public final class Const { public static final short ALOAD = 25; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -967,7 +1051,7 @@ public final class Const { public static final short ILOAD_0 = 26; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -975,7 +1059,7 @@ public final class Const { public static final short ILOAD_1 = 27; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -983,7 +1067,7 @@ public final class Const { public static final short ILOAD_2 = 28; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -991,7 +1075,7 @@ public final class Const { public static final short ILOAD_3 = 29; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -999,7 +1083,7 @@ public final class Const { public static final short LLOAD_0 = 30; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1007,7 +1091,7 @@ public final class Const { public static final short LLOAD_1 = 31; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1015,7 +1099,7 @@ public final class Const { public static final short LLOAD_2 = 32; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1023,7 +1107,7 @@ public final class Const { public static final short LLOAD_3 = 33; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1031,7 +1115,7 @@ public final class Const { public static final short FLOAD_0 = 34; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1039,7 +1123,7 @@ public final class Const { public static final short FLOAD_1 = 35; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1047,7 +1131,7 @@ public final class Const { public static final short FLOAD_2 = 36; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1055,7 +1139,7 @@ public final class Const { public static final short FLOAD_3 = 37; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1063,7 +1147,7 @@ public final class Const { public static final short DLOAD_0 = 38; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1071,7 +1155,7 @@ public final class Const { public static final short DLOAD_1 = 39; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1079,7 +1163,7 @@ public final class Const { public static final short DLOAD_2 = 40; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1087,7 +1171,7 @@ public final class Const { public static final short DLOAD_3 = 41; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1095,7 +1179,7 @@ public final class Const { public static final short ALOAD_0 = 42; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1103,7 +1187,7 @@ public final class Const { public static final short ALOAD_1 = 43; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1111,7 +1195,7 @@ public final class Const { public static final short ALOAD_2 = 44; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1119,7 +1203,7 @@ public final class Const { public static final short ALOAD_3 = 45; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1127,7 +1211,7 @@ public final class Const { public static final short IALOAD = 46; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1135,7 +1219,7 @@ public final class Const { public static final short LALOAD = 47; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1143,7 +1227,7 @@ public final class Const { public static final short FALOAD = 48; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1151,7 +1235,7 @@ public final class Const { public static final short DALOAD = 49; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1159,7 +1243,7 @@ public final class Const { public static final short AALOAD = 50; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1167,7 +1251,7 @@ public final class Const { public static final short BALOAD = 51; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1175,7 +1259,7 @@ public final class Const { public static final short CALOAD = 52; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1183,7 +1267,7 @@ public final class Const { public static final short SALOAD = 53; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1191,7 +1275,7 @@ public final class Const { public static final short ISTORE = 54; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1199,7 +1283,7 @@ public final class Const { public static final short LSTORE = 55; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1207,7 +1291,7 @@ public final class Const { public static final short FSTORE = 56; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1215,7 +1299,7 @@ public final class Const { public static final short DSTORE = 57; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1223,7 +1307,7 @@ public final class Const { public static final short ASTORE = 58; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1231,7 +1315,7 @@ public final class Const { public static final short ISTORE_0 = 59; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1239,7 +1323,7 @@ public final class Const { public static final short ISTORE_1 = 60; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1247,7 +1331,7 @@ public final class Const { public static final short ISTORE_2 = 61; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1255,7 +1339,7 @@ public final class Const { public static final short ISTORE_3 = 62; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1263,7 +1347,7 @@ public final class Const { public static final short LSTORE_0 = 63; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1271,7 +1355,7 @@ public final class Const { public static final short LSTORE_1 = 64; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1279,7 +1363,7 @@ public final class Const { public static final short LSTORE_2 = 65; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1287,7 +1371,7 @@ public final class Const { public static final short LSTORE_3 = 66; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1295,7 +1379,7 @@ public final class Const { public static final short FSTORE_0 = 67; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1303,7 +1387,7 @@ public final class Const { public static final short FSTORE_1 = 68; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1311,7 +1395,7 @@ public final class Const { public static final short FSTORE_2 = 69; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1319,7 +1403,7 @@ public final class Const { public static final short FSTORE_3 = 70; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1327,7 +1411,7 @@ public final class Const { public static final short DSTORE_0 = 71; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1335,7 +1419,7 @@ public final class Const { public static final short DSTORE_1 = 72; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1343,7 +1427,7 @@ public final class Const { public static final short DSTORE_2 = 73; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1351,7 +1435,7 @@ public final class Const { public static final short DSTORE_3 = 74; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1359,7 +1443,7 @@ public final class Const { public static final short ASTORE_0 = 75; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1367,7 +1451,7 @@ public final class Const { public static final short ASTORE_1 = 76; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1375,7 +1459,7 @@ public final class Const { public static final short ASTORE_2 = 77; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -1383,7 +1467,7 @@ public final class Const { public static final short ASTORE_3 = 78; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1391,7 +1475,7 @@ public final class Const { public static final short IASTORE = 79; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1399,7 +1483,7 @@ public final class Const { public static final short LASTORE = 80; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1407,7 +1491,7 @@ public final class Const { public static final short FASTORE = 81; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1415,7 +1499,7 @@ public final class Const { public static final short DASTORE = 82; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1423,7 +1507,7 @@ public final class Const { public static final short AASTORE = 83; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1431,7 +1515,7 @@ public final class Const { public static final short BASTORE = 84; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1439,7 +1523,7 @@ public final class Const { public static final short CASTORE = 85; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1447,7 +1531,7 @@ public final class Const { public static final short SASTORE = 86; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1455,7 +1539,7 @@ public final class Const { public static final short POP = 87; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1463,7 +1547,7 @@ public final class Const { public static final short POP2 = 88; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1471,7 +1555,7 @@ public final class Const { public static final short DUP = 89; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1479,7 +1563,7 @@ public final class Const { public static final short DUP_X1 = 90; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1487,7 +1571,7 @@ public final class Const { public static final short DUP_X2 = 91; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1495,7 +1579,7 @@ public final class Const { public static final short DUP2 = 92; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1503,7 +1587,7 @@ public final class Const { public static final short DUP2_X1 = 93; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1511,7 +1595,7 @@ public final class Const { public static final short DUP2_X2 = 94; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1519,7 +1603,7 @@ public final class Const { public static final short SWAP = 95; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1527,7 +1611,7 @@ public final class Const { public static final short IADD = 96; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1535,7 +1619,7 @@ public final class Const { public static final short LADD = 97; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1543,7 +1627,7 @@ public final class Const { public static final short FADD = 98; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1551,7 +1635,7 @@ public final class Const { public static final short DADD = 99; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1559,7 +1643,7 @@ public final class Const { public static final short ISUB = 100; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1567,7 +1651,7 @@ public final class Const { public static final short LSUB = 101; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1575,7 +1659,7 @@ public final class Const { public static final short FSUB = 102; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1583,7 +1667,7 @@ public final class Const { public static final short DSUB = 103; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1591,7 +1675,7 @@ public final class Const { public static final short IMUL = 104; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1599,7 +1683,7 @@ public final class Const { public static final short LMUL = 105; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1607,7 +1691,7 @@ public final class Const { public static final short FMUL = 106; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1615,7 +1699,7 @@ public final class Const { public static final short DMUL = 107; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1623,7 +1707,7 @@ public final class Const { public static final short IDIV = 108; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1631,7 +1715,7 @@ public final class Const { public static final short LDIV = 109; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1639,7 +1723,7 @@ public final class Const { public static final short FDIV = 110; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1647,7 +1731,7 @@ public final class Const { public static final short DDIV = 111; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1655,7 +1739,7 @@ public final class Const { public static final short IREM = 112; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1663,7 +1747,7 @@ public final class Const { public static final short LREM = 113; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1671,7 +1755,7 @@ public final class Const { public static final short FREM = 114; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1679,7 +1763,7 @@ public final class Const { public static final short DREM = 115; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1687,7 +1771,7 @@ public final class Const { public static final short INEG = 116; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1695,7 +1779,7 @@ public final class Const { public static final short LNEG = 117; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1703,7 +1787,7 @@ public final class Const { public static final short FNEG = 118; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1711,7 +1795,7 @@ public final class Const { public static final short DNEG = 119; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1719,7 +1803,7 @@ public final class Const { public static final short ISHL = 120; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1727,7 +1811,7 @@ public final class Const { public static final short LSHL = 121; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1735,7 +1819,7 @@ public final class Const { public static final short ISHR = 122; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1743,7 +1827,7 @@ public final class Const { public static final short LSHR = 123; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1751,7 +1835,7 @@ public final class Const { public static final short IUSHR = 124; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1759,7 +1843,7 @@ public final class Const { public static final short LUSHR = 125; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1767,7 +1851,7 @@ public final class Const { public static final short IAND = 126; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1775,7 +1859,7 @@ public final class Const { public static final short LAND = 127; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1783,7 +1867,7 @@ public final class Const { public static final short IOR = 128; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1791,7 +1875,7 @@ public final class Const { public static final short LOR = 129; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1799,7 +1883,7 @@ public final class Const { public static final short IXOR = 130; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1807,7 +1891,7 @@ public final class Const { public static final short LXOR = 131; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1815,7 +1899,7 @@ public final class Const { public static final short IINC = 132; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1823,7 +1907,7 @@ public final class Const { public static final short I2L = 133; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1831,7 +1915,7 @@ public final class Const { public static final short I2F = 134; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1839,7 +1923,7 @@ public final class Const { public static final short I2D = 135; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1847,7 +1931,7 @@ public final class Const { public static final short L2I = 136; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1855,7 +1939,7 @@ public final class Const { public static final short L2F = 137; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1863,7 +1947,7 @@ public final class Const { public static final short L2D = 138; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1871,7 +1955,7 @@ public final class Const { public static final short F2I = 139; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1879,7 +1963,7 @@ public final class Const { public static final short F2L = 140; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1887,7 +1971,7 @@ public final class Const { public static final short F2D = 141; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1895,7 +1979,7 @@ public final class Const { public static final short D2I = 142; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1903,7 +1987,7 @@ public final class Const { public static final short D2L = 143; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1911,7 +1995,7 @@ public final class Const { public static final short D2F = 144; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1919,7 +2003,7 @@ public final class Const { public static final short I2B = 145; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1927,7 +2011,7 @@ public final class Const { public static final short INT2BYTE = 145; // Old notation /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1935,7 +2019,7 @@ public final class Const { public static final short I2C = 146; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1943,7 +2027,7 @@ public final class Const { public static final short INT2CHAR = 146; // Old notation /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1951,7 +2035,7 @@ public final class Const { public static final short I2S = 147; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -1959,7 +2043,7 @@ public final class Const { public static final short INT2SHORT = 147; // Old notation /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1967,7 +2051,7 @@ public final class Const { public static final short LCMP = 148; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1975,7 +2059,7 @@ public final class Const { public static final short FCMPL = 149; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1983,7 +2067,7 @@ public final class Const { public static final short FCMPG = 150; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1991,7 +2075,7 @@ public final class Const { public static final short DCMPL = 151; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -1999,7 +2083,7 @@ public final class Const { public static final short DCMPG = 152; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2007,7 +2091,7 @@ public final class Const { public static final short IFEQ = 153; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2015,7 +2099,7 @@ public final class Const { public static final short IFNE = 154; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2023,7 +2107,7 @@ public final class Const { public static final short IFLT = 155; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2031,7 +2115,7 @@ public final class Const { public static final short IFGE = 156; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2039,7 +2123,7 @@ public final class Const { public static final short IFGT = 157; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2047,7 +2131,7 @@ public final class Const { public static final short IFLE = 158; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2055,7 +2139,7 @@ public final class Const { public static final short IF_ICMPEQ = 159; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2063,7 +2147,7 @@ public final class Const { public static final short IF_ICMPNE = 160; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2071,7 +2155,7 @@ public final class Const { public static final short IF_ICMPLT = 161; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2079,7 +2163,7 @@ public final class Const { public static final short IF_ICMPGE = 162; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2087,7 +2171,7 @@ public final class Const { public static final short IF_ICMPGT = 163; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2095,7 +2179,7 @@ public final class Const { public static final short IF_ICMPLE = 164; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2103,7 +2187,7 @@ public final class Const { public static final short IF_ACMPEQ = 165; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2111,7 +2195,7 @@ public final class Const { public static final short IF_ACMPNE = 166; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2119,7 +2203,7 @@ public final class Const { public static final short GOTO = 167; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -2127,7 +2211,7 @@ public final class Const { public static final short JSR = 168; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -2135,7 +2219,7 @@ public final class Const { public static final short RET = 169; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2143,7 +2227,7 @@ public final class Const { public static final short TABLESWITCH = 170; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2151,7 +2235,7 @@ public final class Const { public static final short LOOKUPSWITCH = 171; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2159,7 +2243,7 @@ public final class Const { public static final short IRETURN = 172; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2167,7 +2251,7 @@ public final class Const { public static final short LRETURN = 173; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2175,7 +2259,7 @@ public final class Const { public static final short FRETURN = 174; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2183,7 +2267,7 @@ public final class Const { public static final short DRETURN = 175; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2191,7 +2275,7 @@ public final class Const { public static final short ARETURN = 176; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2199,7 +2283,7 @@ public final class Const { public static final short RETURN = 177; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2207,7 +2291,7 @@ public final class Const { public static final short GETSTATIC = 178; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2215,7 +2299,7 @@ public final class Const { public static final short PUTSTATIC = 179; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2223,7 +2307,7 @@ public final class Const { public static final short GETFIELD = 180; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2231,7 +2315,7 @@ public final class Const { public static final short PUTFIELD = 181; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2239,7 +2323,7 @@ public final class Const { public static final short INVOKEVIRTUAL = 182; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2247,7 +2331,7 @@ public final class Const { public static final short INVOKESPECIAL = 183; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -2255,7 +2339,7 @@ public final class Const { public static final short INVOKENONVIRTUAL = 183; // Old name in JDK 1.0 /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2263,7 +2347,7 @@ public final class Const { public static final short INVOKESTATIC = 184; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2271,7 +2355,7 @@ public final class Const { public static final short INVOKEINTERFACE = 185; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2279,7 +2363,7 @@ public final class Const { public static final short INVOKEDYNAMIC = 186; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in The * Java Virtual Machine Specification @@ -2287,7 +2371,7 @@ public final class Const { public static final short NEW = 187; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2295,7 +2379,7 @@ public final class Const { public static final short NEWARRAY = 188; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2303,7 +2387,7 @@ public final class Const { public static final short ANEWARRAY = 189; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2311,7 +2395,7 @@ public final class Const { public static final short ARRAYLENGTH = 190; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2319,7 +2403,7 @@ public final class Const { public static final short ATHROW = 191; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2327,7 +2411,7 @@ public final class Const { public static final short CHECKCAST = 192; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2335,7 +2419,7 @@ public final class Const { public static final short INSTANCEOF = 193; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2343,7 +2427,7 @@ public final class Const { public static final short MONITORENTER = 194; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2351,7 +2435,7 @@ public final class Const { public static final short MONITOREXIT = 195; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2359,7 +2443,7 @@ public final class Const { public static final short WIDE = 196; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode * definitions in The Java Virtual Machine Specification @@ -2367,7 +2451,7 @@ public final class Const { public static final short MULTIANEWARRAY = 197; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2375,7 +2459,7 @@ public final class Const { public static final short IFNULL = 198; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions * in The Java Virtual Machine Specification @@ -2383,7 +2467,7 @@ public final class Const { public static final short IFNONNULL = 199; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2391,7 +2475,7 @@ public final class Const { public static final short GOTO_W = 200; /** - * Java VM opcode. + * Java VM opcode {@value}. * * @see Opcode definitions in * The Java Virtual Machine Specification @@ -2399,7 +2483,7 @@ public final class Const { public static final short JSR_W = 201; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see Reserved opcodes in the Java * Virtual Machine Specification @@ -2407,7 +2491,7 @@ public final class Const { public static final short BREAKPOINT = 202; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2418,7 +2502,7 @@ public final class Const { public static final short LDC_QUICK = 203; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2429,7 +2513,7 @@ public final class Const { public static final short LDC_W_QUICK = 204; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2440,7 +2524,7 @@ public final class Const { public static final short LDC2_W_QUICK = 205; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2451,7 +2535,7 @@ public final class Const { public static final short GETFIELD_QUICK = 206; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2462,7 +2546,7 @@ public final class Const { public static final short PUTFIELD_QUICK = 207; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2473,7 +2557,7 @@ public final class Const { public static final short GETFIELD2_QUICK = 208; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2484,7 +2568,7 @@ public final class Const { public static final short PUTFIELD2_QUICK = 209; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2495,7 +2579,7 @@ public final class Const { public static final short GETSTATIC_QUICK = 210; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2506,7 +2590,7 @@ public final class Const { public static final short PUTSTATIC_QUICK = 211; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2517,7 +2601,7 @@ public final class Const { public static final short GETSTATIC2_QUICK = 212; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2528,7 +2612,7 @@ public final class Const { public static final short PUTSTATIC2_QUICK = 213; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2539,7 +2623,7 @@ public final class Const { public static final short INVOKEVIRTUAL_QUICK = 214; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2550,7 +2634,7 @@ public final class Const { public static final short INVOKENONVIRTUAL_QUICK = 215; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2561,7 +2645,7 @@ public final class Const { public static final short INVOKESUPER_QUICK = 216; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2572,7 +2656,7 @@ public final class Const { public static final short INVOKESTATIC_QUICK = 217; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2583,7 +2667,7 @@ public final class Const { public static final short INVOKEINTERFACE_QUICK = 218; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2594,7 +2678,7 @@ public final class Const { public static final short INVOKEVIRTUALOBJECT_QUICK = 219; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2605,7 +2689,7 @@ public final class Const { public static final short NEW_QUICK = 221; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2616,7 +2700,7 @@ public final class Const { public static final short ANEWARRAY_QUICK = 222; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2627,7 +2711,7 @@ public final class Const { public static final short MULTIANEWARRAY_QUICK = 223; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2638,7 +2722,7 @@ public final class Const { public static final short CHECKCAST_QUICK = 224; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2649,7 +2733,7 @@ public final class Const { public static final short INSTANCEOF_QUICK = 225; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2660,7 +2744,7 @@ public final class Const { public static final short INVOKEVIRTUAL_QUICK_W = 226; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2671,7 +2755,7 @@ public final class Const { public static final short GETFIELD_QUICK_W = 227; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see @@ -2682,7 +2766,7 @@ public final class Const { public static final short PUTFIELD_QUICK_W = 228; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see Reserved opcodes in the Java * Virtual Machine Specification @@ -2690,7 +2774,7 @@ public final class Const { public static final short IMPDEP1 = 254; /** - * JVM internal opcode. + * JVM internal opcode {@value}. * * @see Reserved opcodes in the Java * Virtual Machine Specification @@ -2698,34 +2782,44 @@ public final class Const { public static final short IMPDEP2 = 255; /** - * BCEL virtual instruction for pushing an arbitrary data type onto the stack. Will be converted to the appropriate JVM + * BCEL virtual instruction for pushing an arbitrary data type onto the stack: {@value}. Will be converted to the appropriate JVM * opcode when the class is dumped. */ public static final short PUSH = 4711; /** - * BCEL virtual instruction for either LOOKUPSWITCH or TABLESWITCH. Will be converted to the appropriate JVM opcode when + * BCEL virtual instruction for either LOOKUPSWITCH or TABLESWITCH: {@value}. Will be converted to the appropriate JVM opcode when * the class is dumped. */ public static final short SWITCH = 4712; - /** Illegal opcode. */ + /** + * Illegal opcode: {@value}. + */ public static final short UNDEFINED = -1; - /** Illegal opcode. */ + /** + * Illegal opcode: {@value}. + */ public static final short UNPREDICTABLE = -2; - /** Illegal opcode. */ + /** + * Illegal opcode: {@value}. + */ public static final short RESERVED = -3; - /** Mnemonic for an illegal opcode. */ + /** + * Mnemonic for an illegal opcode: {@value}. + */ public static final String ILLEGAL_OPCODE = ""; - /** Mnemonic for an illegal type. */ + /** + * Mnemonic for an illegal type: {@value}. + */ public static final String ILLEGAL_TYPE = ""; /** - * Boolean data type. + * Boolean data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2733,7 +2827,7 @@ public final class Const { public static final byte T_BOOLEAN = 4; /** - * Char data type. + * Char data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2741,7 +2835,7 @@ public final class Const { public static final byte T_CHAR = 5; /** - * Float data type. + * Float data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2749,7 +2843,7 @@ public final class Const { public static final byte T_FLOAT = 6; /** - * Double data type. + * Double data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2757,7 +2851,7 @@ public final class Const { public static final byte T_DOUBLE = 7; /** - * Byte data type. + * Byte data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2765,7 +2859,7 @@ public final class Const { public static final byte T_BYTE = 8; /** - * Short data type. + * Short data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2773,7 +2867,7 @@ public final class Const { public static final byte T_SHORT = 9; /** - * Int data type. + * Int data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2781,7 +2875,7 @@ public final class Const { public static final byte T_INT = 10; /** - * Long data type. + * Long data type: {@value}. * * @see Static Constraints in * the Java Virtual Machine Specification @@ -2827,7 +2921,7 @@ public final class Const { /** * The signature characters corresponding to primitive types, e.g., SHORT_TYPE_NAMES[T_INT] = "I" */ - private static final String[] SHORT_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "Z", "C", "F", "D", "B", "S", "I", "J", "V", + public static final String[] SHORT_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "Z", "C", "F", "D", "B", "S", "I", "J", "V", ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE}; /** @@ -3036,11 +3130,13 @@ public final class Const { public static final byte ATTR_MODULE_MAIN_CLASS = 24; public static final byte ATTR_NEST_HOST = 25; public static final byte ATTR_NEST_MEMBERS = 26; - public static final short KNOWN_ATTRIBUTES = 27; // count of attributes + public static final byte ATTR_RECORD = 27; + + public static final short KNOWN_ATTRIBUTES = 28; // count of attributes private static final String[] ATTRIBUTE_NAMES = {"SourceFile", "ConstantValue", "Code", "Exceptions", "LineNumberTable", "LocalVariableTable", "InnerClasses", "Synthetic", "Deprecated", "PMGClass", "Signature", "StackMap", "RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations", "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", "AnnotationDefault", "LocalVariableTypeTable", "EnclosingMethod", - "StackMapTable", "BootstrapMethods", "MethodParameters", "Module", "ModulePackages", "ModuleMainClass", "NestHost", "NestMembers"}; + "StackMapTable", "BootstrapMethods", "MethodParameters", "Module", "ModulePackages", "ModuleMainClass", "NestHost", "NestMembers", "Record"}; /** * Constants used in the StackMap attribute. */ @@ -3070,6 +3166,7 @@ public final class Const { public static final int SAME_FRAME_EXTENDED = 251; public static final int APPEND_FRAME = 252; public static final int FULL_FRAME = 255; + /** * Constants that define the maximum value of those constants which store ranges. */ @@ -3090,6 +3187,7 @@ public final class Const { public static final byte REF_invokeSpecial = 7; public static final byte REF_newInvokeSpecial = 8; public static final byte REF_invokeInterface = 9; + /** * The names of the reference_kinds of a CONSTANT_MethodHandle_info. */ @@ -3097,7 +3195,7 @@ public final class Const { "newInvokeSpecial", "invokeInterface"}; /** - * @param index + * @param index index into {@code ACCESS_NAMES}. * @return the ACCESS_NAMES entry at the given index * @since 6.0 */ @@ -3107,7 +3205,7 @@ public static String getAccessName(final int index) { /** * - * @param index + * @param index index into {@code ACCESS_NAMES}. * @return the attribute name * @since 6.0 */ @@ -3118,7 +3216,7 @@ public static String getAttributeName(final int index) { /** * The primitive class names corresponding to the T_XX constants, e.g., CLASS_TYPE_NAMES[T_INT] = "java.lang.Integer" * - * @param index + * @param index index into {@code CLASS_TYPE_NAMES}. * @return the class name * @since 6.0 */ @@ -3128,7 +3226,7 @@ public static String getClassTypeName(final int index) { /** * - * @param index + * @param index index into {@code CONSTANT_NAMES}. * @return the CONSTANT_NAMES entry at the given index * @since 6.0 */ @@ -3140,7 +3238,7 @@ public static String getConstantName(final int index) { /** * - * @param index + * @param index index into {@code CONSUME_STACK}. * @return Number of words consumed on operand stack * @since 6.0 */ @@ -3157,7 +3255,7 @@ public static Iterable getInterfacesImplementedByArrays() { /** * - * @param index + * @param index index into {@code ITEM_NAMES}. * @return the item name * @since 6.0 */ @@ -3167,7 +3265,7 @@ public static String getItemName(final int index) { /** * - * @param index + * @param index index into {@code METHODHANDLE_NAMES}. * @return the method handle name * @since 6.0 */ @@ -3177,7 +3275,7 @@ public static String getMethodHandleName(final int index) { /** * - * @param index + * @param index index into {@code NO_OF_OPERANDS}. * @return Number of byte code operands * @since 6.0 */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/ExceptionConst.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/ExceptionConst.java index d45c5794b7b..89cf3f835da 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/ExceptionConst.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/ExceptionConst.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -26,7 +26,7 @@ * Exception constants. * * @since 6.0 (intended to replace the InstructionConstant interface) - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class ExceptionConst { @@ -52,7 +52,6 @@ public enum EXCS { * Super class of any linking exception (aka Linkage Error) */ public static final Class LINKING_EXCEPTION = LinkageError.class; - /** * Linking Exceptions */ @@ -67,10 +66,10 @@ public enum EXCS { public static final Class NO_SUCH_METHOD_ERROR = NoSuchMethodError.class; public static final Class NO_CLASS_DEF_FOUND_ERROR = NoClassDefFoundError.class; public static final Class UNSATISFIED_LINK_ERROR = UnsatisfiedLinkError.class; + public static final Class VERIFY_ERROR = VerifyError.class; /* UnsupportedClassVersionError is new in JDK 1.2 */ // public static final Class UnsupportedClassVersionError = UnsupportedClassVersionError.class; - /** * Run-Time Exceptions */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Repository.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Repository.java index d36260cc23a..10f6a1a8ff4 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Repository.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/Repository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,7 +30,7 @@ * @see com.sun.org.apache.bcel.internal.util.Repository * @see SyntheticRepository * - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public abstract class Repository { @@ -174,7 +174,7 @@ public static JavaClass lookupClass(final Class clazz) throws ClassNotFoundEx } /** - * Lookups class somewhere found on your CLASSPATH, or wherever the repository instance looks for it. + * Lookups class somewhere found on your CLASSPATH, or whereever the repository instance looks for it. * * @return class object for given fully qualified class name * @throws ClassNotFoundException if the class could not be found or parsed correctly diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AccessFlags.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AccessFlags.java index 61ec9c4d690..f1d350894c9 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AccessFlags.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AccessFlags.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -25,27 +25,36 @@ * Super class for all objects that have modifiers like private, final, ... I.e. * classes, fields, and methods. * - * @LastModified: Jan 2020 + * @LastModified: Sept 2025 */ public abstract class AccessFlags { /** - * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter + * Access flags. + * + * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. */ @java.lang.Deprecated protected int access_flags; // TODO not used externally at present + /** + * Constructs a new instance. + */ public AccessFlags() { } /** - * @param a initial access flags + * Constructs a new instance. + * + * @param accessFlags initial access flags. */ - public AccessFlags(final int a) { - access_flags = a; + public AccessFlags(final int accessFlags) { + access_flags = accessFlags; } /** + * Gets access flags. + * * @return Access flags of the object aka. "modifiers". */ public final int getAccessFlags() { @@ -53,142 +62,303 @@ public final int getAccessFlags() { } /** - * @return Access flags of the object aka. "modifiers". + * Gets access flags. + * + * @return Access flags of the object also known as modifiers. */ public final int getModifiers() { return access_flags; } + /** + * Tests whether the abstract bit is on. + * + * @return whether the abstract bit is on. + */ public final boolean isAbstract() { - return (access_flags & Const.ACC_ABSTRACT) != 0; + return test(Const.ACC_ABSTRACT); } + /** + * Sets the abstract bit. + * + * @param flag The new value. + */ public final void isAbstract(final boolean flag) { setFlag(Const.ACC_ABSTRACT, flag); } + /** + * Tests whether the annotation bit is on. + * + * @return whether the annotation bit is on. + */ public final boolean isAnnotation() { - return (access_flags & Const.ACC_ANNOTATION) != 0; + return test(Const.ACC_ANNOTATION); } + /** + * Sets the annotation bit. + * + * @param flag The new value. + */ public final void isAnnotation(final boolean flag) { setFlag(Const.ACC_ANNOTATION, flag); } - + /** + * Tests whether the enum bit is on. + * + * @return whether the enum bit is on. + */ public final boolean isEnum() { - return (access_flags & Const.ACC_ENUM) != 0; + return test(Const.ACC_ENUM); } + /** + * Sets the enum bit. + * + * @param flag The new value. + */ public final void isEnum(final boolean flag) { setFlag(Const.ACC_ENUM, flag); } + /** + * Tests whether the final bit is on. + * + * @return whether the final bit is on. + */ public final boolean isFinal() { - return (access_flags & Const.ACC_FINAL) != 0; + return test(Const.ACC_FINAL); } + /** + * Sets the final bit. + * + * @param flag The new value. + */ public final void isFinal(final boolean flag) { setFlag(Const.ACC_FINAL, flag); } + /** + * Tests whether the interface bit is on. + * + * @return whether the interface bit is on. + */ public final boolean isInterface() { - return (access_flags & Const.ACC_INTERFACE) != 0; + return test(Const.ACC_INTERFACE); } + /** + * Sets the interface bit. + * + * @param flag The new value. + */ public final void isInterface(final boolean flag) { setFlag(Const.ACC_INTERFACE, flag); } + /** + * Tests whether the native bit is on. + * + * @return whether the native bit is on. + */ public final boolean isNative() { - return (access_flags & Const.ACC_NATIVE) != 0; + return test(Const.ACC_NATIVE); } + /** + * Sets the native bit. + * + * @param flag The new value. + */ public final void isNative(final boolean flag) { setFlag(Const.ACC_NATIVE, flag); } + /** + * Tests whether the private bit is on. + * + * @return whether the private bit is on. + */ public final boolean isPrivate() { - return (access_flags & Const.ACC_PRIVATE) != 0; + return test(Const.ACC_PRIVATE); } + /** + * Sets the private bit. + * + * @param flag The new value. + */ public final void isPrivate(final boolean flag) { setFlag(Const.ACC_PRIVATE, flag); } + /** + * Tests whether the protected bit is on. + * + * @return whether the protected bit is on. + */ public final boolean isProtected() { - return (access_flags & Const.ACC_PROTECTED) != 0; + return test(Const.ACC_PROTECTED); } + /** + * Sets the protected bit. + * + * @param flag The new value. + */ public final void isProtected(final boolean flag) { setFlag(Const.ACC_PROTECTED, flag); } + /** + * Tests whether the public bit is on. + * + * @return whether the public bit is on. + */ public final boolean isPublic() { - return (access_flags & Const.ACC_PUBLIC) != 0; + return test(Const.ACC_PUBLIC); } + /** + * Sets the public bit. + * + * @param flag The new value. + */ public final void isPublic(final boolean flag) { setFlag(Const.ACC_PUBLIC, flag); } + /** + * Tests whether the static bit is on. + * + * @return whether the static bit is on. + */ public final boolean isStatic() { - return (access_flags & Const.ACC_STATIC) != 0; + return test(Const.ACC_STATIC); } + /** + * Sets the static bit. + * + * @param flag The new value. + */ public final void isStatic(final boolean flag) { setFlag(Const.ACC_STATIC, flag); } + /** + * Tests whether the strict bit is on. + * + * @return whether the strict bit is on. + */ public final boolean isStrictfp() { - return (access_flags & Const.ACC_STRICT) != 0; + return test(Const.ACC_STRICT); } + /** + * Sets the strict bit. + * + * @param flag The new value. + */ public final void isStrictfp(final boolean flag) { setFlag(Const.ACC_STRICT, flag); } + /** + * Tests whether the synchronized bit is on. + * + * @return whether the synchronized bit is on. + */ public final boolean isSynchronized() { - return (access_flags & Const.ACC_SYNCHRONIZED) != 0; + return test(Const.ACC_SYNCHRONIZED); } + /** + * Sets the synchronized bit. + * + * @param flag The new value. + */ public final void isSynchronized(final boolean flag) { setFlag(Const.ACC_SYNCHRONIZED, flag); } + /** + * Tests whether the synthetic bit is on. + * + * @return whether the synthetic bit is on. + */ public final boolean isSynthetic() { - return (access_flags & Const.ACC_SYNTHETIC) != 0; + return test(Const.ACC_SYNTHETIC); } + /** + * Sets the synthetic bit. + * + * @param flag The new value. + */ public final void isSynthetic(final boolean flag) { setFlag(Const.ACC_SYNTHETIC, flag); } + /** + * Tests whether the transient bit is on. + * + * @return whether the varargs bit is on. + */ public final boolean isTransient() { - return (access_flags & Const.ACC_TRANSIENT) != 0; + return test(Const.ACC_TRANSIENT); } + /** + * Sets the varargs bit. + * + * @param flag The new value. + */ public final void isTransient(final boolean flag) { setFlag(Const.ACC_TRANSIENT, flag); } + /** + * Tests whether the varargs bit is on. + * + * @return whether the varargs bit is on. + */ public final boolean isVarArgs() { - return (access_flags & Const.ACC_VARARGS) != 0; + return test(Const.ACC_VARARGS); } + /** + * Sets the varargs bit. + * + * @param flag The new value. + */ public final void isVarArgs(final boolean flag) { setFlag(Const.ACC_VARARGS, flag); } + /** + * Tests whether the volatile bit is on. + * + * @return whether the volatile bit is on. + */ public final boolean isVolatile() { - return (access_flags & Const.ACC_VOLATILE) != 0; + return test(Const.ACC_VOLATILE); } + /** + * Sets the volatile bit. + * + * @param flag The new value. + */ public final void isVolatile(final boolean flag) { setFlag(Const.ACC_VOLATILE, flag); } /** - * Set access flags aka "modifiers". + * Sets access flags also known as modifiers. * * @param accessFlags Access flags of the object. */ @@ -207,11 +377,21 @@ private void setFlag(final int flag, final boolean set) { } /** - * Set access flags aka "modifiers". + * Sets access flags aka "modifiers". * * @param accessFlags Access flags of the object. */ public final void setModifiers(final int accessFlags) { setAccessFlags(accessFlags); } + + /** + * Tests whether the bit is on. + * + * @param test the bit to test. + * @return whether the bit is on. + */ + private boolean test(final short test) { + return (access_flags & test) != 0; + } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AnnotationEntry.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AnnotationEntry.java index 466e9bf3404..c9503332a6f 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AnnotationEntry.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/AnnotationEntry.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,20 +26,22 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; +import jdk.xml.internal.Utils; /** * Represents one annotation in the annotation table * * @since 6.0 + * @LastModified: Sept 2025 */ public class AnnotationEntry implements Node { public static final AnnotationEntry[] EMPTY_ARRAY = {}; - public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attrs) { + public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attributes) { // Find attributes that contain annotation data - return Stream.of(attrs).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries())) - .toArray(AnnotationEntry[]::new); + return Utils.streamOfIfNonNull(attributes).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries())) + .toArray(AnnotationEntry[]::new); } /** @@ -55,7 +56,6 @@ public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attrs) public static AnnotationEntry read(final DataInput input, final ConstantPool constantPool, final boolean isRuntimeVisible) throws IOException { final AnnotationEntry annotationEntry = new AnnotationEntry(input.readUnsignedShort(), constantPool, isRuntimeVisible); final int numElementValuePairs = input.readUnsignedShort(); - annotationEntry.elementValuePairs = new ArrayList<>(); for (int i = 0; i < numElementValuePairs; i++) { annotationEntry.elementValuePairs .add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool)); @@ -69,12 +69,13 @@ public static AnnotationEntry read(final DataInput input, final ConstantPool con private final boolean isRuntimeVisible; - private List elementValuePairs; + private final List elementValuePairs; public AnnotationEntry(final int typeIndex, final ConstantPool constantPool, final boolean isRuntimeVisible) { this.typeIndex = typeIndex; this.constantPool = constantPool; this.isRuntimeVisible = isRuntimeVisible; + this.elementValuePairs = new ArrayList<>(); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Annotations.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Annotations.java index 52ac9d0dd98..6ff9b4a046f 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Annotations.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Annotations.java @@ -52,7 +52,7 @@ public abstract class Annotations extends Attribute implements Iterable iterator() { * @param annotationTable the entries to set in this annotation */ public final void setAnnotationTable(final AnnotationEntry[] annotationTable) { - this.annotationTable = annotationTable; + this.annotationTable = annotationTable != null ? annotationTable : AnnotationEntry.EMPTY_ARRAY; } /** @@ -151,9 +148,6 @@ public final String toString() { } protected void writeAnnotations(final DataOutputStream dos) throws IOException { - if (annotationTable == null) { - return; - } dos.writeShort(annotationTable.length); for (final AnnotationEntry element : annotationTable) { element.dump(dos); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ArrayElementValue.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ArrayElementValue.java index e8768886de5..35d0412f57a 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ArrayElementValue.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ArrayElementValue.java @@ -31,12 +31,12 @@ public class ArrayElementValue extends ElementValue { // For array types, this is the array private final ElementValue[] elementValues; - public ArrayElementValue(final int type, final ElementValue[] datums, final ConstantPool cpool) { + public ArrayElementValue(final int type, final ElementValue[] elementValues, final ConstantPool cpool) { super(type, cpool); if (type != ARRAY) { throw new ClassFormatException("Only element values of type array can be built with this ctor - type specified: " + type); } - this.elementValues = datums; + this.elementValues = elementValues != null ? elementValues : EMPTY_ARRAY; } @Override diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Attribute.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Attribute.java index bf72fee4e00..cd03615cbc0 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Attribute.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Attribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -53,7 +53,7 @@ * @see Synthetic * @see Deprecated * @see Signature - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public abstract class Attribute implements Cloneable, Node { private static final boolean debug = false; @@ -181,6 +181,8 @@ public static Attribute readAttribute(final DataInput dataInput, final ConstantP return new NestHost(nameIndex, length, dataInput, constantPool); case Const.ATTR_NEST_MEMBERS: return new NestMembers(nameIndex, length, dataInput, constantPool); + case Const.ATTR_RECORD: + return new Record(nameIndex, length, dataInput, constantPool); default: // Never reached throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag); @@ -279,7 +281,7 @@ public Object clone() { try { attr = (Attribute) super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } return attr; } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/BootstrapMethod.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/BootstrapMethod.java index 61b818ec4f0..224e0df6b94 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/BootstrapMethod.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/BootstrapMethod.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,6 +26,7 @@ import java.util.Arrays; import com.sun.org.apache.bcel.internal.Const; +import jdk.xml.internal.Utils; /** * This class represents a bootstrap method attribute, i.e., the bootstrap method ref, the number of bootstrap arguments @@ -35,9 +35,12 @@ * @see The class File Format : * The BootstrapMethods Attribute * @since 6.0 + * @LastModified: Sept 2025 */ public class BootstrapMethod implements Cloneable { + static final BootstrapMethod[] EMPTY_ARRAY = {}; + /** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */ private int bootstrapMethodRef; @@ -54,7 +57,7 @@ public BootstrapMethod(final BootstrapMethod c) { } /** - * Construct object from input stream. + * Constructs object from input stream. * * @param input Input stream * @throws IOException if an I/O error occurs. @@ -78,7 +81,7 @@ private BootstrapMethod(final int bootstrapMethodRef, final int numBootstrapArgu */ public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) { this.bootstrapMethodRef = bootstrapMethodRef; - this.bootstrapArguments = bootstrapArguments; + setBootstrapArguments(bootstrapArguments); } /** @@ -87,7 +90,7 @@ public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArgume public BootstrapMethod copy() { try { return (BootstrapMethod) clone(); - } catch (final CloneNotSupportedException e) { + } catch (final CloneNotSupportedException ignore) { // TODO should this throw? } return null; @@ -132,7 +135,7 @@ public int getNumBootstrapArguments() { * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info */ public void setBootstrapArguments(final int[] bootstrapArguments) { - this.bootstrapArguments = bootstrapArguments; + this.bootstrapArguments = Utils.createEmptyArrayIfNull(bootstrapArguments); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/BootstrapMethods.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/BootstrapMethods.java index 6f9930f1b16..ef2475e1856 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/BootstrapMethods.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/BootstrapMethods.java @@ -58,11 +58,11 @@ public BootstrapMethods(final BootstrapMethods c) { */ public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) { super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool); - this.bootstrapMethods = bootstrapMethods; + setBootstrapMethods(bootstrapMethods); } /** - * Construct object from Input stream. + * Constructs object from Input stream. * * @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes @@ -135,7 +135,7 @@ public Iterator iterator() { * @param bootstrapMethods the array of bootstrap methods */ public final void setBootstrapMethods(final BootstrapMethod[] bootstrapMethods) { - this.bootstrapMethods = bootstrapMethods; + this.bootstrapMethods = bootstrapMethods != null ? bootstrapMethods : BootstrapMethod.EMPTY_ARRAY; } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassFormatException.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassFormatException.java index a61e1d75390..037f3908379 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassFormatException.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassFormatException.java @@ -47,12 +47,10 @@ public ClassFormatException(final String message) { /** * Constructs a new instance with the specified detail message and cause. - *

- * Note that the detail message associated with {@code cause} is not automatically incorporated in this runtime exception's detail message. * * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method). - * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A {@code null} value is permitted, and indicates that - * the cause is nonexistent or unknown.) + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). A {@code null} value is permitted, and indicates that + * the cause is nonexistent or unknown. * @since 6.0 */ public ClassFormatException(final String message, final Throwable cause) { @@ -63,8 +61,8 @@ public ClassFormatException(final String message, final Throwable cause) { * Constructs a new instance with the specified cause and a detail message of {@code (cause==null ? null : cause.toString())} (which typically contains the * class and detail message of {@code cause}). This constructor is useful for runtime exceptions that are little more than wrappers for other throwables. * - * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A {@code null} value is permitted, and indicates that the - * cause is nonexistent or unknown.) + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). A {@code null} value is permitted, and indicates that the + * cause is nonexistent or unknown. * @since 6.7.0 */ public ClassFormatException(final Throwable cause) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassParser.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassParser.java index c9daaeabf9b..0dbda722ec4 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassParser.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ClassParser.java @@ -37,7 +37,7 @@ * appropriate exception is propagated back to the caller. * * The structure and the names comply, except for a few conveniences, exactly with the - * JVM specification 1.0. See this paper for further details about + * JVM specification 1.0. See this paper for further details about * the structure of a bytecode file. */ public final class ClassParser { @@ -57,7 +57,7 @@ public final class ClassParser { private Field[] fields; // class fields, i.e., its variables private Method[] methods; // methods defined in the class private Attribute[] attributes; // attributes defined in the class - private final boolean isZip; // Loaded from zip file + private final boolean isZip; // Loaded from ZIP file /** * Parses class from the given stream. @@ -91,7 +91,7 @@ public ClassParser(final String fileName) { /** * Parses class from given .class file in a ZIP-archive * - * @param zipFile zip file name + * @param zipFile ZIP file name * @param fileName file name */ public ClassParser(final String zipFile, final String fileName) { @@ -104,7 +104,7 @@ public ClassParser(final String zipFile, final String fileName) { /** * Parses the given Java class file and return an object that represents the contained data, i.e., constants, methods, * fields and commands. A ClassFormatException is raised, if the file is not a valid .class file. (This does - * not include verification of the byte code as it is performed by the java interpreter). + * not include verification of the byte code as it is performed by the Java interpreter). * * @return Class object representing the parsed class file * @throws IOException if an I/O error occurs. @@ -151,11 +151,11 @@ public JavaClass parse() throws IOException, ClassFormatException { // for (int i=0; i < u.length; i++) // System.err.println("WARNING: " + u[i]); // Everything should have been read now - // if(file.available() > 0) { + // if (file.available() > 0) { // int bytes = file.available(); // byte[] buf = new byte[bytes]; // file.read(buf); - // if(!(isZip && (buf.length == 1))) { + // if (!(isZip && (buf.length == 1))) { // System.err.println("WARNING: Trailing garbage at end of " + fileName); // System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf)); // } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Code.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Code.java index 498a8c71b18..7573a5412e7 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Code.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Code.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,6 +27,7 @@ import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.util.Args; +import jdk.xml.internal.Utils; /** * This class represents a chunk of Java byte code contained in a method. It is instantiated by the @@ -59,7 +60,7 @@ * @see CodeException * @see LineNumberTable * @see LocalVariableTable - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class Code extends Attribute { @@ -93,7 +94,7 @@ public Code(final Code code) { code = new byte[codeLength]; // Read byte code file.readFully(code); /* - * Read exception table that contains all regions where an exception handler is active, i.e., a try { ... } catch() + * Read exception table that contains all regions where an exception handler is active, i.e., a try { ... } catch () * block. */ final int exceptionTableLength = file.readUnsignedShort(); @@ -107,7 +108,7 @@ public Code(final Code code) { final int attributesCount = file.readUnsignedShort(); attributes = new Attribute[attributesCount]; for (int i = 0; i < attributesCount; i++) { - attributes[i] = Attribute.readAttribute(file, constantPool); + attributes[i] = readAttribute(file, constantPool); } /* * Adjust length, because of setAttributes in this(), s.b. length is incorrect, because it didn't take the internal @@ -131,8 +132,8 @@ public Code(final int nameIndex, final int length, final int maxStack, final int super(Const.ATTR_CODE, nameIndex, length, constantPool); this.maxStack = Args.requireU2(maxStack, "maxStack"); this.maxLocals = Args.requireU2(maxLocals, "maxLocals"); - this.code = code != null ? code : Const.EMPTY_BYTE_ARRAY; - this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY; + this.code = Utils.createEmptyArrayIfNull(code); + this.exceptionTable = Utils.createEmptyArrayIfNull(exceptionTable, CodeException[].class); Args.requireU2(this.exceptionTable.length, "exceptionTable.length"); this.attributes = attributes != null ? attributes : EMPTY_ARRAY; super.setLength(calculateLength()); // Adjust length @@ -263,6 +264,20 @@ public LocalVariableTable getLocalVariableTable() { return null; } + /** + * Gets the local variable type table attribute {@link LocalVariableTypeTable}. + * @return LocalVariableTypeTable of Code, if it has one, null otherwise. + * @since 6.10.0 + */ + public LocalVariableTypeTable getLocalVariableTypeTable() { + for (final Attribute attribute : attributes) { + if (attribute instanceof LocalVariableTypeTable) { + return (LocalVariableTypeTable) attribute; + } + } + return null; + } + /** * @return Number of local variables. */ @@ -277,6 +292,20 @@ public int getMaxStack() { return maxStack; } + /** + * Finds the attribute of {@link StackMap} instance. + * @return StackMap of Code, if it has one, else null. + * @since 6.8.0 + */ + public StackMap getStackMap() { + for (final Attribute attribute : attributes) { + if (attribute instanceof StackMap) { + return (StackMap) attribute; + } + } + return null; + } + /** * @param attributes the attributes to set for this Code */ @@ -289,7 +318,7 @@ public void setAttributes(final Attribute[] attributes) { * @param code byte code */ public void setCode(final byte[] code) { - this.code = code != null ? code : Const.EMPTY_BYTE_ARRAY; + this.code = Utils.createEmptyArrayIfNull(code); super.setLength(calculateLength()); // Adjust length } @@ -297,7 +326,7 @@ public void setCode(final byte[] code) { * @param exceptionTable exception table */ public void setExceptionTable(final CodeException[] exceptionTable) { - this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY; + this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_ARRAY; super.setLength(calculateLength()); // Adjust length } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/CodeException.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/CodeException.java index ee224e6b348..b8bf109239e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/CodeException.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/CodeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -52,19 +52,19 @@ *

* * @see Code - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class CodeException implements Cloneable, Node { /** * Empty array. */ - static final CodeException[] EMPTY_CODE_EXCEPTION_ARRAY = {}; + static final CodeException[] EMPTY_ARRAY = {}; /** Range in the code the exception handler. */ private int startPc; - /** active. startPc is inclusive, endPc exclusive. */ + /** Active. startPc is inclusive, endPc exclusive. */ private int endPc; /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Constant.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Constant.java index 885e1b599eb..9b3d6f31e17 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Constant.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Constant.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -32,30 +32,29 @@ * in the constant pool of a class file. The classes keep closely to * the JVM specification. * - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public abstract class Constant implements Cloneable, Node { - private static BCELComparator bcelComparator = new BCELComparator() { + static final Constant[] EMPTY_ARRAY = {}; + + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final Constant THIS = (Constant) o1; - final Constant THAT = (Constant) o2; - return Objects.equals(THIS.toString(), THAT.toString()); + public boolean equals(final Constant a, final Constant b) { + return a == b || a != null && b != null && Objects.equals(a.toString(), b.toString()); } @Override - public int hashCode(final Object o) { - final Constant THIS = (Constant) o; - return THIS.toString().hashCode(); + public int hashCode(final Constant o) { + return o != null ? Objects.hashCode(o.toString()) : 0; } }; /** - * @return Comparison strategy object + * @return Comparison strategy object. */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } @@ -113,7 +112,7 @@ public static Constant readConstant(final DataInput dataInput) throws IOExceptio /** * @param comparator Comparison strategy object */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } @@ -148,7 +147,7 @@ public Object clone() { try { return super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } } @@ -174,7 +173,7 @@ public Constant copy() { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof Constant && bcelComparator.equals(this, (Constant) obj); } /** @@ -185,7 +184,7 @@ public final byte getTag() { } /** - * Returns value as defined by given BCELComparator strategy. By default return the hashcode of the result of + * Returns value as defined by given BCELComparator strategy. By default return the hash code of the result of * toString(). * * @see Object#hashCode() diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantCP.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantCP.java index 71fd91b249a..51113a1aeaa 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantCP.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantCP.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -28,11 +28,11 @@ /** * Abstract super class for Fieldref, Methodref, InterfaceMethodref and InvokeDynamic constants. * - * @see ConstantFieldref - * @see ConstantMethodref - * @see ConstantInterfaceMethodref - * @see ConstantInvokeDynamic - * @LastModified: Jun 2019 + * @see ConstantFieldref + * @see ConstantMethodref + * @see ConstantInterfaceMethodref + * @see ConstantInvokeDynamic + * @LastModified: Sept 2025 */ public abstract class ConstantCP extends Constant { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantDouble.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantDouble.java index ebb3d0af46a..14b43937c92 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantDouble.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantDouble.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -29,8 +29,8 @@ /** * This class is derived from the abstract {@link Constant} and represents a reference to a Double object. * - * @see Constant - * @LastModified: Jun 2019 + * @see Constant + * @LastModified: Sept 2025 */ public final class ConstantDouble extends Constant implements ConstantObject { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantFloat.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantFloat.java index 9c30c9e4fdb..e86bbb94e66 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantFloat.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantFloat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -29,8 +29,8 @@ /** * This class is derived from the abstract {@link Constant} and represents a reference to a float object. * - * @see Constant - * @LastModified: Jun 2019 + * @see Constant + * @LastModified: Sept 2025 */ public final class ConstantFloat extends Constant implements ConstantObject { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantInteger.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantInteger.java index cabd2e15b03..20c0717acb6 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantInteger.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantInteger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -29,8 +29,8 @@ /** * This class is derived from the abstract {@link Constant} and represents a reference to an int object. * - * @see Constant - * @LastModified: Jun 2019 + * @see Constant + * @LastModified: Sept 2025 */ public final class ConstantInteger extends Constant implements ConstantObject { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantLong.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantLong.java index c1e683abadb..6936162c264 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantLong.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantLong.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -29,8 +29,8 @@ /** * This class is derived from the abstract {@link Constant} and represents a reference to a long object. * - * @see Constant - * @LastModified: Jan 2020 + * @see Constant + * @LastModified: Sept 2025 */ public final class ConstantLong extends Constant implements ConstantObject { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantObject.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantObject.java index cb28f7dacb8..ab187b7e4f8 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantObject.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantObject.java @@ -29,7 +29,10 @@ public interface ConstantObject { /** - * @return object representing the constant, e.g., Long for ConstantLong + * Gets the object representing the constant, e.g., Long for ConstantLong. + * + * @param constantPool the constant. + * @return object representing the constant, e.g., Long for ConstantLong. */ - Object getConstantValue(ConstantPool cp); + Object getConstantValue(ConstantPool constantPool); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java index 5fb4ef1b080..ae1e3977c99 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -35,7 +35,7 @@ * * @see Constant * @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class ConstantPool implements Cloneable, Node, Iterable { @@ -73,7 +73,7 @@ private static String escape(final String str) { * @param constantPool Array of constants */ public ConstantPool(final Constant[] constantPool) { - this.constantPool = constantPool; + setConstantPool(constantPool); } /** @@ -88,6 +88,7 @@ public ConstantPool(final DataInput input) throws IOException { constantPool = new Constant[constantPoolCount]; /* * constantPool[0] is unused by the compiler and may be used freely by the implementation. + * constantPool[0] is currently unused by the implementation. */ for (int i = 1; i < constantPoolCount; i++) { constantPool[i] = Constant.readConstant(input); @@ -288,7 +289,7 @@ public T getConstant(final int index, final byte tag) throw */ public T getConstant(final int index, final byte tag, final Class castTo) throws ClassFormatException { final T c = getConstant(index); - if (c.getTag() != tag) { + if (c == null || c.getTag() != tag) { throw new ClassFormatException("Expected class '" + Const.getConstantName(tag) + "' at index " + index + " and got " + c); } return c; @@ -313,16 +314,18 @@ public T getConstant(final int index, final Class castTo throw new ClassFormatException("Invalid constant pool reference at index: " + index + ". Expected " + castTo + " but was " + constantPool[index].getClass()); } - // Previous check ensures this won't throw a ClassCastException - final T c = castTo.cast(constantPool[index]); - if (c == null - // the 0th element is always null - && index != 0) { + if (index > 1) { final Constant prev = constantPool[index - 1]; - if (prev == null || prev.getTag() != Const.CONSTANT_Double && prev.getTag() != Const.CONSTANT_Long) { - throw new ClassFormatException("Constant pool at index " + index + " is null."); + if (prev != null && (prev.getTag() == Const.CONSTANT_Double || prev.getTag() == Const.CONSTANT_Long)) { + throw new ClassFormatException("Constant pool at index " + index + " is invalid. The index is unused due to the preceeding " + + Const.getConstantName(prev.getTag()) + "."); } } + // Previous check ensures this won't throw a ClassCastException + final T c = castTo.cast(constantPool[index]); + if (c == null) { + throw new ClassFormatException("Constant pool at index " + index + " is null."); + } return c; } @@ -402,7 +405,7 @@ public ConstantUtf8 getConstantUtf8(final int index) throws ClassFormatException * @return Length of constant pool. */ public int getLength() { - return constantPool == null ? 0 : constantPool.length; + return constantPool.length; } @Override @@ -421,7 +424,7 @@ public void setConstant(final int index, final Constant constant) { * @param constantPool */ public void setConstantPool(final Constant[] constantPool) { - this.constantPool = constantPool; + this.constantPool = constantPool != null ? constantPool : Constant.EMPTY_ARRAY; } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantUtf8.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantUtf8.java index ec875554c1a..90e45c807e5 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantUtf8.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantUtf8.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -36,11 +36,11 @@ * The following system properties govern caching this class performs. *

*
    - *
  • {@value #SYS_PROP_CACHE_MAX_ENTRIES} (since 6.4): The size of the cache, by default 0, meaning caching is + *
  • {@link #SYS_PROP_CACHE_MAX_ENTRIES} (since 6.4): The size of the cache, by default 0, meaning caching is * disabled.
  • - *
  • {@value #SYS_PROP_CACHE_MAX_ENTRY_SIZE} (since 6.0): The maximum size of the values to cache, by default 200, 0 + *
  • {@link #SYS_PROP_CACHE_MAX_ENTRY_SIZE} (since 6.0): The maximum size of the values to cache, by default 200, 0 * disables caching. Values larger than this are not cached.
  • - *
  • {@value #SYS_PROP_STATISTICS} (since 6.0): Prints statistics on the console when the JVM exits.
  • + *
  • {@link #SYS_PROP_STATISTICS} (since 6.0): Prints statistics on the console when the JVM exits.
  • *
*

* Here is a sample Maven invocation with caching disabled: @@ -58,11 +58,11 @@ * * * @see Constant - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class ConstantUtf8 extends Constant { - private static class Cache { + private static final class Cache { private static final boolean BCEL_STATISTICS = false; private static final int MAX_ENTRIES = 20000; @@ -82,7 +82,7 @@ protected boolean removeEldestEntry(final Map.Entry eldest private static final int MAX_ENTRY_SIZE = 200; static boolean isEnabled() { - return Cache.MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0; + return MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0; } } @@ -117,6 +117,11 @@ static synchronized void clearStats() { hits = considered = skipped = created = 0; } + // Avoid Spotbugs complaint about Write to static field + private static void countCreated() { + created++; + } + /** * Gets a new or cached instance of the given value. *

@@ -203,7 +208,7 @@ public ConstantUtf8(final ConstantUtf8 constantUtf8) { ConstantUtf8(final DataInput dataInput) throws IOException { super(Const.CONSTANT_Utf8); value = dataInput.readUTF(); - created++; + countCreated(); } /** @@ -212,7 +217,7 @@ public ConstantUtf8(final ConstantUtf8 constantUtf8) { public ConstantUtf8(final String value) { super(Const.CONSTANT_Utf8); this.value = Objects.requireNonNull(value, "value"); - created++; + countCreated(); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantValue.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantValue.java index 311e9a33fa3..143c2a25544 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantValue.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantValue.java @@ -56,7 +56,7 @@ public ConstantValue(final ConstantValue c) { } /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Name index in constant pool * @param length Content length in bytes diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Deprecated.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Deprecated.java index 90841d96081..c561afe33c5 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Deprecated.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Deprecated.java @@ -59,7 +59,7 @@ public Deprecated(final int nameIndex, final int length, final byte[] bytes, fin } /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java index 3c475891acd..934b608d6ac 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/DescendingVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -22,12 +22,13 @@ import java.util.Objects; import java.util.Stack; import java.util.stream.Stream; +import jdk.xml.internal.Utils; /** - * Traverses a JavaClass with another Visitor object 'piggy-backed' that is - * applied to all components of a JavaClass object. I.e. this class supplies the - * traversal strategy, other classes can make use of it. + * Traverses a JavaClass with another Visitor object 'piggy-backed' that is applied to all components of a JavaClass + * object. I.e. this class supplies the traversal strategy, other classes can make use of it. * + * @LastModified: Sept 2025 */ public class DescendingVisitor implements Visitor { private final JavaClass clazz; @@ -46,7 +47,7 @@ public DescendingVisitor(final JavaClass clazz, final Visitor visitor) { } private void accept(final E[] node) { - Stream.of(node).forEach(e -> e.accept(this)); + Utils.streamOfIfNonNull(node).forEach(e -> e.accept(this)); } /** @@ -507,6 +508,21 @@ public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) { stack.pop(); } + @Override + public void visitRecord(final Record record) { + stack.push(record); + record.accept(visitor); + accept(record.getComponents()); + stack.pop(); + } + + @Override + public void visitRecordComponent(final RecordComponentInfo recordComponentInfo) { + stack.push(recordComponentInfo); + recordComponentInfo.accept(visitor); + stack.pop(); + } + @Override public void visitSignature(final Signature attribute) { stack.push(attribute); @@ -531,6 +547,20 @@ public void visitStackMap(final StackMap table) { @Override public void visitStackMapEntry(final StackMapEntry var) { + stack.push(var); + var.accept(visitor); + accept(var.getTypesOfLocals()); + accept(var.getTypesOfStackItems()); + stack.pop(); + } + + /** + * Visits a {@link StackMapType} object. + * @param var object to visit + * @since 6.8.0 + */ + @Override + public void visitStackMapType(final StackMapType var) { stack.push(var); var.accept(visitor); stack.pop(); @@ -549,4 +579,5 @@ public void visitUnknown(final Unknown attribute) { attribute.accept(visitor); stack.pop(); } + } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ElementValue.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ElementValue.java index 5c3d9b3172b..d87307c0e7d 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ElementValue.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ElementValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -50,7 +50,7 @@ *} * * @since 6.0 - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public abstract class ElementValue { @@ -67,6 +67,7 @@ public abstract class ElementValue { public static final byte PRIMITIVE_LONG = 'J'; public static final byte PRIMITIVE_SHORT = 'S'; public static final byte PRIMITIVE_BOOLEAN = 'Z'; + static final ElementValue[] EMPTY_ARRAY = {}; /** * Reads an {@code element_value} as an {@code ElementValue}. @@ -124,7 +125,7 @@ public static ElementValue readElementValue(final DataInput input, final Constan final int numArrayVals = input.readUnsignedShort(); final ElementValue[] evalues = new ElementValue[numArrayVals]; for (int j = 0; j < numArrayVals; j++) { - evalues[j] = ElementValue.readElementValue(input, cpool, arrayNesting); + evalues[j] = readElementValue(input, cpool, arrayNesting); } return new ArrayElementValue(ARRAY, evalues, cpool); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/EmptyVisitor.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/EmptyVisitor.java index 826ba41af70..db33c871656 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/EmptyVisitor.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/EmptyVisitor.java @@ -315,6 +315,15 @@ public void visitStackMap(final StackMap obj) { public void visitStackMapEntry(final StackMapEntry obj) { } + /** + * Visits a {@link StackMapType} object. + * @param obj object to visit + * @since 6.8.0 + */ + @Override + public void visitStackMapType(final StackMapType obj) { + } + @Override public void visitSynthetic(final Synthetic obj) { } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ExceptionTable.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ExceptionTable.java index 90eaa3eb062..1b6004b3740 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ExceptionTable.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ExceptionTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,6 +27,7 @@ import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.util.Args; +import jdk.xml.internal.Utils; /** * This class represents the table of exceptions that are thrown by a method. This attribute may be used once per @@ -43,7 +44,7 @@ * } * * @see Code - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class ExceptionTable extends Attribute { @@ -60,7 +61,7 @@ public ExceptionTable(final ExceptionTable c) { } /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool * @param length Content length in bytes @@ -85,7 +86,7 @@ public ExceptionTable(final ExceptionTable c) { */ public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) { super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool); - this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : Const.EMPTY_INT_ARRAY; + this.exceptionIndexTable = Utils.createEmptyArrayIfNull(exceptionIndexTable); Args.requireU2(this.exceptionIndexTable.length, "exceptionIndexTable.length"); } @@ -156,7 +157,7 @@ public int getNumberOfExceptions() { * length. */ public void setExceptionIndexTable(final int[] exceptionIndexTable) { - this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : Const.EMPTY_INT_ARRAY; + this.exceptionIndexTable = Utils.createEmptyArrayIfNull(exceptionIndexTable); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Field.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Field.java index 7e6ccb2ecb5..8ffc796a0ea 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Field.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Field.java @@ -42,45 +42,37 @@ public final class Field extends FieldOrMethod { */ public static final Field[] EMPTY_ARRAY = {}; - private static BCELComparator bcelComparator = new BCELComparator() { + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final Field THIS = (Field) o1; - final Field THAT = (Field) o2; - return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature()); + public boolean equals(final Field a, final Field b) { + return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature()); } @Override - public int hashCode(final Object o) { - final Field THIS = (Field) o; - return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + public int hashCode(final Field o) { + return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0; } }; /** - * Empty array. + * @return Comparison strategy object. */ - static final Field[] EMPTY_FIELD_ARRAY = {}; - - /** - * @return Comparison strategy object - */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } /** - * @param comparator Comparison strategy object + * @param comparator Comparison strategy object. */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } /** - * Construct object from file stream. + * Constructs object from file stream. * - * @param file Input stream + * @param file Input stream. */ Field(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException { super(file, constantPool); @@ -133,7 +125,7 @@ public Field copy(final ConstantPool constantPool) { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof Field && bcelComparator.equals(this, (Field) obj); } /** @@ -149,14 +141,16 @@ public ConstantValue getConstantValue() { } /** + * See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2.2 + * * @return type of field */ public Type getType() { - return Type.getReturnType(getSignature()); + return Type.getType(getSignature()); } /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR + * Return value as defined by given BCELComparator strategy. By default return the hash code of the field's name XOR * signature. * * @see Object#hashCode() diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/FieldOrMethod.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/FieldOrMethod.java index 1daa6a62fd5..679d5a9eb7c 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/FieldOrMethod.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/FieldOrMethod.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -28,7 +28,7 @@ /** * Abstract super class for fields and methods. * - * @LastModified: Jan 2020 + * @LastModified: Sept 2025 */ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node { @@ -72,7 +72,7 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No } /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O error occurs. @@ -88,7 +88,7 @@ protected FieldOrMethod(final DataInput file, final ConstantPool constantPool) t } /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O error occurs. @@ -137,7 +137,7 @@ protected FieldOrMethod copy_(final ConstantPool constantPool) { Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool)); return c; } catch (final CloneNotSupportedException e) { - throw new IllegalStateException(e); + throw new UnsupportedOperationException(e); } } @@ -152,10 +152,8 @@ public final void dump(final DataOutputStream file) throws IOException { file.writeShort(name_index); file.writeShort(signature_index); file.writeShort(attributes_count); - if (attributes != null) { - for (final Attribute attribute : attributes) { - attribute.dump(file); - } + for (final Attribute attribute : attributes) { + attribute.dump(file); } } @@ -171,6 +169,22 @@ public AnnotationEntry[] getAnnotationEntries() { return annotationEntries; } + /** + * Gets attribute for given tag. + * @return Attribute for given tag, null if not found. + * Refer to {@link com.sun.org.apache.bcel.internal.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values. + * @since 6.10.0 + */ + @SuppressWarnings("unchecked") + public final T getAttribute(final byte tag) { + for (final Attribute attribute : getAttributes()) { + if (attribute.getTag() == tag) { + return (T) attribute; + } + } + return null; + } + /** * @return Collection of object attributes. */ @@ -221,7 +235,7 @@ public final int getNameIndex() { } /** - * @return String representation of object's type signature (java style) + * @return String representation of object's type signature (Java style) */ public final String getSignature() { return constant_pool.getConstantUtf8(signature_index).getBytes(); @@ -238,8 +252,8 @@ public final int getSignatureIndex() { * @param attributes Collection of object attributes. */ public final void setAttributes(final Attribute[] attributes) { - this.attributes = attributes; - this.attributes_count = attributes != null ? attributes.length : 0; // init deprecated field + this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY; + this.attributes_count = this.attributes.length; // init deprecated field } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClass.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClass.java index d77582815b7..82900dcca10 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClass.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClass.java @@ -41,7 +41,7 @@ public final class InnerClass implements Cloneable, Node { private int innerAccessFlags; /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O error occurs. diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClasses.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClasses.java index 2295ca5c625..b61be1effa0 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClasses.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InnerClasses.java @@ -42,7 +42,7 @@ public final class InnerClasses extends Attribute implements Iterable iterator() { * @param innerClasses the array of inner classes */ public void setInnerClasses(final InnerClass[] innerClasses) { - this.innerClasses = innerClasses != null ? innerClasses : EMPTY_INNER_CLASSE_ARRAY; + this.innerClasses = innerClasses != null ? innerClasses : EMPTY_ARRAY; } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InvalidMethodSignatureException.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InvalidMethodSignatureException.java new file mode 100644 index 00000000000..eaf1da2d2e1 --- /dev/null +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/InvalidMethodSignatureException.java @@ -0,0 +1,53 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.sun.org.apache.bcel.internal.classfile; + +/** + * Thrown when the BCEL attempts to read a class file and determines that a class is malformed or otherwise cannot be interpreted as a class file. + * + * @since 6.8.0 + */ +public class InvalidMethodSignatureException extends ClassFormatException { + + private static final long serialVersionUID = 1L; + + /** + * Constructs a new instance with the specified invalid signature as the message. + * + * @param signature The invalid signature is saved for later retrieval by the {@link #getMessage()} method. + */ + public InvalidMethodSignatureException(final String signature) { + super(signature); + } + + /** + * Constructs a new instance with the specified invalid signature as the message and a cause. + * + * @param signature The invalid signature is saved for later retrieval by the {@link #getMessage()} method. + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). A {@code null} value is permitted, and indicates that + * the cause is nonexistent or unknown. + */ + public InvalidMethodSignatureException(final String signature, final Throwable cause) { + super(signature, cause); + } + +} diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/JavaClass.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/JavaClass.java index d6c4cfa6a07..1b0e2ed1ce0 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/JavaClass.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/JavaClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -38,6 +38,7 @@ import com.sun.org.apache.bcel.internal.util.BCELComparator; import com.sun.org.apache.bcel.internal.util.ClassQueue; import com.sun.org.apache.bcel.internal.util.SyntheticRepository; +import jdk.xml.internal.Utils; /** * Represents a Java class, i.e., the data structures, constant pool, fields, methods and commands contained in a Java @@ -46,7 +47,7 @@ * classes should see the ClassGen class. * * @see com.sun.org.apache.bcel.internal.generic.ClassGen - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparable { @@ -67,26 +68,23 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl public static final byte HEAP = 1; public static final byte FILE = 2; public static final byte ZIP = 3; - private static BCELComparator bcelComparator = new BCELComparator() { + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final JavaClass THIS = (JavaClass) o1; - final JavaClass THAT = (JavaClass) o2; - return Objects.equals(THIS.getClassName(), THAT.getClassName()); + public boolean equals(final JavaClass a, final JavaClass b) { + return a == b || a != null && b != null && Objects.equals(a.getClassName(), b.getClassName()); } @Override - public int hashCode(final Object o) { - final JavaClass THIS = (JavaClass) o; - return THIS.getClassName().hashCode(); + public int hashCode(final JavaClass o) { + return o != null ? Objects.hashCode(o.getClassName()) : 0; } }; /** - * @return Comparison strategy object + * @return Comparison strategy object. */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } @@ -100,9 +98,9 @@ private static String indent(final Object obj) { } /** - * @param comparator Comparison strategy object + * @param comparator Comparison strategy object. */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } @@ -128,8 +126,10 @@ public static void setComparator(final BCELComparator comparator) { private boolean isAnonymous; private boolean isNested; + private boolean isRecord; private boolean computedNestedTypeStatus; + private boolean computedRecord; /** * In cases where we go ahead and create something, use the default SyntheticRepository, because we don't know any @@ -177,17 +177,15 @@ public JavaClass(final int classNameIndex, final int superclassNameIndex, final public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags, final ConstantPool constantPool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes, final byte source) { super(accessFlags); - if (interfaces == null) { - interfaces = Const.EMPTY_INT_ARRAY; - } + interfaces = Utils.createEmptyArrayIfNull(interfaces); if (attributes == null) { attributes = Attribute.EMPTY_ARRAY; } if (fields == null) { - fields = Field.EMPTY_FIELD_ARRAY; + fields = Field.EMPTY_ARRAY; } if (methods == null) { - methods = Method.EMPTY_METHOD_ARRAY; + methods = Method.EMPTY_ARRAY; } this.classNameIndex = classNameIndex; this.superclassNameIndex = superclassNameIndex; @@ -254,6 +252,19 @@ public int compareTo(final JavaClass obj) { return getClassName().compareTo(obj.getClassName()); } + private void computeIsRecord() { + if (computedRecord) { + return; + } + for (final Attribute attribute : this.attributes) { + if (attribute instanceof Record) { + isRecord = true; + break; + } + } + this.computedRecord = true; + } + private void computeNestedTypeStatus() { if (computedNestedTypeStatus) { return; @@ -384,11 +395,51 @@ public void dump(final String fileName) throws IOException { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof JavaClass && bcelComparator.equals(this, (JavaClass) obj); + } + + /** + * Finds a visible field by name and type in this class and its super classes. + * @param fieldName the field name to find + * @param fieldType the field type to find + * @return field matching given name and type, null if field is not found or not accessible from this class. + * @throws ClassNotFoundException + * @since 6.8.0 + */ + public Field findField(final String fieldName, final Type fieldType) throws ClassNotFoundException { + for (final Field field : fields) { + if (field.getName().equals(fieldName)) { + final Type fType = Type.getType(field.getSignature()); + /* + * TODO: Check if assignment compatibility is sufficient. What does Sun do? + */ + if (fType.equals(fieldType)) { + return field; + } + } + } + + final JavaClass superclass = getSuperClass(); + if (superclass != null && !"java.lang.Object".equals(superclass.getClassName())) { + final Field f = superclass.findField(fieldName, fieldType); + if (f != null && (f.isPublic() || f.isProtected() || !f.isPrivate() && packageName.equals(superclass.getPackageName()))) { + return f; + } + } + final JavaClass[] implementedInterfaces = getInterfaces(); + if (implementedInterfaces != null) { + for (final JavaClass implementedInterface : implementedInterfaces) { + final Field f = implementedInterface.findField(fieldName, fieldType); + if (f != null) { + return f; + } + } + } + return null; } /** - * Get all interfaces implemented by this JavaClass (transitively). + * Gets all interfaces implemented by this JavaClass (transitively). * * @throws ClassNotFoundException if any of the class's superclasses or interfaces can't be found. */ @@ -409,7 +460,7 @@ public JavaClass[] getAllInterfaces() throws ClassNotFoundException { queue.enqueue(iface); } } - return allInterfaces.toArray(JavaClass.EMPTY_ARRAY); + return allInterfaces.toArray(EMPTY_ARRAY); } /** @@ -424,6 +475,22 @@ public AnnotationEntry[] getAnnotationEntries() { return annotations; } + /** + * Gets attribute for given tag. + * @return Attribute for given tag, null if not found. + * Refer to {@link com.sun.org.apache.bcel.internal.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values. + * @since 6.10.0 + */ + @SuppressWarnings("unchecked") + public final T getAttribute(final byte tag) { + for (final Attribute attribute : getAttributes()) { + if (attribute.getTag() == tag) { + return (T) attribute; + } + } + return null; + } + /** * @return Attributes of the class. */ @@ -495,7 +562,7 @@ public String[] getInterfaceNames() { } /** - * Get interfaces directly implemented by this JavaClass. + * Gets interfaces directly implemented by this JavaClass. * * @throws ClassNotFoundException if any of the class's interfaces can't be found. */ @@ -587,7 +654,7 @@ public String getSourceFilePath() { } /** - * @return the superclass for this JavaClass object, or null if this is java.lang.Object + * @return the superclass for this JavaClass object, or null if this is {@link Object} * @throws ClassNotFoundException if the superclass can't be found */ public JavaClass getSuperClass() throws ClassNotFoundException { @@ -607,12 +674,12 @@ public JavaClass[] getSuperClasses() throws ClassNotFoundException { for (clazz = clazz.getSuperClass(); clazz != null; clazz = clazz.getSuperClass()) { allSuperClasses.add(clazz); } - return allSuperClasses.toArray(JavaClass.EMPTY_ARRAY); + return allSuperClasses.toArray(EMPTY_ARRAY); } /** - * returns the super class name of this class. In the case that this class is java.lang.Object, it will return itself - * (java.lang.Object). This is probably incorrect but isn't fixed at this time to not break existing clients. + * returns the super class name of this class. In the case that this class is {@link Object}, it will return itself + * ({@link Object}). This is probably incorrect but isn't fixed at this time to not break existing clients. * * @return Superclass name. */ @@ -628,7 +695,7 @@ public int getSuperclassNameIndex() { } /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name. + * Return value as defined by given BCELComparator strategy. By default return the hash code of the class name. * * @see Object#hashCode() */ @@ -645,7 +712,7 @@ public boolean implementationOf(final JavaClass inter) throws ClassNotFoundExcep if (!inter.isInterface()) { throw new IllegalArgumentException(inter.getClassName() + " is no interface"); } - if (this.equals(inter)) { + if (equals(inter)) { return true; } final JavaClass[] superInterfaces = getAllInterfaces(); @@ -664,7 +731,7 @@ public boolean implementationOf(final JavaClass inter) throws ClassNotFoundExcep * @throws ClassNotFoundException if superclasses or superinterfaces of this object can't be found */ public final boolean instanceOf(final JavaClass superclass) throws ClassNotFoundException { - if (this.equals(superclass)) { + if (equals(superclass)) { return true; } for (final JavaClass clazz : getSuperClasses()) { @@ -698,6 +765,17 @@ public final boolean isNested() { return this.isNested; } + /** + * Tests whether this class was declared as a record + * + * @return true if a record attribute is present, false otherwise. + * @since 6.9.0 + */ + public boolean isRecord() { + computeIsRecord(); + return this.isRecord; + } + public final boolean isSuper() { return (super.getAccessFlags() & Const.ACC_SUPER) != 0; } @@ -706,7 +784,7 @@ public final boolean isSuper() { * @param attributes . */ public void setAttributes(final Attribute[] attributes) { - this.attributes = attributes; + this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY; } /** @@ -734,11 +812,11 @@ public void setConstantPool(final ConstantPool constantPool) { * @param fields . */ public void setFields(final Field[] fields) { - this.fields = fields; + this.fields = fields != null ? fields : Field.EMPTY_ARRAY; } /** - * Set File name of class, aka SourceFile attribute value + * Sets File name of class, aka SourceFile attribute value */ public void setFileName(final String fileName) { this.fileName = fileName; @@ -748,14 +826,14 @@ public void setFileName(final String fileName) { * @param interfaceNames . */ public void setInterfaceNames(final String[] interfaceNames) { - this.interfaceNames = interfaceNames; + this.interfaceNames = Utils.createEmptyArrayIfNull(interfaceNames, String[].class); } /** * @param interfaces . */ public void setInterfaces(final int[] interfaces) { - this.interfaces = interfaces; + this.interfaces = Utils.createEmptyArrayIfNull(interfaces); } /** @@ -769,7 +847,7 @@ public void setMajor(final int major) { * @param methods . */ public void setMethods(final Method[] methods) { - this.methods = methods; + this.methods = methods != null ? methods : Method.EMPTY_ARRAY; } /** @@ -787,7 +865,7 @@ public void setRepository(final com.sun.org.apache.bcel.internal.util.Repository } /** - * Set absolute path to file this class was read from. + * Sets absolute path to file this class was read from. */ public void setSourceFileName(final String sourceFileName) { this.sourceFileName = sourceFileName; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumber.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumber.java index 4380d04bc06..dc41ad065f8 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumber.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumber.java @@ -40,11 +40,11 @@ public final class LineNumber implements Cloneable, Node { /** Program Counter (PC) corresponds to line */ private int startPc; - /** number in source file */ + /** Number in source file */ private int lineNumber; /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O Exception occurs in readUnsignedShort diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumberTable.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumberTable.java index 6251fc514cc..96541f309bd 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumberTable.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LineNumberTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -36,7 +36,7 @@ * * @see Code * @see LineNumber - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public final class LineNumberTable extends Attribute implements Iterable { @@ -44,7 +44,7 @@ public final class LineNumberTable extends Attribute implements Iterable + * Note that both objects use the same references (shallow copy). Use copy() for a physical copy. + *

*/ public LineNumberTable(final LineNumberTable c) { this(c.getNameIndex(), c.getLength(), c.getLineNumberTable(), c.getConstantPool()); @@ -190,7 +191,7 @@ public Iterator iterator() { * @param lineNumberTable the line number entries for this table */ public void setLineNumberTable(final LineNumber[] lineNumberTable) { - this.lineNumberTable = lineNumberTable; + this.lineNumberTable = lineNumberTable != null ? lineNumberTable : LineNumber.EMPTY_ARRAY; } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LocalVariableTable.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LocalVariableTable.java index fd56e14a539..26fde9bdbdf 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LocalVariableTable.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LocalVariableTable.java @@ -40,10 +40,12 @@ */ public class LocalVariableTable extends Attribute implements Iterable { + private static final LocalVariable[] EMPTY_ARRAY = {}; + private LocalVariable[] localVariableTable; // variables /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool * @param length Content length in bytes @@ -68,7 +70,7 @@ public class LocalVariableTable extends Attribute implements Iterable iterator() { } public final void setLocalVariableTable(final LocalVariable[] localVariableTable) { - this.localVariableTable = localVariableTable; + this.localVariableTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY; } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LocalVariableTypeTable.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LocalVariableTypeTable.java index 08868a82de8..ce327e20f52 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LocalVariableTypeTable.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/LocalVariableTypeTable.java @@ -63,14 +63,14 @@ */ public class LocalVariableTypeTable extends Attribute implements Iterable { + private static final LocalVariable[] EMPTY_ARRAY = {}; + private LocalVariable[] localVariableTypeTable; // variables LocalVariableTypeTable(final int nameIdx, final int len, final DataInput input, final ConstantPool cpool) throws IOException { this(nameIdx, len, (LocalVariable[]) null, cpool); - final int localVariableTypeTableLength = input.readUnsignedShort(); localVariableTypeTable = new LocalVariable[localVariableTypeTableLength]; - for (int i = 0; i < localVariableTypeTableLength; i++) { localVariableTypeTable[i] = new LocalVariable(input, cpool); } @@ -97,7 +97,6 @@ public void accept(final Visitor v) { @Override public Attribute copy(final ConstantPool constantPool) { final LocalVariableTypeTable c = (LocalVariableTypeTable) clone(); - c.localVariableTypeTable = new LocalVariable[localVariableTypeTable.length]; Arrays.setAll(c.localVariableTypeTable, i -> localVariableTypeTable[i].copy()); c.setConstantPool(constantPool); @@ -119,7 +118,6 @@ public final LocalVariable getLocalVariable(final int index) { return variable; } } - return null; } @@ -137,7 +135,7 @@ public Iterator iterator() { } public final void setLocalVariableTable(final LocalVariable[] localVariableTable) { - this.localVariableTypeTable = localVariableTable; + this.localVariableTypeTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY; } /** @@ -146,15 +144,12 @@ public final void setLocalVariableTable(final LocalVariable[] localVariableTable @Override public final String toString() { final StringBuilder buf = new StringBuilder(); - for (int i = 0; i < localVariableTypeTable.length; i++) { buf.append(localVariableTypeTable[i].toStringShared(true)); - if (i < localVariableTypeTable.length - 1) { buf.append('\n'); } } - return buf.toString(); } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Method.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Method.java index ba2623eec08..643c820f366 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Method.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Method.java @@ -40,42 +40,34 @@ public final class Method extends FieldOrMethod { */ public static final Method[] EMPTY_ARRAY = {}; - private static BCELComparator bcelComparator = new BCELComparator() { + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final Method THIS = (Method) o1; - final Method THAT = (Method) o2; - return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature()); + public boolean equals(final Method a, final Method b) { + return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature()); } @Override - public int hashCode(final Object o) { - final Method THIS = (Method) o; - return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + public int hashCode(final Method o) { + return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0; } }; /** - * Empty array. + * @return Comparison strategy object. */ - static final Method[] EMPTY_METHOD_ARRAY = {}; - - /** - * @return Comparison strategy object - */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } /** - * @param comparator Comparison strategy object + * @param comparator Comparison strategy object. */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } - // annotations defined on the parameters of a method + /** Annotations defined on the parameters of a method. */ private ParameterAnnotationEntry[] parameterAnnotationEntries; /** @@ -85,7 +77,7 @@ public Method() { } /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O error occurs. @@ -142,7 +134,7 @@ public Method copy(final ConstantPool constantPool) { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof Method && bcelComparator.equals(this, (Method) obj); } /** @@ -189,7 +181,7 @@ public LineNumberTable getLineNumberTable() { } /** - * @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code atribute. + * @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code attribute. */ public LocalVariableTable getLocalVariableTable() { final Code code = getCode(); @@ -199,6 +191,19 @@ public LocalVariableTable getLocalVariableTable() { return code.getLocalVariableTable(); } + /** + * Gets the local variable type table attribute {@link LocalVariableTypeTable}. + * @return LocalVariableTypeTable of code attribute if any, i.e. the call is forwarded to the Code attribute. + * @since 6.10.0 + */ + public LocalVariableTypeTable getLocalVariableTypeTable() { + final Code code = getCode(); + if (code == null) { + return null; + } + return code.getLocalVariableTypeTable(); + } + /** * @return Annotations on the parameters of a method * @since 6.0 @@ -218,7 +223,7 @@ public Type getReturnType() { } /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the method's name XOR + * Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR * signature. * * @see Object#hashCode() diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameter.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameter.java index ffc1a20f80a..865e154d334 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameter.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameter.java @@ -29,6 +29,9 @@ /** * Entry of the parameters table. + *

+ * Implements {@link Node} as of 6.7.0. + *

* * @see The class File Format : * The MethodParameters Attribute @@ -46,7 +49,7 @@ public MethodParameter() { } /** - * Construct object from input stream. + * Constructs an instance from a DataInput. * * @param input Input stream * @throws IOException if an I/O error occurs. @@ -75,7 +78,7 @@ public MethodParameter copy() { } /** - * Dump object to file stream on binary format. + * Dumps object to file stream on binary format. * * @param file Output file stream * @throws IOException if an I/O error occurs. @@ -94,7 +97,10 @@ public int getNameIndex() { } /** - * Returns the name of the parameter. + * Gets the name of the parameter. + * + * @param constantPool The pool to query. + * @return Constant from the given pool. */ public String getParameterName(final ConstantPool constantPool) { if (nameIndex == 0) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameters.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameters.java index 5b5d1d77f6f..2f5bffd8d3c 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameters.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/MethodParameters.java @@ -42,13 +42,12 @@ public class MethodParameters extends Attribute implements Iterable parameters[i].copy()); c.setConstantPool(constantPool); return c; @@ -96,6 +94,6 @@ public Iterator iterator() { } public void setParameters(final MethodParameter[] parameters) { - this.parameters = parameters; + this.parameters = parameters != null ? parameters : EMPTY_ARRAY; } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Module.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Module.java index 00eebe18245..addf6f0aea3 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Module.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Module.java @@ -44,19 +44,27 @@ public final class Module extends Attribute { */ public static final String EXTENSION = ".jmod"; + private static String getClassNameAtIndex(final ConstantPool cp, final int index, final boolean compactClassName) { + final String className = cp.getConstantString(index, Const.CONSTANT_Class); + if (compactClassName) { + return Utility.compactClassName(className, false); + } + return className; + } private final int moduleNameIndex; private final int moduleFlags; - private final int moduleVersionIndex; + private final int moduleVersionIndex; private ModuleRequires[] requiresTable; private ModuleExports[] exportsTable; private ModuleOpens[] opensTable; private final int usesCount; private final int[] usesIndex; + private ModuleProvides[] providesTable; /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool * @param length Content length in bytes @@ -113,8 +121,6 @@ public void accept(final Visitor v) { v.visitModule(this); } - // TODO add more getters and setters? - /** * @return deep copy of this attribute */ @@ -186,6 +192,25 @@ public ModuleExports[] getExportsTable() { return exportsTable; } + /** + * Gets flags for this module. + * @return module flags + * @since 6.10.0 + */ + public int getModuleFlags() { + return moduleFlags; + } + + /** + * Gets module name. + * @param cp Array of constants + * @return module name + * @since 6.10.0 + */ + public String getModuleName(final ConstantPool cp) { + return cp.getConstantString(moduleNameIndex, Const.CONSTANT_Module); + } + /** * @return table of provided interfaces * @see ModuleOpens @@ -210,6 +235,31 @@ public ModuleRequires[] getRequiresTable() { return requiresTable; } + /** + * Gets the array of class names for this module's uses. + * @param constantPool Array of constants usually obtained from the ClassFile object + * @param compactClassName false for original constant pool value, true to replace '/' with '.' + * @return array of used class names + * @since 6.10.0 + */ + public String[] getUsedClassNames(final ConstantPool constantPool, final boolean compactClassName) { + final String[] usedClassNames = new String[usesCount]; + for (int i = 0; i < usesCount; i++) { + usedClassNames[i] = getClassNameAtIndex(constantPool, usesIndex[i], compactClassName); + } + return usedClassNames; + } + + /** + * Gets version for this module. + * @param cp Array of constants + * @return version from constant pool, "0" if version index is 0 + * @since 6.10.0 + */ + public String getVersion(final ConstantPool cp) { + return moduleVersionIndex == 0 ? "0" : cp.getConstantString(moduleVersionIndex, Const.CONSTANT_Utf8); + } + /** * @return String representation, i.e., a list of packages. */ @@ -218,9 +268,9 @@ public String toString() { final ConstantPool cp = super.getConstantPool(); final StringBuilder buf = new StringBuilder(); buf.append("Module:\n"); - buf.append(" name: ").append(Utility.pathToPackage(cp.getConstantString(moduleNameIndex, Const.CONSTANT_Module))).append("\n"); + buf.append(" name: ").append(Utility.pathToPackage(getModuleName(cp))).append("\n"); buf.append(" flags: ").append(String.format("%04x", moduleFlags)).append("\n"); - final String version = moduleVersionIndex == 0 ? "0" : cp.getConstantString(moduleVersionIndex, Const.CONSTANT_Utf8); + final String version = getVersion(cp); buf.append(" version: ").append(version).append("\n"); buf.append(" requires(").append(requiresTable.length).append("):\n"); @@ -240,8 +290,8 @@ public String toString() { buf.append(" uses(").append(usesIndex.length).append("):\n"); for (final int index : usesIndex) { - final String className = cp.getConstantString(index, Const.CONSTANT_Class); - buf.append(" ").append(Utility.compactClassName(className, false)).append("\n"); + final String className = getClassNameAtIndex(cp, index, true); + buf.append(" ").append(className).append("\n"); } buf.append(" provides(").append(providesTable.length).append("):\n"); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleExports.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleExports.java index 8a97f4b6d08..f92f508b862 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleExports.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleExports.java @@ -36,13 +36,17 @@ */ public final class ModuleExports implements Cloneable, Node { + private static String getToModuleNameAtIndex(final ConstantPool constantPool, final int index) { + return constantPool.getConstantString(index, Const.CONSTANT_Module); + } private final int exportsIndex; // points to CONSTANT_Package_info private final int exportsFlags; private final int exportsToCount; + private final int[] exportsToIndex; // points to CONSTANT_Module_info /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O Exception occurs in readUnsignedShort @@ -68,8 +72,6 @@ public void accept(final Visitor v) { v.visitModuleExports(this); } - // TODO add more getters and setters? - /** * @return deep copy of this object */ @@ -97,6 +99,39 @@ public void dump(final DataOutputStream file) throws IOException { } } + /** + * Gets the flags for this ModuleExports. + * @return the exportsFlags + * @since 6.10.0 + */ + public int getExportsFlags() { + return exportsFlags; + } + + /** + * Gets the exported package name. + * @param constantPool the constant pool from the ClassFile + * @return the exported package name + * @since 6.10.0 + */ + public String getPackageName(final ConstantPool constantPool) { + return constantPool.constantToString(exportsIndex, Const.CONSTANT_Package); + } + + /** + * Gets an array of module names for this ModuleExports. + * @param constantPool Array of constants usually obtained from the ClassFile object + * @return array of module names following 'exports to' + * @since 6.10.0 + */ + public String[] getToModuleNames(final ConstantPool constantPool) { + final String[] toModuleNames = new String[exportsToCount]; + for (int i = 0; i < exportsToCount; i++) { + toModuleNames[i] = getToModuleNameAtIndex(constantPool, exportsToIndex[i]); + } + return toModuleNames; + } + /** * @return String representation */ @@ -110,13 +145,13 @@ public String toString() { */ public String toString(final ConstantPool constantPool) { final StringBuilder buf = new StringBuilder(); - final String packageName = constantPool.constantToString(exportsIndex, Const.CONSTANT_Package); - buf.append(Utility.compactClassName(packageName, false)); + final String packageName = getPackageName(constantPool); + buf.append(packageName); buf.append(", ").append(String.format("%04x", exportsFlags)); buf.append(", to(").append(exportsToCount).append("):\n"); for (final int index : exportsToIndex) { - final String moduleName = constantPool.getConstantString(index, Const.CONSTANT_Module); - buf.append(" ").append(Utility.compactClassName(moduleName, false)).append("\n"); + final String moduleName = getToModuleNameAtIndex(constantPool, index); + buf.append(" ").append(moduleName).append("\n"); } return buf.substring(0, buf.length() - 1); // remove the last newline } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleMainClass.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleMainClass.java index a6ffd882862..b73bd01f794 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleMainClass.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleMainClass.java @@ -39,7 +39,7 @@ public final class ModuleMainClass extends Attribute { private int mainClassIndex; /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool * @param length Content length in bytes diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleOpens.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleOpens.java index 06b404df72b..388370a45e7 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleOpens.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleOpens.java @@ -36,13 +36,17 @@ */ public final class ModuleOpens implements Cloneable, Node { + private static String getToModuleNameAtIndex(final ConstantPool constantPool, final int index) { + return constantPool.getConstantString(index, Const.CONSTANT_Module); + } private final int opensIndex; // points to CONSTANT_Package_info private final int opensFlags; private final int opensToCount; + private final int[] opensToIndex; // points to CONSTANT_Module_info /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O Exception occurs in readUnsignedShort @@ -68,8 +72,6 @@ public void accept(final Visitor v) { v.visitModuleOpens(this); } - // TODO add more getters and setters? - /** * @return deep copy of this object */ @@ -97,6 +99,39 @@ public void dump(final DataOutputStream file) throws IOException { } } + /** + * Gets the flags for this ModuleOpens. + * @return the opensFlags + * @since 6.10.0 + */ + public int getOpensFlags() { + return opensFlags; + } + + /** + * Gets the opened package name. + * @param constantPool the constant pool from the ClassFile + * @return the opened package name + * @since 6.10.0 + */ + public String getPackageName(final ConstantPool constantPool) { + return constantPool.constantToString(opensIndex, Const.CONSTANT_Package); + } + + /** + * Gets an array of module names for this ModuleOpens. + * @param constantPool Array of constants usually obtained from the ClassFile object + * @return array of module names following 'opens to' + * @since 6.10.0 + */ + public String[] getToModuleNames(final ConstantPool constantPool) { + final String[] toModuleNames = new String[opensToCount]; + for (int i = 0; i < opensToCount; i++) { + toModuleNames[i] = getToModuleNameAtIndex(constantPool, opensToIndex[i]); + } + return toModuleNames; + } + /** * @return String representation */ @@ -110,13 +145,13 @@ public String toString() { */ public String toString(final ConstantPool constantPool) { final StringBuilder buf = new StringBuilder(); - final String packageName = constantPool.constantToString(opensIndex, Const.CONSTANT_Package); - buf.append(Utility.compactClassName(packageName, false)); + final String packageName = getPackageName(constantPool); + buf.append(packageName); buf.append(", ").append(String.format("%04x", opensFlags)); buf.append(", to(").append(opensToCount).append("):\n"); for (final int index : opensToIndex) { - final String moduleName = constantPool.getConstantString(index, Const.CONSTANT_Module); - buf.append(" ").append(Utility.compactClassName(moduleName, false)).append("\n"); + final String moduleName = getToModuleNameAtIndex(constantPool, index); + buf.append(" ").append(moduleName).append("\n"); } return buf.substring(0, buf.length() - 1); // remove the last newline } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModulePackages.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModulePackages.java index 96367e02d2d..f48587e5455 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModulePackages.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModulePackages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,20 +27,21 @@ import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.util.Args; +import jdk.xml.internal.Utils; /** * This class is derived from Attribute and represents the list of packages that are exported or opened by the * Module attribute. There may be at most one ModulePackages attribute in a ClassFile structure. * * @see Attribute - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class ModulePackages extends Attribute { private int[] packageIndexTable; /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool * @param length Content length in bytes @@ -65,7 +66,7 @@ public final class ModulePackages extends Attribute { */ public ModulePackages(final int nameIndex, final int length, final int[] packageIndexTable, final ConstantPool constantPool) { super(Const.ATTR_MODULE_PACKAGES, nameIndex, length, constantPool); - this.packageIndexTable = packageIndexTable != null ? packageIndexTable : Const.EMPTY_INT_ARRAY; + this.packageIndexTable = Utils.createEmptyArrayIfNull(packageIndexTable); Args.requireU2(this.packageIndexTable.length, "packageIndexTable.length"); } @@ -145,7 +146,7 @@ public String[] getPackageNames() { * @param packageIndexTable the list of package indexes Also redefines number_of_packages according to table length. */ public void setPackageIndexTable(final int[] packageIndexTable) { - this.packageIndexTable = packageIndexTable != null ? packageIndexTable : Const.EMPTY_INT_ARRAY; + this.packageIndexTable = Utils.createEmptyArrayIfNull(packageIndexTable); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleProvides.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleProvides.java index f6c6058dfbb..490e9cd5d44 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleProvides.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleProvides.java @@ -36,12 +36,20 @@ */ public final class ModuleProvides implements Cloneable, Node { + private static String getImplementationClassNameAtIndex(final ConstantPool constantPool, final int index, final boolean compactClassName) { + final String className = constantPool.getConstantString(index, Const.CONSTANT_Class); + if (compactClassName) { + return Utility.compactClassName(className, false); + } + return className; + } private final int providesIndex; // points to CONSTANT_Class_info private final int providesWithCount; + private final int[] providesWithIndex; // points to CONSTANT_Class_info /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O Exception occurs in readUnsignedShort @@ -66,8 +74,6 @@ public void accept(final Visitor v) { v.visitModuleProvides(this); } - // TODO add more getters and setters? - /** * @return deep copy of this object */ @@ -94,6 +100,31 @@ public void dump(final DataOutputStream file) throws IOException { } } + /** + * Gets the array of implementation class names for this ModuleProvides. + * @param constantPool Array of constants usually obtained from the ClassFile object + * @param compactClassName false for original constant pool value, true to replace '/' with '.' + * @return array of implementation class names + * @since 6.10.0 + */ + public String[] getImplementationClassNames(final ConstantPool constantPool, final boolean compactClassName) { + final String[] implementationClassNames = new String[providesWithCount]; + for (int i = 0; i < providesWithCount; i++) { + implementationClassNames[i] = getImplementationClassNameAtIndex(constantPool, providesWithIndex[i], compactClassName); + } + return implementationClassNames; + } + + /** + * Gets the interface name for this ModuleProvides. + * @param constantPool Array of constants usually obtained from the ClassFile object + * @return interface name + * @since 6.10.0 + */ + public String getInterfaceName(final ConstantPool constantPool) { + return constantPool.constantToString(providesIndex, Const.CONSTANT_Class); + } + /** * @return String representation */ @@ -107,12 +138,12 @@ public String toString() { */ public String toString(final ConstantPool constantPool) { final StringBuilder buf = new StringBuilder(); - final String interfaceName = constantPool.constantToString(providesIndex, Const.CONSTANT_Class); - buf.append(Utility.compactClassName(interfaceName, false)); + final String interfaceName = getInterfaceName(constantPool); + buf.append(interfaceName); buf.append(", with(").append(providesWithCount).append("):\n"); for (final int index : providesWithIndex) { - final String className = constantPool.getConstantString(index, Const.CONSTANT_Class); - buf.append(" ").append(Utility.compactClassName(className, false)).append("\n"); + final String className = getImplementationClassNameAtIndex(constantPool, index, true); + buf.append(" ").append(className).append("\n"); } return buf.substring(0, buf.length() - 1); // remove the last newline } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleRequires.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleRequires.java index c9c26c20649..3149a18290b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleRequires.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ModuleRequires.java @@ -41,7 +41,7 @@ public final class ModuleRequires implements Cloneable, Node { private final int requiresVersionIndex; // either 0 or points to CONSTANT_Utf8_info /** - * Construct object from file stream. + * Constructs object from file stream. * * @param file Input stream * @throws IOException if an I/O Exception occurs in readUnsignedShort @@ -63,8 +63,6 @@ public void accept(final Visitor v) { v.visitModuleRequires(this); } - // TODO add more getters and setters? - /** * @return deep copy of this object */ @@ -89,6 +87,35 @@ public void dump(final DataOutputStream file) throws IOException { file.writeShort(requiresVersionIndex); } + /** + * Gets the module name from the constant pool. + * @param constantPool Array of constants usually obtained from the ClassFile object + * @return module name + * @since 6.10.0 + */ + public String getModuleName(final ConstantPool constantPool) { + return constantPool.constantToString(requiresIndex, Const.CONSTANT_Module); + } + + /** + * Gets the flags for this ModuleRequires. + * @return the requiresFlags + * @since 6.10.0 + */ + public int getRequiresFlags() { + return requiresFlags; + } + + /** + * Gets the required version from the constant pool. + * @param constantPool Array of constants usually obtained from the ClassFile object + * @return required version, "0" if version index is 0. + * @since 6.10.0 + */ + public String getVersion(final ConstantPool constantPool) { + return requiresVersionIndex == 0 ? "0" : constantPool.getConstantString(requiresVersionIndex, Const.CONSTANT_Utf8); + } + /** * @return String representation */ @@ -102,10 +129,10 @@ public String toString() { */ public String toString(final ConstantPool constantPool) { final StringBuilder buf = new StringBuilder(); - final String moduleName = constantPool.constantToString(requiresIndex, Const.CONSTANT_Module); - buf.append(Utility.compactClassName(moduleName, false)); + final String moduleName = getModuleName(constantPool); + buf.append(moduleName); buf.append(", ").append(String.format("%04x", requiresFlags)); - final String version = requiresVersionIndex == 0 ? "0" : constantPool.getConstantString(requiresVersionIndex, Const.CONSTANT_Utf8); + final String version = getVersion(constantPool); buf.append(", ").append(version); return buf.toString(); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/NestMembers.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/NestMembers.java index 05d982ca6e8..261f57d98a8 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/NestMembers.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/NestMembers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,6 +27,7 @@ import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.util.Args; +import jdk.xml.internal.Utils; /** * This class is derived from Attribute and records the classes and interfaces that are authorized to claim @@ -34,14 +35,14 @@ * ClassFile structure. * * @see Attribute - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class NestMembers extends Attribute { private int[] classes; /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool * @param length Content length in bytes @@ -66,7 +67,7 @@ public final class NestMembers extends Attribute { */ public NestMembers(final int nameIndex, final int length, final int[] classes, final ConstantPool constantPool) { super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool); - this.classes = classes != null ? classes : Const.EMPTY_INT_ARRAY; + this.classes = Utils.createEmptyArrayIfNull(classes); Args.requireU2(this.classes.length, "classes.length"); } @@ -146,7 +147,7 @@ public int getNumberClasses() { * @param classes the list of class indexes Also redefines number_of_classes according to table length. */ public void setClasses(final int[] classes) { - this.classes = classes != null ? classes : Const.EMPTY_INT_ARRAY; + this.classes = Utils.createEmptyArrayIfNull(classes); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Node.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Node.java index c0395732d79..792ef31cb72 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Node.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Node.java @@ -26,5 +26,5 @@ */ public interface Node { - void accept(Visitor obj); + void accept(Visitor visitor); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/PMGClass.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/PMGClass.java index 9b1dd4c7b41..b7b5e1f1d99 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/PMGClass.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/PMGClass.java @@ -38,7 +38,7 @@ public final class PMGClass extends Attribute { private int pmgIndex; /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotationEntry.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotationEntry.java index a3070fa7e0c..6ebe60c8049 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotationEntry.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotationEntry.java @@ -37,22 +37,28 @@ public class ParameterAnnotationEntry implements Node { static final ParameterAnnotationEntry[] EMPTY_ARRAY = {}; - public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attrs) { + public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attributes) { + if (attributes == null) { + return EMPTY_ARRAY; + } // Find attributes that contain parameter annotation data - final List accumulatedAnnotations = new ArrayList<>(attrs.length); - for (final Attribute attribute : attrs) { + final List accumulatedAnnotations = new ArrayList<>(attributes.length); + for (final Attribute attribute : attributes) { if (attribute instanceof ParameterAnnotations) { final ParameterAnnotations runtimeAnnotations = (ParameterAnnotations) attribute; - Collections.addAll(accumulatedAnnotations, runtimeAnnotations.getParameterAnnotationEntries()); + final ParameterAnnotationEntry[] parameterAnnotationEntries = runtimeAnnotations.getParameterAnnotationEntries(); + if (parameterAnnotationEntries != null) { + Collections.addAll(accumulatedAnnotations, parameterAnnotationEntries); + } } } - return accumulatedAnnotations.toArray(ParameterAnnotationEntry.EMPTY_ARRAY); + return accumulatedAnnotations.toArray(EMPTY_ARRAY); } private final AnnotationEntry[] annotationTable; /** - * Construct object from input stream. + * Constructs object from input stream. * * @param input Input stream * @throws IOException if an I/O error occurs. diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotations.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotations.java index 4817793120f..1e056b5d4f8 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotations.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ParameterAnnotations.java @@ -34,10 +34,14 @@ */ public abstract class ParameterAnnotations extends Attribute implements Iterable { + private static final ParameterAnnotationEntry[] EMPTY_ARRAY = {}; + /** Table of parameter annotations */ private ParameterAnnotationEntry[] parameterAnnotationTable; /** + * Constructs a new instance. + * * @param parameterAnnotationType the subclass type of the parameter annotation * @param nameIndex Index pointing to the name Code * @param length Content length in bytes @@ -55,6 +59,8 @@ public abstract class ParameterAnnotations extends Attribute implements Iterable } /** + * Constructs a new instance. + * * @param parameterAnnotationType the subclass type of the parameter annotation * @param nameIndex Index pointing to the name Code * @param length Content length in bytes @@ -120,6 +126,6 @@ public Iterator iterator() { * @param parameterAnnotationTable the entries to set in this parameter annotation */ public final void setParameterAnnotationTable(final ParameterAnnotationEntry[] parameterAnnotationTable) { - this.parameterAnnotationTable = parameterAnnotationTable; + this.parameterAnnotationTable = parameterAnnotationTable != null ? parameterAnnotationTable : EMPTY_ARRAY; } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Record.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Record.java new file mode 100644 index 00000000000..f59cfa37ca4 --- /dev/null +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Record.java @@ -0,0 +1,153 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.sun.org.apache.bcel.internal.classfile; + +import java.io.DataInput; +import java.io.DataOutputStream; +import java.io.IOException; + +import com.sun.org.apache.bcel.internal.Const; +import com.sun.org.apache.bcel.internal.util.Args; + +/** + * Extends {@link Attribute} and records the classes and + * interfaces that are authorized to claim membership in the nest hosted by the + * current class or interface. There may be at most one Record attribute in a + * ClassFile structure. + * + * @see Attribute + * @since 6.9.0 + */ +public final class Record extends Attribute { + + private static final RecordComponentInfo[] EMPTY_RCI_ARRAY = {}; + + private static RecordComponentInfo[] readComponents(final DataInput input, final ConstantPool constantPool) + throws IOException { + final int classCount = input.readUnsignedShort(); + final RecordComponentInfo[] components = new RecordComponentInfo[classCount]; + for (int i = 0; i < classCount; i++) { + components[i] = new RecordComponentInfo(input, constantPool); + } + return components; + } + + private RecordComponentInfo[] components; + + /** + * Constructs object from input stream. + * + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param input Input stream + * @param constantPool Array of constants + * @throws IOException if an I/O error occurs. + */ + Record(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) + throws IOException { + this(nameIndex, length, readComponents(input, constantPool), constantPool); + } + + /** + * Constructs a new instance using components. + * + * @param nameIndex Index in constant pool + * @param length Content length in bytes + * @param classes Array of Record Component Info elements + * @param constantPool Array of constants + */ + public Record(final int nameIndex, final int length, final RecordComponentInfo[] classes, + final ConstantPool constantPool) { + super(Const.ATTR_RECORD, nameIndex, length, constantPool); + this.components = classes != null ? classes : EMPTY_RCI_ARRAY; + Args.requireU2(this.components.length, "attributes.length"); + } + + /** + * Called by objects that are traversing the nodes of the tree implicitly + * defined by the contents of a Java class. For example, the hierarchy of methods, + * fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + @Override + public void accept(final Visitor v) { + v.visitRecord(this); + } + + /** + * Copies this instance and its components. + * + * @return a deep copy of this instance and its components. + */ + @Override + public Attribute copy(final ConstantPool constantPool) { + final Record c = (Record) clone(); + if (components.length > 0) { + c.components = components.clone(); + } + c.setConstantPool(constantPool); + return c; + } + + /** + * Dumps this instance into a file stream in binary format. + * + * @param file output stream. + * @throws IOException if an I/O error occurs. + */ + @Override + public void dump(final DataOutputStream file) throws IOException { + super.dump(file); + file.writeShort(components.length); + for (final RecordComponentInfo component : components) { + component.dump(file); + } + } + + /** + * Gets all the record components. + * + * @return array of Record Component Info elements. + */ + public RecordComponentInfo[] getComponents() { + return components; + } + + /** + * Converts this instance to a String suitable for debugging. + * + * @return String a String suitable for debugging. + */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder(); + buf.append("Record("); + buf.append(components.length); + buf.append("):\n"); + for (final RecordComponentInfo component : components) { + buf.append(" ").append(component.toString()).append("\n"); + } + return buf.substring(0, buf.length() - 1); // remove the last newline + } + +} diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RecordComponentInfo.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RecordComponentInfo.java new file mode 100644 index 00000000000..3679647d409 --- /dev/null +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RecordComponentInfo.java @@ -0,0 +1,139 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.sun.org.apache.bcel.internal.classfile; + +import java.io.DataInput; +import java.io.DataOutputStream; +import java.io.IOException; + +import com.sun.org.apache.bcel.internal.Const; + +/** + * Record component info from a record. Instances from this class maps + * every component from a given record. + * + * @see + * The Java Virtual Machine Specification, Java SE 14 Edition, Records (preview) + * @since 6.9.0 + */ +public class RecordComponentInfo implements Node { + + private final int index; + private final int descriptorIndex; + private final Attribute[] attributes; + private final ConstantPool constantPool; + + /** + * Constructs a new instance from an input stream. + * + * @param input Input stream + * @param constantPool Array of constants + * @throws IOException if an I/O error occurs. + */ + public RecordComponentInfo(final DataInput input, final ConstantPool constantPool) throws IOException { + this.index = input.readUnsignedShort(); + this.descriptorIndex = input.readUnsignedShort(); + final int attributesCount = input.readUnsignedShort(); + this.attributes = new Attribute[attributesCount]; + for (int j = 0; j < attributesCount; j++) { + attributes[j] = Attribute.readAttribute(input, constantPool); + } + this.constantPool = constantPool; + } + + @Override + public void accept(final Visitor v) { + v.visitRecordComponent(this); + } + + /** + * Dumps contents into a file stream in binary format. + * + * @param file Output file stream + * @throws IOException if an I/O error occurs. + */ + public void dump(final DataOutputStream file) throws IOException { + file.writeShort(index); + file.writeShort(descriptorIndex); + file.writeShort(attributes.length); + for (final Attribute attribute : attributes) { + attribute.dump(file); + } + } + + /** + * Gets all attributes. + * + * @return all attributes. + */ + public Attribute[] getAttributes() { + return attributes; + } + + /** + * Gets the constant pool. + * + * @return Constant pool. + */ + public ConstantPool getConstantPool() { + return constantPool; + } + + /** + * Gets the description index. + * + * @return index in constant pool of this record component descriptor. + */ + public int getDescriptorIndex() { + return descriptorIndex; + } + + /** + * Gets the name index. + * + * @return index in constant pool of this record component name. + */ + public int getIndex() { + return index; + } + + /** + * Converts this instance to a String suitable for debugging. + * + * @return a String suitable for debugging. + */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder(); + buf.append("RecordComponentInfo("); + buf.append(constantPool.getConstantString(index, Const.CONSTANT_Utf8)); + buf.append(","); + buf.append(constantPool.getConstantString(descriptorIndex, Const.CONSTANT_Utf8)); + buf.append(","); + buf.append(attributes.length); + buf.append("):\n"); + for (final Attribute attribute : attributes) { + buf.append(" ").append(attribute.toString()).append("\n"); + } + return buf.substring(0, buf.length() - 1); // remove the last newline + } + +} diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleAnnotations.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleAnnotations.java index 7afb8719559..7a7c539f15a 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleAnnotations.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleAnnotations.java @@ -28,13 +28,15 @@ import com.sun.org.apache.bcel.internal.Const; /** - * represents an annotation that is represented in the class file but is not provided to the JVM. + * An annotation that is represented in the class file but is not provided to the JVM. * * @since 6.0 */ public class RuntimeInvisibleAnnotations extends Annotations { /** + * Constructs a new instance. + * * @param nameIndex Index pointing to the name Code * @param length Content length in bytes * @param input Input stream @@ -46,7 +48,9 @@ public RuntimeInvisibleAnnotations(final int nameIndex, final int length, final } /** - * @return deep copy of this attribute + * Creates a deep copy of this attribute. + * + * @return deep copy of this attribute. */ @Override public Attribute copy(final ConstantPool constantPool) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleParameterAnnotations.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleParameterAnnotations.java index e4c3276f968..3d50ce16d40 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleParameterAnnotations.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeInvisibleParameterAnnotations.java @@ -34,6 +34,8 @@ public class RuntimeInvisibleParameterAnnotations extends ParameterAnnotations { /** + * Constructs a new instance. + * * @param nameIndex Index pointing to the name Code * @param length Content length in bytes * @param input Input stream diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleAnnotations.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleAnnotations.java index c91c77387b9..4bf8e6f7197 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleAnnotations.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleAnnotations.java @@ -28,13 +28,15 @@ import com.sun.org.apache.bcel.internal.Const; /** - * represents an annotation that is represented in the class file and is provided to the JVM. + * An annotation that is represented in the class file and is provided to the JVM. * * @since 6.0 */ public class RuntimeVisibleAnnotations extends Annotations { /** + * Constructs a new instance. + * * @param nameIndex Index pointing to the name Code * @param length Content length in bytes * @param input Input stream @@ -46,7 +48,9 @@ public RuntimeVisibleAnnotations(final int nameIndex, final int length, final Da } /** - * @return deep copy of this attribute + * Creates a deep copy of this attribute. + * + * @return deep copy of this attribute. */ @Override public Attribute copy(final ConstantPool constantPool) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleParameterAnnotations.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleParameterAnnotations.java index 7e5d7eaaca3..ab5355235f6 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleParameterAnnotations.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/RuntimeVisibleParameterAnnotations.java @@ -34,6 +34,8 @@ public class RuntimeVisibleParameterAnnotations extends ParameterAnnotations { /** + * Constructs a new instance. + * * @param nameIndex Index pointing to the name Code * @param length Content length in bytes * @param input Input stream diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Signature.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Signature.java index 4f5d3a341b3..2161bbcb6ec 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Signature.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Signature.java @@ -110,7 +110,7 @@ private static void matchIdent(final MyByteArrayInputStream in, final StringBuil if ((ch = in.read()) == -1) { throw new IllegalArgumentException("Illegal signature: " + in.getData() + " no ident, reaching EOF"); } - // System.out.println("return from ident:" + (char)ch); + // System.out.println("return from ident:" + (char) ch); if (!identStart(ch)) { final StringBuilder buf2 = new StringBuilder(); int count = 1; @@ -128,7 +128,7 @@ private static void matchIdent(final MyByteArrayInputStream in, final StringBuil buf.append(buf2); ch = in.read(); in.unread(); - // System.out.println("so far:" + buf2 + ":next:" +(char)ch); + // System.out.println("so far:" + buf2 + ":next:" +(char) ch); } else { for (int i = 0; i < count; i++) { in.unread(); @@ -141,10 +141,10 @@ private static void matchIdent(final MyByteArrayInputStream in, final StringBuil do { buf2.append((char) ch); ch = in.read(); - // System.out.println("within ident:"+ (char)ch); + // System.out.println("within ident:"+ (char) ch); } while (ch != -1 && (Character.isJavaIdentifierPart((char) ch) || ch == '/')); buf.append(Utility.pathToPackage(buf2.toString())); - // System.out.println("regular return ident:"+ (char)ch + ":" + buf2); + // System.out.println("regular return ident:"+ (char) ch + ":" + buf2); if (ch != -1) { in.unread(); } @@ -160,7 +160,7 @@ public static String translate(final String s) { private int signatureIndex; /** - * Construct object from file stream. + * Constructs object from file stream. * * @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SimpleElementValue.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SimpleElementValue.java index 5e4e98d94df..e3e1cf40031 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SimpleElementValue.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SimpleElementValue.java @@ -54,7 +54,7 @@ public void dump(final DataOutputStream dos) throws IOException { dos.writeShort(getIndex()); break; default: - throw new ClassFormatException("SimpleElementValue doesnt know how to write out type " + type); + throw new ClassFormatException("SimpleElementValue doesn't know how to write out type " + type); } } @@ -67,7 +67,7 @@ public int getIndex() { public boolean getValueBoolean() { if (super.getType() != PRIMITIVE_BOOLEAN) { - throw new IllegalStateException("Dont call getValueBoolean() on a non BOOLEAN ElementValue"); + throw new IllegalStateException("Don't call getValueBoolean() on a non BOOLEAN ElementValue"); } final ConstantInteger bo = (ConstantInteger) super.getConstantPool().getConstant(getIndex()); return bo.getBytes() != 0; @@ -75,21 +75,21 @@ public boolean getValueBoolean() { public byte getValueByte() { if (super.getType() != PRIMITIVE_BYTE) { - throw new IllegalStateException("Dont call getValueByte() on a non BYTE ElementValue"); + throw new IllegalStateException("Don't call getValueByte() on a non BYTE ElementValue"); } return (byte) super.getConstantPool().getConstantInteger(getIndex()).getBytes(); } public char getValueChar() { if (super.getType() != PRIMITIVE_CHAR) { - throw new IllegalStateException("Dont call getValueChar() on a non CHAR ElementValue"); + throw new IllegalStateException("Don't call getValueChar() on a non CHAR ElementValue"); } return (char) super.getConstantPool().getConstantInteger(getIndex()).getBytes(); } public double getValueDouble() { if (super.getType() != PRIMITIVE_DOUBLE) { - throw new IllegalStateException("Dont call getValueDouble() on a non DOUBLE ElementValue"); + throw new IllegalStateException("Don't call getValueDouble() on a non DOUBLE ElementValue"); } final ConstantDouble d = (ConstantDouble) super.getConstantPool().getConstant(getIndex()); return d.getBytes(); @@ -97,7 +97,7 @@ public double getValueDouble() { public float getValueFloat() { if (super.getType() != PRIMITIVE_FLOAT) { - throw new IllegalStateException("Dont call getValueFloat() on a non FLOAT ElementValue"); + throw new IllegalStateException("Don't call getValueFloat() on a non FLOAT ElementValue"); } final ConstantFloat f = (ConstantFloat) super.getConstantPool().getConstant(getIndex()); return f.getBytes(); @@ -105,14 +105,14 @@ public float getValueFloat() { public int getValueInt() { if (super.getType() != PRIMITIVE_INT) { - throw new IllegalStateException("Dont call getValueInt() on a non INT ElementValue"); + throw new IllegalStateException("Don't call getValueInt() on a non INT ElementValue"); } return super.getConstantPool().getConstantInteger(getIndex()).getBytes(); } public long getValueLong() { if (super.getType() != PRIMITIVE_LONG) { - throw new IllegalStateException("Dont call getValueLong() on a non LONG ElementValue"); + throw new IllegalStateException("Don't call getValueLong() on a non LONG ElementValue"); } final ConstantLong j = (ConstantLong) super.getConstantPool().getConstant(getIndex()); return j.getBytes(); @@ -120,7 +120,7 @@ public long getValueLong() { public short getValueShort() { if (super.getType() != PRIMITIVE_SHORT) { - throw new IllegalStateException("Dont call getValueShort() on a non SHORT ElementValue"); + throw new IllegalStateException("Don't call getValueShort() on a non SHORT ElementValue"); } final ConstantInteger s = (ConstantInteger) super.getConstantPool().getConstant(getIndex()); return (short) s.getBytes(); @@ -128,7 +128,7 @@ public short getValueShort() { public String getValueString() { if (super.getType() != STRING) { - throw new IllegalStateException("Dont call getValueString() on a non STRING ElementValue"); + throw new IllegalStateException("Don't call getValueString() on a non STRING ElementValue"); } return super.getConstantPool().getConstantUtf8(getIndex()).getBytes(); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SourceFile.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SourceFile.java index e9ceed21957..bfa9cbf8fcb 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SourceFile.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/SourceFile.java @@ -40,7 +40,7 @@ public final class SourceFile extends Attribute { private int sourceFileIndex; /** - * Construct object from input stream. + * Constructs object from input stream. * * @param nameIndex Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMap.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMap.java index 1f8ce5ea410..317638e6b2d 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMap.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMap.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,8 +30,8 @@ /** * This class represents a stack map attribute used for preverification of Java classes for the - * Java 2 Micro Edition (J2ME). This attribute is used by the - * KVM and contained within the Code attribute of a method. See CLDC + * Java 2 Micro Edition (J2ME). This attribute is used by the + * KVM and contained within the Code attribute of a method. See CLDC * specification 5.3.1.2 * *
@@ -46,14 +46,14 @@
  * @see Code
  * @see StackMapEntry
  * @see StackMapType
- * @LastModified: Oct 2020
+ * @LastModified: Sept 2025
  */
 public final class StackMap extends Attribute {
 
     private StackMapEntry[] table; // Table of stack map entries
 
     /**
-     * Construct object from input stream.
+     * Constructs object from input stream.
      *
      * @param nameIndex Index of name
      * @param length Content length in bytes
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapEntry.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapEntry.java
index 110e30392ab..015083dd066 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapEntry.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapEntry.java
@@ -59,7 +59,7 @@ public final class StackMapEntry implements Node, Cloneable {
     private ConstantPool constantPool;
 
     /**
-     * Construct object from input stream.
+     * Constructs object from input stream.
      *
      * @param dataInput Input stream
      * @throws IOException if an I/O error occurs.
@@ -75,9 +75,7 @@ public final class StackMapEntry implements Node, Cloneable {
         } else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
             byteCodeOffset = dataInput.readUnsignedShort();
             typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) };
-        } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) {
-            byteCodeOffset = dataInput.readUnsignedShort();
-        } else if (frameType == Const.SAME_FRAME_EXTENDED) {
+        } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX || frameType == Const.SAME_FRAME_EXTENDED) {
             byteCodeOffset = dataInput.readUnsignedShort();
         } else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
             byteCodeOffset = dataInput.readUnsignedShort();
@@ -167,7 +165,7 @@ public StackMapEntry copy() {
         try {
             e = (StackMapEntry) clone();
         } catch (final CloneNotSupportedException ex) {
-            throw new Error("Clone Not Supported");
+            throw new UnsupportedOperationException("Clone Not Supported", ex);
         }
 
         e.typesOfLocals = new StackMapType[typesOfLocals.length];
@@ -190,9 +188,7 @@ public void dump(final DataOutputStream file) throws IOException {
         } else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
             file.writeShort(byteCodeOffset);
             typesOfStackItems[0].dump(file);
-        } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) {
-            file.writeShort(byteCodeOffset);
-        } else if (frameType == Const.SAME_FRAME_EXTENDED) {
+        } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX || frameType == Const.SAME_FRAME_EXTENDED) {
             file.writeShort(byteCodeOffset);
         } else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
             file.writeShort(byteCodeOffset);
@@ -232,7 +228,6 @@ public int getFrameType() {
 
     /**
      * Calculate stack map entry size
-     *
      */
     int getMapEntrySize() {
         if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapType.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapType.java
index 4575b31dfce..b93066d53b7 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapType.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/StackMapType.java
@@ -34,9 +34,9 @@
  * @see StackMap
  * @see Const
  */
-public final class StackMapType implements Cloneable {
+public final class StackMapType implements Node, Cloneable {
 
-    public static final StackMapType[] EMPTY_ARRAY = {}; // must be public because BCELifier code generator writes calls to it
+    public static final StackMapType[] EMPTY_ARRAY = {}; // BCELifier code generator writes calls to constructor translating null to EMPTY_ARRAY
 
     private byte type;
     private int index = -1; // Index to CONSTANT_Class or offset
@@ -53,7 +53,7 @@ public StackMapType(final byte type, final int index, final ConstantPool constan
     }
 
     /**
-     * Construct object from file stream.
+     * Constructs object from file stream.
      *
      * @param file Input stream
      * @throws IOException if an I/O error occurs.
@@ -66,6 +66,18 @@ public StackMapType(final byte type, final int index, final ConstantPool constan
         this.constantPool = constantPool;
     }
 
+    /**
+     * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
+     * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
+     *
+     * @param v Visitor object
+     * @since 6.8.0
+     */
+    @Override
+    public void accept(final Visitor v) {
+        v.visitStackMapType(this);
+    }
+
     private byte checkType(final byte type) {
         if (type < Const.ITEM_Bogus || type > Const.ITEM_NewObject) {
             throw new ClassFormatException("Illegal type for StackMapType: " + type);
@@ -98,6 +110,15 @@ public void dump(final DataOutputStream file) throws IOException {
         }
     }
 
+    /**
+     * Gets the class name of this StackMapType from the constant pool at index position.
+     * @return the fully qualified name of the class for this StackMapType.
+     * @since 6.8.0
+     */
+    public String getClassName() {
+        return constantPool.constantToString(index, Const.CONSTANT_Class);
+    }
+
     /**
      * @return Constant pool used by this object.
      */
@@ -129,7 +150,7 @@ private String printIndex() {
             if (index < 0) {
                 return ", class=";
             }
-            return ", class=" + constantPool.constantToString(index, Const.CONSTANT_Class);
+            return ", class=" + getClassName();
         }
         if (type == Const.ITEM_NewObject) {
             return ", offset=" + index;
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Synthetic.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Synthetic.java
index 3683fd6437e..c7fef8fcebc 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Synthetic.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Synthetic.java
@@ -52,7 +52,7 @@ public Synthetic(final int nameIndex, final int length, final byte[] bytes, fina
     }
 
     /**
-     * Construct object from input stream.
+     * Constructs object from input stream.
      *
      * @param nameIndex Index in constant pool to CONSTANT_Utf8
      * @param length Content length in bytes
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Utility.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Utility.java
index 12dbbe4828a..6967dcefd94 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Utility.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Utility.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -43,7 +43,7 @@
 /**
  * Utility functions that do not really belong to any class in particular.
  *
- * @LastModified: Feb 2023
+ * @LastModified: Sept 2025
  */
 // @since 6.0 methods are no longer final
 public abstract class Utility {
@@ -51,7 +51,7 @@ public abstract class Utility {
     /**
      * Decode characters into bytes. Used by decode()
      */
-    private static class JavaReader extends FilterReader {
+    private static final class JavaReader extends FilterReader {
 
         public JavaReader(final Reader in) {
             super(in);
@@ -88,10 +88,10 @@ public int read(final char[] cbuf, final int off, final int len) throws IOExcept
     }
 
     /**
-     * Encode bytes into valid java identifier characters. Used by
+     * Encode bytes into valid Java identifier characters. Used by
      * encode()
      */
-    private static class JavaWriter extends FilterWriter {
+    private static final class JavaWriter extends FilterWriter {
 
         public JavaWriter(final Writer out) {
             super(out);
@@ -437,7 +437,9 @@ public static String codeToString(final ByteSequence bytes, final ConstantPool c
         case Const.NEW:
         case Const.CHECKCAST:
             buf.append("\t");
-            //$FALL-THROUGH$
+            index = bytes.readUnsignedShort();
+            buf.append("\t<").append(constantPool.constantToString(index, Const.CONSTANT_Class)).append(">").append(verbose ? " (" + index + ")" : "");
+            break;
         case Const.INSTANCEOF:
             index = bytes.readUnsignedShort();
             buf.append("\t<").append(constantPool.constantToString(index, Const.CONSTANT_Class)).append(">").append(verbose ? " (" + index + ")" : "");
@@ -864,7 +866,7 @@ public static String[] methodSignatureArgumentTypes(final String signature, fina
             // Skip any type arguments to read argument declarations between '(' and ')'
             index = signature.indexOf('(') + 1;
             if (index <= 0) {
-                throw new ClassFormatException("Invalid method signature: " + signature);
+                throw new InvalidMethodSignatureException(signature);
             }
             while (signature.charAt(index) != ')') {
                 vec.add(typeSignatureToString(signature.substring(index), chopit));
@@ -872,7 +874,7 @@ public static String[] methodSignatureArgumentTypes(final String signature, fina
                 index += unwrap(CONSUMER_CHARS); // update position
             }
         } catch (final StringIndexOutOfBoundsException e) { // Should never occur
-            throw new ClassFormatException("Invalid method signature: " + signature, e);
+            throw new InvalidMethodSignatureException(signature, e);
         }
         return vec.toArray(Const.EMPTY_STRING_ARRAY);
     }
@@ -903,11 +905,11 @@ public static String methodSignatureReturnType(final String signature, final boo
             // Read return type after ')'
             index = signature.lastIndexOf(')') + 1;
             if (index <= 0) {
-                throw new ClassFormatException("Invalid method signature: " + signature);
+                throw new InvalidMethodSignatureException(signature);
             }
             type = typeSignatureToString(signature.substring(index), chopit);
         } catch (final StringIndexOutOfBoundsException e) { // Should never occur
-            throw new ClassFormatException("Invalid method signature: " + signature, e);
+            throw new InvalidMethodSignatureException(signature, e);
         }
         return type;
     }
@@ -959,7 +961,7 @@ public static String methodSignatureToString(final String signature, final Strin
             // Skip any type arguments to read argument declarations between '(' and ')'
             index = signature.indexOf('(') + 1;
             if (index <= 0) {
-                throw new ClassFormatException("Invalid method signature: " + signature);
+                throw new InvalidMethodSignatureException(signature);
             }
             while (signature.charAt(index) != ')') {
                 final String paramType = typeSignatureToString(signature.substring(index), chopit);
@@ -985,7 +987,7 @@ public static String methodSignatureToString(final String signature, final Strin
             // Read return type after ')'
             type = typeSignatureToString(signature.substring(index), chopit);
         } catch (final StringIndexOutOfBoundsException e) { // Should never occur
-            throw new ClassFormatException("Invalid method signature: " + signature, e);
+            throw new InvalidMethodSignatureException(signature, e);
         }
         // ignore any throws information in the signature
         if (buf.length() > 1) {
@@ -1172,7 +1174,7 @@ public static String signatureToString(final String signature, final boolean cho
             type = typeParams + typeSignaturesToString(signature.substring(index), chopit, ')');
             index += unwrap(CONSUMER_CHARS); // update position
             // add return type
-            type = type + typeSignatureToString(signature.substring(index), chopit);
+            type += typeSignatureToString(signature.substring(index), chopit);
             index += unwrap(CONSUMER_CHARS); // update position
             // ignore any throws information in the signature
             return type;
@@ -1237,12 +1239,12 @@ public static byte typeOfMethodSignature(final String signature) throws ClassFor
         int index;
         try {
             if (signature.charAt(0) != '(') {
-                throw new ClassFormatException("Invalid method signature: " + signature);
+                throw new InvalidMethodSignatureException(signature);
             }
             index = signature.lastIndexOf(')') + 1;
             return typeOfSignature(signature.substring(index));
         } catch (final StringIndexOutOfBoundsException e) {
-            throw new ClassFormatException("Invalid method signature: " + signature, e);
+            throw new InvalidMethodSignatureException(signature, e);
         }
     }
 
@@ -1286,10 +1288,10 @@ public static byte typeOfSignature(final String signature) throws ClassFormatExc
             case '*':
                 return typeOfSignature(signature.substring(1));
             default:
-                throw new ClassFormatException("Invalid method signature: " + signature);
+                throw new InvalidMethodSignatureException(signature);
             }
         } catch (final StringIndexOutOfBoundsException e) {
-            throw new ClassFormatException("Invalid method signature: " + signature, e);
+            throw new InvalidMethodSignatureException(signature, e);
         }
     }
 
@@ -1469,8 +1471,8 @@ public static String typeSignatureToString(final String signature, final boolean
                 } else {
                     type.append(typeSignatureToString(signature.substring(consumedChars), chopit));
                     // update our consumed count by the number of characters the for type argument
-                    consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
-                    wrap(Utility.CONSUMER_CHARS, consumedChars);
+                    consumedChars = unwrap(CONSUMER_CHARS) + consumedChars;
+                    wrap(CONSUMER_CHARS, consumedChars);
                 }
 
                 // are there more TypeArguments?
@@ -1490,8 +1492,8 @@ public static String typeSignatureToString(final String signature, final boolean
                     } else {
                         type.append(typeSignatureToString(signature.substring(consumedChars), chopit));
                         // update our consumed count by the number of characters the for type argument
-                        consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
-                        wrap(Utility.CONSUMER_CHARS, consumedChars);
+                        consumedChars = unwrap(CONSUMER_CHARS) + consumedChars;
+                        wrap(CONSUMER_CHARS, consumedChars);
                     }
                 }
 
@@ -1508,14 +1510,14 @@ public static String typeSignatureToString(final String signature, final boolean
                     // update our consumed count by the number of characters the for type argument
                     // note that this count includes the "L" we added, but that is ok
                     // as it accounts for the "." we didn't consume
-                    consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
-                    wrap(Utility.CONSUMER_CHARS, consumedChars);
+                    consumedChars = unwrap(CONSUMER_CHARS) + consumedChars;
+                    wrap(CONSUMER_CHARS, consumedChars);
                     return type.toString();
                 }
                 if (signature.charAt(consumedChars) != ';') {
                     throw new ClassFormatException("Invalid signature: " + signature);
                 }
-                wrap(Utility.CONSUMER_CHARS, consumedChars + 1); // remove final ";"
+                wrap(CONSUMER_CHARS, consumedChars + 1); // remove final ";"
                 return type.toString();
             }
             case 'S':
@@ -1536,9 +1538,9 @@ public static String typeSignatureToString(final String signature, final boolean
                 // The rest of the string denotes a ''
                 type = typeSignatureToString(signature.substring(n), chopit);
                 // corrected concurrent private static field acess
-                // Utility.consumed_chars += consumed_chars; is replaced by:
-                final int temp = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
-                wrap(Utility.CONSUMER_CHARS, temp);
+                // consumed_chars += consumed_chars; is replaced by:
+                final int temp = unwrap(CONSUMER_CHARS) + consumedChars;
+                wrap(CONSUMER_CHARS, temp);
                 return type + brackets.toString();
             }
             case 'V':
@@ -1552,11 +1554,11 @@ public static String typeSignatureToString(final String signature, final boolean
     }
 
     private static int unwrap(final ThreadLocal tl) {
-        return tl.get();
+        return tl.get().intValue();
     }
 
     private static void wrap(final ThreadLocal tl, final int value) {
-        tl.set(value);
+        tl.set(Integer.valueOf(value));
     }
 
 }
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Visitor.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Visitor.java
index 74cb8400d3e..1f6fe9c96ee 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Visitor.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/Visitor.java
@@ -217,11 +217,32 @@ default void visitNestMembers(final NestMembers obj) {
      */
     void visitParameterAnnotation(ParameterAnnotations obj);
 
+
     /**
      * @since 6.0
      */
     void visitParameterAnnotationEntry(ParameterAnnotationEntry obj);
 
+    /**
+     * Visits a {@link Record} object.
+     *
+     * @param obj Record to visit
+     * @since 6.9.0
+     */
+    default void visitRecord(final Record obj) {
+        // empty
+    }
+
+    /**
+     * Visits a {@link RecordComponentInfo} object.
+     *
+     * @param record component to visit
+     * @since 6.9.0
+     */
+    default void visitRecordComponent(final RecordComponentInfo record) {
+     // noop
+    }
+
     void visitSignature(Signature obj);
 
     void visitSourceFile(SourceFile obj);
@@ -230,7 +251,18 @@ default void visitNestMembers(final NestMembers obj) {
 
     void visitStackMapEntry(StackMapEntry obj);
 
+    /**
+     * Visits a {@link StackMapType} object.
+     *
+     * @param obj object to visit
+     * @since 6.8.0
+     */
+    default void visitStackMapType(final StackMapType obj) {
+      // empty
+    }
+
     void visitSynthetic(Synthetic obj);
 
     void visitUnknown(Unknown obj);
+
 }
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/package-info.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/package-info.java
new file mode 100644
index 00000000000..4e8d383bcab
--- /dev/null
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * reserved comment block
+ * DO NOT REMOVE OR ALTER!
+ */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Classes that describe the structure of a Java class file and a class file parser.
+ */
+package com.sun.org.apache.bcel.internal.classfile;
diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ARRAYLENGTH.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ARRAYLENGTH.java
index 2d7188e9174..db756700085 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ARRAYLENGTH.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ARRAYLENGTH.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -28,12 +28,12 @@
  * 
  * Stack: ..., arrayref -> ..., length
  * 
- * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class ARRAYLENGTH extends Instruction implements ExceptionThrower, StackProducer, StackConsumer /* since 6.0 */ { /** - * Get length of array + * Gets length of array */ public ARRAYLENGTH() { super(com.sun.org.apache.bcel.internal.Const.ARRAYLENGTH, (short) 1); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ATHROW.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ATHROW.java index bb2e953f850..07171fefde1 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ATHROW.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ATHROW.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -28,8 +28,10 @@ *
  * Stack: ..., objectref -> objectref
  * 
+ * + * @LastModified: Sept 2025 */ -public class ATHROW extends Instruction implements UnconditionalBranch, ExceptionThrower { +public class ATHROW extends Instruction implements UnconditionalBranch, ExceptionThrower, StackConsumer { /** * Throw exception @@ -48,6 +50,7 @@ public ATHROW() { public void accept(final Visitor v) { v.visitUnconditionalBranch(this); v.visitExceptionThrower(this); + v.visitStackConsumer(this); v.visitATHROW(this); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/AnnotationEntryGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/AnnotationEntryGen.java index ea01a837175..0fad6ea7389 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/AnnotationEntryGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/AnnotationEntryGen.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -28,6 +28,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry; import com.sun.org.apache.bcel.internal.classfile.Attribute; @@ -37,10 +38,11 @@ import com.sun.org.apache.bcel.internal.classfile.RuntimeInvisibleParameterAnnotations; import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleAnnotations; import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleParameterAnnotations; +import jdk.xml.internal.Utils; /** * @since 6.0 - * @LastModified: Jan 2020 + * @LastModified: Sept 2025 */ public class AnnotationEntryGen { @@ -53,7 +55,7 @@ public class AnnotationEntryGen { * @param annotationEntryGens An array of AnnotationGen objects */ static Attribute[] getAnnotationAttributes(final ConstantPoolGen cp, final AnnotationEntryGen[] annotationEntryGens) { - if (annotationEntryGens.length == 0) { + if (annotationEntryGens == null && annotationEntryGens.length == 0) { return Attribute.EMPTY_ARRAY; } @@ -255,11 +257,7 @@ public void addElementNameValuePair(final ElementValuePairGen evp) { } private List copyValues(final ElementValuePair[] in, final ConstantPoolGen cpool, final boolean copyPoolEntries) { - final List out = new ArrayList<>(); - for (final ElementValuePair nvp : in) { - out.add(new ElementValuePairGen(nvp, cpool, copyPoolEntries)); - } - return out; + return Utils.streamOfIfNonNull(in).map(nvp -> new ElementValuePairGen(nvp, cpool, copyPoolEntries)).collect(Collectors.toList()); } public void dump(final DataOutputStream dos) throws IOException { @@ -286,18 +284,20 @@ public int getTypeIndex() { } public final String getTypeName() { - return getTypeSignature();// BCELBUG: Should I use this instead? + return getTypeSignature(); // BCELBUG: Should I use this instead? // Utility.signatureToString(getTypeSignature()); } public final String getTypeSignature() { - // ConstantClass c = (ConstantClass)cpool.getConstant(typeIndex); + // ConstantClass c = (ConstantClass) cpool.getConstant(typeIndex); final ConstantUtf8 utf8 = (ConstantUtf8) cpool.getConstant(typeIndex/* c.getNameIndex() */); return utf8.getBytes(); } /** - * Returns list of ElementNameValuePair objects + * Returns list of ElementNameValuePair objects. + * + * @return list of ElementNameValuePair objects. */ public List getValues() { return evs; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayElementValueGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayElementValueGen.java index 71374877efe..59b774a9afc 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayElementValueGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayElementValueGen.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -25,12 +24,15 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import com.sun.org.apache.bcel.internal.classfile.ArrayElementValue; import com.sun.org.apache.bcel.internal.classfile.ElementValue; +import jdk.xml.internal.Utils; /** * @since 6.0 + * @LastModified: Sept 2025 */ public class ArrayElementValueGen extends ElementValueGen { // J5TODO: Should we make this an array or a list? A list would be easier to @@ -46,7 +48,7 @@ public ArrayElementValueGen(final ArrayElementValue value, final ConstantPoolGen evalues = new ArrayList<>(); final ElementValue[] in = value.getElementValuesArray(); for (final ElementValue element : in) { - evalues.add(ElementValueGen.copy(element, cpool, copyPoolEntries)); + evalues.add(copy(element, cpool, copyPoolEntries)); } } @@ -55,15 +57,12 @@ public ArrayElementValueGen(final ConstantPoolGen cp) { evalues = new ArrayList<>(); } - public ArrayElementValueGen(final int type, final ElementValue[] datums, final ConstantPoolGen cpool) { + public ArrayElementValueGen(final int type, final ElementValue[] elementValues, final ConstantPoolGen cpool) { super(type, cpool); if (type != ARRAY) { throw new IllegalArgumentException("Only element values of type array can be built with this ctor - type specified: " + type); } - this.evalues = new ArrayList<>(); - for (final ElementValue datum : datums) { - evalues.add(ElementValueGen.copy(datum, cpool, true)); - } + this.evalues = Utils.streamOfIfNonNull(elementValues).map(e -> copy(e, cpool, true)).collect(Collectors.toList()); } public void addElement(final ElementValueGen gen) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayType.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayType.java index 138999ebe90..78a676e875e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayType.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ArrayType.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -24,6 +23,8 @@ /** * Denotes array type, such as int[][] + * + * @LastModified: Sept 2025 */ public final class ArrayType extends ReferenceType { @@ -43,7 +44,7 @@ public ArrayType(final byte type, final int dimensions) { /** * Convenience constructor for reference array type, e.g. Object[] * - * @param className complete name of class (java.lang.String, e.g.) + * @param className complete name of class ({@link String}, for example) * @param dimensions array dimensions */ public ArrayType(final String className, final int dimensions) { @@ -56,6 +57,7 @@ public ArrayType(final String className, final int dimensions) { * @param type type of array (may be an array itself) * @param dimensions array dimensions */ + @SuppressWarnings("deprecation") //signature public ArrayType(final Type type, final int dimensions) { super(Const.T_ARRAY, ""); if (dimensions < 1 || dimensions > Const.MAX_BYTE) { @@ -79,7 +81,7 @@ public ArrayType(final Type type, final int dimensions) { buf.append('['); } buf.append(basicType.getSignature()); - super.setSignature(buf.toString()); + this.signature = buf.toString(); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/BranchHandle.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/BranchHandle.java index 91ab9ac5463..f489f9a7658 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/BranchHandle.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/BranchHandle.java @@ -63,7 +63,7 @@ public InstructionHandle getTarget() { } /** - * Set new contents. Old instruction is disposed and may not be used anymore. + * Sets new contents. Old instruction is disposed and may not be used anymore. */ @Override // This is only done in order to apply the additional type check; could be merged with super impl. public void setInstruction(final Instruction i) { // TODO could be package-protected? diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CPInstruction.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CPInstruction.java index 1dfd244141a..ff45e5cde93 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CPInstruction.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CPInstruction.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. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -35,7 +35,7 @@ * @see LDC * @see INVOKEVIRTUAL * - * @LastModified: Jan 2020 + * @LastModified: Sept 2025 */ public abstract class CPInstruction extends Instruction implements TypedInstruction, IndexedInstruction { @@ -104,7 +104,7 @@ protected void initFromFile(final ByteSequence bytes, final boolean wide) throws } /** - * Set the index to constant pool. + * Sets the index to constant pool. * * @param index in constant pool. */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassElementValueGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassElementValueGen.java index 1c1c032dbd5..8e024eebaa4 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassElementValueGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassElementValueGen.java @@ -48,12 +48,12 @@ public ClassElementValueGen(final ClassElementValue value, final ConstantPoolGen } protected ClassElementValueGen(final int typeIdx, final ConstantPoolGen cpool) { - super(ElementValueGen.CLASS, cpool); + super(CLASS, cpool); this.idx = typeIdx; } public ClassElementValueGen(final ObjectType t, final ConstantPoolGen cpool) { - super(ElementValueGen.CLASS, cpool); + super(CLASS, cpool); // this.idx = cpool.addClass(t); idx = cpool.addUtf8(t.getSignature()); } @@ -67,9 +67,9 @@ public void dump(final DataOutputStream dos) throws IOException { public String getClassString() { final ConstantUtf8 cu8 = (ConstantUtf8) getConstantPool().getConstant(idx); return cu8.getBytes(); - // ConstantClass c = (ConstantClass)getConstantPool().getConstant(idx); + // ConstantClass c = (ConstantClass) getConstantPool().getConstant(idx); // ConstantUtf8 utf8 = - // (ConstantUtf8)getConstantPool().getConstant(c.getNameIndex()); + // (ConstantUtf8) getConstantPool().getConstant(c.getNameIndex()); // return utf8.getBytes(); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassGen.java index acaf4519567..debf930fe90 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -40,40 +40,37 @@ import com.sun.org.apache.bcel.internal.util.BCELComparator; /** - * Template class for building up a java class. May be initialized with an existing java class (file). + * Template class for building up a java class. May be initialized with an existing Java class (file). * * @see JavaClass - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class ClassGen extends AccessFlags implements Cloneable { - private static BCELComparator bcelComparator = new BCELComparator() { + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final ClassGen THIS = (ClassGen) o1; - final ClassGen THAT = (ClassGen) o2; - return Objects.equals(THIS.getClassName(), THAT.getClassName()); + public boolean equals(final ClassGen a, final ClassGen b) { + return a == b || a != null && b != null && Objects.equals(a.getClassName(), b.getClassName()); } @Override - public int hashCode(final Object o) { - final ClassGen THIS = (ClassGen) o; - return THIS.getClassName().hashCode(); + public int hashCode(final ClassGen o) { + return o != null ? Objects.hashCode(o.getClassName()) : 0; } }; /** * @return Comparison strategy object */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } /** * @param comparator Comparison strategy object */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } @@ -101,7 +98,7 @@ public static void setComparator(final BCELComparator comparator) { private List observers; /** - * Initialize with existing class. + * Constructs a new instance from an existing class. * * @param clazz JavaClass object (e.g. read from file) */ @@ -118,15 +115,26 @@ public ClassGen(final JavaClass clazz) { final Attribute[] attributes = clazz.getAttributes(); // J5TODO: Could make unpacking lazy, done on first reference final AnnotationEntryGen[] annotations = unpackAnnotations(attributes); - Collections.addAll(interfaceList, clazz.getInterfaceNames()); - for (final Attribute attribute : attributes) { - if (!(attribute instanceof Annotations)) { - addAttribute(attribute); + final String[] interfaceNames = clazz.getInterfaceNames(); + if (interfaceNames != null) { + Collections.addAll(interfaceList, interfaceNames); + } + if (attributes != null) { + for (final Attribute attribute : attributes) { + if (!(attribute instanceof Annotations)) { + addAttribute(attribute); + } } } Collections.addAll(annotationList, annotations); - Collections.addAll(methodList, clazz.getMethods()); - Collections.addAll(fieldList, clazz.getFields()); + final Method[] methods = clazz.getMethods(); + if (methods != null) { + Collections.addAll(methodList, methods); + } + final Field[] fields = clazz.getFields(); + if (fields != null) { + Collections.addAll(fieldList, fields); + } } /** @@ -242,7 +250,7 @@ public Object clone() { try { return super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } } @@ -282,7 +290,7 @@ public Method containsMethod(final String name, final String signature) { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof ClassGen && bcelComparator.equals(this, (ClassGen) obj); } // J5TODO: Should we make calling unpackAnnotations() lazy and put it in here? @@ -379,7 +387,7 @@ public int getSuperclassNameIndex() { } /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name. + * Return value as defined by given BCELComparator strategy. By default return the hash code of the class name. * * @see Object#hashCode() */ @@ -478,7 +486,7 @@ public void setConstantPool(final ConstantPoolGen constantPool) { } /** - * Set major version number of class file, default value is 45 (JDK 1.1) + * Sets major version number of class file, default value is 45 (JDK 1.1) * * @param major major version number */ @@ -492,11 +500,13 @@ public void setMethodAt(final Method method, final int pos) { public void setMethods(final Method[] methods) { methodList.clear(); - Collections.addAll(methodList, methods); + if (methods != null) { + Collections.addAll(methodList, methods); + } } /** - * Set minor version number of class file, default value is 3 (JDK 1.1) + * Sets minor version number of class file, default value is 3 (JDK 1.1) * * @param minor minor version number */ @@ -515,17 +525,19 @@ public void setSuperclassNameIndex(final int superclassNameIndex) { } /** - * Look for attributes representing annotations and unpack them. + * Unpacks attributes representing annotations. */ - private AnnotationEntryGen[] unpackAnnotations(final Attribute[] attrs) { + private AnnotationEntryGen[] unpackAnnotations(final Attribute[] attributes) { final List annotationGenObjs = new ArrayList<>(); - for (final Attribute attr : attrs) { - if (attr instanceof RuntimeVisibleAnnotations) { - final RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) attr; - rva.forEach(a -> annotationGenObjs.add(new AnnotationEntryGen(a, getConstantPool(), false))); - } else if (attr instanceof RuntimeInvisibleAnnotations) { - final RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations) attr; - ria.forEach(a -> annotationGenObjs.add(new AnnotationEntryGen(a, getConstantPool(), false))); + if (attributes != null) { + for (final Attribute attr : attributes) { + if (attr instanceof RuntimeVisibleAnnotations) { + final RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) attr; + rva.forEach(a -> annotationGenObjs.add(new AnnotationEntryGen(a, getConstantPool(), false))); + } else if (attr instanceof RuntimeInvisibleAnnotations) { + final RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations) attr; + ria.forEach(a -> annotationGenObjs.add(new AnnotationEntryGen(a, getConstantPool(), false))); + } } } return annotationGenObjs.toArray(AnnotationEntryGen.EMPTY_ARRAY); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CodeExceptionGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CodeExceptionGen.java index fa660954d15..2518131ccee 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CodeExceptionGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/CodeExceptionGen.java @@ -63,7 +63,7 @@ public Object clone() { try { return super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } } @@ -81,7 +81,7 @@ public ObjectType getCatchType() { } /** - * Get CodeException object.
+ * Gets CodeException object.
* * This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods * has been called for the instruction list. @@ -120,7 +120,7 @@ public void setCatchType(final ObjectType catchType) { } /* - * Set end of handler + * Sets end of handler * * @param endPc End of handled region (inclusive) */ @@ -130,7 +130,7 @@ public void setEndPC(final InstructionHandle endPc) { // TODO could be package-p } /* - * Set handler code + * Sets handler code * * @param handlerPc Start of handler */ @@ -140,7 +140,7 @@ public void setHandlerPC(final InstructionHandle handlerPc) { // TODO could be p } /* - * Set start of handler + * Sets start of handler * * @param startPc Start of handled region (inclusive) */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ElementValuePairGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ElementValuePairGen.java index bdc9c517a86..878f392b6b7 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ElementValuePairGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ElementValuePairGen.java @@ -44,7 +44,7 @@ public ElementValuePairGen(final ElementValuePair nvp, final ConstantPoolGen cpo // Could assert nvp.getNameString() points to the same thing as // constantPoolGen.getConstant(nvp.getNameIndex()) // if - // (!nvp.getNameString().equals(((ConstantUtf8)constantPoolGen.getConstant(nvp.getNameIndex())).getBytes())) + // (!nvp.getNameString().equals(((ConstantUtf8) constantPoolGen.getConstant(nvp.getNameIndex())).getBytes())) // { // throw new IllegalArgumentException("envp buggered"); // } @@ -86,7 +86,7 @@ public int getNameIndex() { } public final String getNameString() { - // ConstantString cu8 = (ConstantString)constantPoolGen.getConstant(nameIdx); + // ConstantString cu8 = (ConstantString) constantPoolGen.getConstant(nameIdx); return ((ConstantUtf8) constantPoolGen.getConstant(nameIdx)).getBytes(); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/EnumElementValueGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/EnumElementValueGen.java index 95ac794f2d7..95c00ed3813 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/EnumElementValueGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/EnumElementValueGen.java @@ -40,10 +40,8 @@ public class EnumElementValueGen extends ElementValueGen { public EnumElementValueGen(final EnumElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) { super(ENUM_CONSTANT, cpool); if (copyPoolEntries) { - typeIdx = cpool.addUtf8(value.getEnumTypeString());// was - // addClass(value.getEnumTypeString()); - valueIdx = cpool.addUtf8(value.getEnumValueString()); // was - // addString(value.getEnumValueString()); + typeIdx = cpool.addUtf8(value.getEnumTypeString()); // was addClass(value.getEnumTypeString()); + valueIdx = cpool.addUtf8(value.getEnumValueString()); // was addString(value.getEnumValueString()); } else { typeIdx = value.getTypeIndex(); valueIdx = value.getValueIndex(); @@ -55,7 +53,7 @@ public EnumElementValueGen(final EnumElementValue value, final ConstantPoolGen c * This ctor is used for deserialization */ protected EnumElementValueGen(final int typeIdx, final int valueIdx, final ConstantPoolGen cpool) { - super(ElementValueGen.ENUM_CONSTANT, cpool); + super(ENUM_CONSTANT, cpool); if (super.getElementValueType() != ENUM_CONSTANT) { throw new IllegalArgumentException("Only element values of type enum can be built with this ctor - type specified: " + super.getElementValueType()); } @@ -64,9 +62,9 @@ protected EnumElementValueGen(final int typeIdx, final int valueIdx, final Const } public EnumElementValueGen(final ObjectType t, final String value, final ConstantPoolGen cpool) { - super(ElementValueGen.ENUM_CONSTANT, cpool); - typeIdx = cpool.addUtf8(t.getSignature());// was addClass(t); - valueIdx = cpool.addUtf8(value);// was addString(value); + super(ENUM_CONSTANT, cpool); + typeIdx = cpool.addUtf8(t.getSignature()); // was addClass(t); + valueIdx = cpool.addUtf8(value); // was addString(value); } @Override @@ -90,9 +88,9 @@ public ElementValue getElementValue() { public String getEnumTypeString() { // Constant cc = getConstantPool().getConstant(typeIdx); // ConstantClass cu8 = - // (ConstantClass)getConstantPool().getConstant(typeIdx); + // (ConstantClass) getConstantPool().getConstant(typeIdx); // return - // ((ConstantUtf8)getConstantPool().getConstant(cu8.getNameIndex())).getBytes(); + // ((ConstantUtf8) getConstantPool().getConstant(cu8.getNameIndex())).getBytes(); return ((ConstantUtf8) getConstantPool().getConstant(typeIdx)).getBytes(); // return Utility.signatureToString(cu8.getBytes()); } @@ -100,9 +98,9 @@ public String getEnumTypeString() { public String getEnumValueString() { return ((ConstantUtf8) getConstantPool().getConstant(valueIdx)).getBytes(); // ConstantString cu8 = - // (ConstantString)getConstantPool().getConstant(valueIdx); + // (ConstantString) getConstantPool().getConstant(valueIdx); // return - // ((ConstantUtf8)getConstantPool().getConstant(cu8.getStringIndex())).getBytes(); + // ((ConstantUtf8) getConstantPool().getConstant(cu8.getStringIndex())).getBytes(); } public int getTypeIndex() { @@ -118,8 +116,8 @@ public String stringifyValue() { final ConstantUtf8 cu8 = (ConstantUtf8) getConstantPool().getConstant(valueIdx); return cu8.getBytes(); // ConstantString cu8 = - // (ConstantString)getConstantPool().getConstant(valueIdx); + // (ConstantString) getConstantPool().getConstant(valueIdx); // return - // ((ConstantUtf8)getConstantPool().getConstant(cu8.getStringIndex())).getBytes(); + // ((ConstantUtf8) getConstantPool().getConstant(cu8.getStringIndex())).getBytes(); } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ExceptionThrower.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ExceptionThrower.java index 86a0cad256c..2a488c85ede 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ExceptionThrower.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ExceptionThrower.java @@ -23,7 +23,7 @@ /** * Denote an instruction that may throw a run-time or a linking exception (or both) during execution. This is not quite - * the truth as such; because all instructions may throw an java.lang.VirtualMachineError. These exceptions are omitted. + * the truth as such; because all instructions may throw a {@link VirtualMachineError}. These exceptions are omitted. * * The Lava Language Specification specifies exactly which RUN-TIME and which LINKING exceptions each * instruction may throw which is reflected by the implementers. Due to the structure of the JVM specification, it may diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGen.java index 9d1f4d41d93..30786370d29 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -40,37 +40,34 @@ * to a field (which must of course be compatible with to the declared type). * * @see Field - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public class FieldGen extends FieldGenOrMethodGen { - private static BCELComparator bcelComparator = new BCELComparator() { + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final FieldGen THIS = (FieldGen) o1; - final FieldGen THAT = (FieldGen) o2; - return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature()); + public boolean equals(final FieldGen a, final FieldGen b) { + return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature()); } @Override - public int hashCode(final Object o) { - final FieldGen THIS = (FieldGen) o; - return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + public int hashCode(final FieldGen o) { + return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0; } }; /** - * @return Comparison strategy object + * @return Comparison strategy object. */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } /** - * @param comparator Comparison strategy object + * @param comparator Comparison strategy object. */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } @@ -81,8 +78,8 @@ public static void setComparator(final BCELComparator comparator) { /** * Instantiate from existing field. * - * @param field Field object - * @param cp constant pool (must contain the same entries as the field's constant pool) + * @param field Field object. + * @param cp constant pool (must contain the same entries as the field's constant pool). */ public FieldGen(final Field field, final ConstantPoolGen cp) { this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp); @@ -187,11 +184,11 @@ public FieldGen copy(final ConstantPoolGen cp) { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof FieldGen && bcelComparator.equals(this, (FieldGen) obj); } /** - * Get field object after having set up all necessary values. + * Gets field object after having set up all necessary values. */ public Field getField() { final String signature = getSignature(); @@ -207,10 +204,7 @@ public Field getField() { } public String getInitValue() { - if (value != null) { - return value.toString(); - } - return null; + return Objects.toString(value, null); } @Override @@ -219,7 +213,7 @@ public String getSignature() { } /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR + * Return value as defined by given BCELComparator strategy. By default return the hash code of the field's name XOR * signature. * * @see Object#hashCode() @@ -295,7 +289,7 @@ public void setInitValue(final short s) { } /** - * Set (optional) initial value of field, otherwise it will be set to null/0/false by the JVM automatically. + * Sets (optional) initial value of field, otherwise it will be set to null/0/false by the JVM automatically. */ public void setInitValue(final String str) { checkType(ObjectType.getInstance("java.lang.String")); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGenOrMethodGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGenOrMethodGen.java index 6555392e9d4..bc1fbc8627e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGenOrMethodGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldGenOrMethodGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,7 +30,7 @@ /** * Super class for FieldGen and MethodGen objects, since they have some methods in common! * - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAndTyped, Cloneable { @@ -67,8 +67,10 @@ protected FieldGenOrMethodGen(final int accessFlags) { // TODO could this be pac super(accessFlags); } - protected void addAll(final Attribute[] attrs) { - Collections.addAll(attributeList, attrs); + protected void addAll(final Attribute[] attributes) { + if (attributes != null) { + Collections.addAll(attributeList, attributes); + } } /** @@ -93,7 +95,7 @@ public Object clone() { try { return super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldOrMethod.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldOrMethod.java index 1c646f48292..87ba4cb913e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldOrMethod.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FieldOrMethod.java @@ -53,7 +53,6 @@ protected FieldOrMethod(final short opcode, final int index) { * generated by Java 1.5, this answer is sometimes wrong (e.g., if the "clone()" method is called on an * array). A better idea is to use the {@link #getReferenceType(ConstantPoolGen)} method, which correctly * distinguishes between class types and array types. - * */ @Deprecated public String getClassName(final ConstantPoolGen cpg) { @@ -89,6 +88,9 @@ public ObjectType getLoadClassType(final ConstantPoolGen cpg) { if (rt instanceof ObjectType) { return (ObjectType) rt; } + if (rt instanceof ArrayType) { + return Type.OBJECT; + } throw new ClassGenException(rt.getClass().getCanonicalName() + " " + rt.getSignature() + " does not represent an ObjectType"); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ICONST.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ICONST.java index 5effd7edcd9..b3eb14a9ddf 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ICONST.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ICONST.java @@ -25,7 +25,6 @@ *
  * Stack: ... -> ...,
  * 
- * */ public class ICONST extends Instruction implements ConstantPushInstruction { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/INVOKEDYNAMIC.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/INVOKEDYNAMIC.java index 2865a158de2..998d072e067 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/INVOKEDYNAMIC.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/INVOKEDYNAMIC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -37,7 +37,7 @@ * @see The * invokedynamic instruction in The Java Virtual Machine Specification * @since 6.0 - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class INVOKEDYNAMIC extends InvokeInstruction { @@ -104,11 +104,11 @@ public Class[] getExceptions() { } /** - * Since InvokeDynamic doesn't refer to a reference type, just return java.lang.Object, as that is the only type we can + * Since InvokeDynamic doesn't refer to a reference type, just return {@link Object}, as that is the only type we can * say for sure the reference will be. * * @param cpg the ConstantPoolGen used to create the instruction - * @return an ObjectType for java.lang.Object + * @return an ObjectType for {@link Object} * @since 6.1 */ @Override diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Instruction.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Instruction.java index 16c8e2444b4..a7124409f12 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Instruction.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Instruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -29,7 +29,7 @@ /** * Abstract super class for all Java byte codes. * - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public abstract class Instruction implements Cloneable { @@ -461,7 +461,7 @@ public int consumeStack(final ConstantPoolGen cpg) { public Instruction copy() { Instruction i = null; // "Constant" instruction, no need to duplicate - if (InstructionConst.getInstruction(this.getOpcode()) != null) { + if (InstructionConst.getInstruction(getOpcode()) != null) { i = this; } else { try { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionConst.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionConst.java index 439268e35eb..7b95bfc99b1 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionConst.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionConst.java @@ -170,7 +170,7 @@ public final class InstructionConst { public static final LocalVariableInstruction ISTORE_2 = new ISTORE(2); /** - * Get object via its opcode, for immutable instructions like branch instructions entries are set to null. + * Gets object via its opcode, for immutable instructions like branch instructions entries are set to null. */ static final Instruction[] INSTRUCTIONS = new Instruction[256]; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionFactory.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionFactory.java index 5e9220354c3..3c4b3e9f9da 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionFactory.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,11 +30,11 @@ * * @see Const * @see InstructionConst - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class InstructionFactory { - private static class MethodObject { + private static final class MethodObject { final Type[] argTypes; final Type resultType; @@ -53,10 +53,12 @@ private static class MethodObject { private static final String FQCN_STRING_BUFFER = "java.lang.StringBuffer"; - // N.N. These must agree with the order of Constants.T_CHAR through T_LONG - private static final String[] shortNames = {"C", "F", "D", "B", "S", "I", "L"}; + /** + * These must agree with the order of Constants.T_CHAR through T_LONG. + */ + private static final String[] SHORT_NAMES = {"C", "F", "D", "B", "S", "I", "L"}; - private static final MethodObject[] appendMethodObjects = { + private static final MethodObject[] APPEND_METHOD_OBJECTS = { new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.STRING }), new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.OBJECT }), null, null, // indices 2, 3 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.BOOLEAN }), @@ -484,7 +486,7 @@ public InstructionFactory(final ConstantPoolGen cp) { public Instruction createAppend(final Type type) { final byte t = type.getType(); if (isString(type)) { - return createInvoke(appendMethodObjects[0], Const.INVOKEVIRTUAL); + return createInvoke(APPEND_METHOD_OBJECTS[0], Const.INVOKEVIRTUAL); } switch (t) { case Const.T_BOOLEAN: @@ -495,10 +497,10 @@ public Instruction createAppend(final Type type) { case Const.T_SHORT: case Const.T_INT: case Const.T_LONG: - return createInvoke(appendMethodObjects[t], Const.INVOKEVIRTUAL); + return createInvoke(APPEND_METHOD_OBJECTS[t], Const.INVOKEVIRTUAL); case Const.T_ARRAY: case Const.T_OBJECT: - return createInvoke(appendMethodObjects[1], Const.INVOKEVIRTUAL); + return createInvoke(APPEND_METHOD_OBJECTS[1], Const.INVOKEVIRTUAL); default: throw new IllegalArgumentException("No append for this type? " + type); } @@ -515,7 +517,7 @@ public Instruction createCast(final Type srcType, final Type destType) { if (dest == Const.T_LONG && (src == Const.T_CHAR || src == Const.T_BYTE || src == Const.T_SHORT)) { src = Const.T_INT; } - final String name = "com.sun.org.apache.bcel.internal.generic." + shortNames[src - Const.T_CHAR] + "2" + shortNames[dest - Const.T_CHAR]; + final String name = "com.sun.org.apache.bcel.internal.generic." + SHORT_NAMES[src - Const.T_CHAR] + "2" + SHORT_NAMES[dest - Const.T_CHAR]; Instruction i = null; try { i = (Instruction) Class.forName(name).getDeclaredConstructor().newInstance();; @@ -642,8 +644,10 @@ public InvokeInstruction createInvoke(final String className, final String name, int index; int nargs = 0; final String signature = Type.getMethodSignature(retType, argTypes); - for (final Type argType : argTypes) { - nargs += argType.getSize(); + if (argTypes != null) { + for (final Type argType : argTypes) { + nargs += argType.getSize(); + } } if (useInterface) { index = cp.addInterfaceMethodref(className, name, signature); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionHandle.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionHandle.java index 5e962354d16..2c94b770265 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionHandle.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -38,7 +38,7 @@ * @see Instruction * @see BranchHandle * @see InstructionList - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public class InstructionHandle { @@ -118,7 +118,7 @@ public void addTargeter(final InstructionTargeter t) { if (targeters == null) { targeters = new HashSet<>(); } - // if(!targeters.contains(t)) + // if (!targeters.contains(t)) targeters.add(t); } @@ -135,15 +135,12 @@ void dispose() { } /** - * Get attribute of an instruction handle. + * Gets attribute of an instruction handle. * * @param key the key object to store/retrieve the attribute */ public Object getAttribute(final Object key) { - if (attributes != null) { - return attributes.get(key); - } - return null; + return attributes != null ? attributes.get(key) : null; } /** @@ -247,7 +244,7 @@ final InstructionHandle setNext(final InstructionHandle next) { } /** - * Set the position, i.e., the byte code offset of the contained instruction. + * Sets the position, i.e., the byte code offset of the contained instruction. */ void setPosition(final int pos) { i_position = pos; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionList.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionList.java index 7ffc3a8228e..579efc9fe3b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionList.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -33,6 +33,7 @@ import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.classfile.Constant; import com.sun.org.apache.bcel.internal.util.ByteSequence; +import jdk.xml.internal.Utils; /** * This class is a container for a list of Instruction objects. Instructions can be @@ -46,7 +47,7 @@ * @see Instruction * @see InstructionHandle * @see BranchHandle - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class InstructionList implements Iterable { @@ -60,23 +61,25 @@ public class InstructionList implements Iterable { * @return target position's instruction handle if available */ public static InstructionHandle findHandle(final InstructionHandle[] ihs, final int[] pos, final int count, final int target) { - int l = 0; - int r = count - 1; - /* - * Do a binary search since the pos array is orderd. - */ - do { - final int i = l + r >>> 1; - final int j = pos[i]; - if (j == target) { - return ihs[i]; - } - if (target < j) { - r = i - 1; - } else { - l = i + 1; - } - } while (l <= r); + if (ihs != null && pos != null) { + int l = 0; + int r = count - 1; + /* + * Do a binary search since the pos array is orderd. + */ + do { + final int i = l + r >>> 1; + final int j = pos[i]; + if (j == target) { + return ihs[i]; + } + if (target < j) { + r = i - 1; + } else { + l = i + 1; + } + } while (l <= r); + } return null; } @@ -513,7 +516,7 @@ public void dispose() { } /** - * Get instruction handle for instruction at byte code position pos. This only works properly, if the list is freshly + * Gets instruction handle for instruction at byte code position pos. This only works properly, if the list is freshly * initialized from a byte array or setPositions() has been called before this method. * * @param pos byte code position to search for @@ -605,7 +608,7 @@ public InstructionHandle[] getInstructionHandles() { } /** - * Get positions (offsets) of all instructions in the list. This relies on that the list has been freshly created from + * Gets positions (offsets) of all instructions in the list. This relies on that the list has been freshly created from * an byte code array, or that setPositions() has been called. Otherwise this may be inaccurate. * * @return array containing all instruction's offset in byte code @@ -959,7 +962,7 @@ public void redirectBranches(final InstructionHandle oldTarget, final Instructio * @see MethodGen */ public void redirectExceptionHandlers(final CodeExceptionGen[] exceptions, final InstructionHandle oldTarget, final InstructionHandle newTarget) { - for (final CodeExceptionGen exception : exceptions) { + Utils.streamOfIfNonNull(exceptions).forEach(exception -> { if (exception.getStartPC() == oldTarget) { exception.setStartPC(newTarget); } @@ -969,7 +972,7 @@ public void redirectExceptionHandlers(final CodeExceptionGen[] exceptions, final if (exception.getHandlerPC() == oldTarget) { exception.setHandlerPC(newTarget); } - } + }); } /** @@ -981,16 +984,14 @@ public void redirectExceptionHandlers(final CodeExceptionGen[] exceptions, final * @see MethodGen */ public void redirectLocalVariables(final LocalVariableGen[] lg, final InstructionHandle oldTarget, final InstructionHandle newTarget) { - for (final LocalVariableGen element : lg) { - final InstructionHandle start = element.getStart(); - final InstructionHandle end = element.getEnd(); - if (start == oldTarget) { + Utils.streamOfIfNonNull(lg).forEach(element -> { + if (element.getStart() == oldTarget) { element.setStart(newTarget); } - if (end == oldTarget) { + if (element.getEnd() == oldTarget) { element.setEnd(newTarget); } - } + }); } /** @@ -1120,7 +1121,7 @@ public void setPositions(final boolean check) { // called by code in other packa ih.setPosition(index); pos[count++] = index; /* - * Get an estimate about how many additional bytes may be added, because BranchInstructions may have variable length + * Gets an estimate about how many additional bytes may be added, because BranchInstructions may have variable length * depending on the target offset (short vs. int) or alignment issues (TABLESWITCH and LOOKUPSWITCH). */ switch (i.getOpcode()) { @@ -1132,11 +1133,14 @@ public void setPositions(final boolean check) { // called by code in other packa case Const.LOOKUPSWITCH: maxAdditionalBytes += 3; break; + default: + // TODO should this be an error? + break; } index += i.getLength(); } /* - * Pass 2: Expand the variable-length (Branch)Instructions depending on the target offset (short or int) and ensure that + * Pass 2: Expand the variable-length (Branch) Instructions depending on the target offset (short or int) and ensure that * branch targets are within this list. */ for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) { @@ -1152,8 +1156,7 @@ public void setPositions(final boolean check) { // called by code in other packa pos[count++] = index; index += i.getLength(); } - bytePositions = new int[count]; // Trim to proper size - System.arraycopy(pos, 0, bytePositions, 0, count); + bytePositions = Arrays.copyOfRange(pos, 0, count); // Trim to proper size } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionTargeter.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionTargeter.java index 5146408ef49..0681476b5ee 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionTargeter.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionTargeter.java @@ -22,7 +22,7 @@ package com.sun.org.apache.bcel.internal.generic; /** - * Denote that a class targets InstructionHandles within an InstructionList. Namely the following implementers: + * Denotes that a class targets InstructionHandles within an InstructionList. * * @see BranchHandle * @see LocalVariableGen @@ -33,9 +33,12 @@ public interface InstructionTargeter { // static final InstructionTargeter[] EMPTY_ARRAY = new InstructionTargeter[0]; /** - * Checks whether this targeter targets the specified instruction handle. + * Tests whether this targeter targets the specified instruction handle. + * + * @param instructionHandle the instruction handle to test. + * @return whether this targeter targets the specified instruction handle. */ - boolean containsTarget(InstructionHandle ih); + boolean containsTarget(InstructionHandle instructionHandle); /** * Replaces the target of this targeter from this old handle to the new handle. diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LCMP.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LCMP.java index c517b492f0a..188ac95f6ef 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LCMP.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LCMP.java @@ -27,7 +27,6 @@ *
  * Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -> ..., result <= -1, 0, 1>
  * 
- * */ public class LCMP extends Instruction implements TypedInstruction, StackProducer, StackConsumer { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LDC.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LDC.java index d95bade23bd..13ca0a84cfa 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LDC.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LDC.java @@ -94,6 +94,8 @@ public Type getType(final ConstantPoolGen cpg) { return Type.INT; case com.sun.org.apache.bcel.internal.Const.CONSTANT_Class: return Type.CLASS; + case com.sun.org.apache.bcel.internal.Const.CONSTANT_Dynamic: + return Type.OBJECT; default: // Never reached throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex()); } @@ -113,7 +115,10 @@ public Object getValue(final ConstantPoolGen cpg) { case com.sun.org.apache.bcel.internal.Const.CONSTANT_Class: final int nameIndex = ((com.sun.org.apache.bcel.internal.classfile.ConstantClass) c).getNameIndex(); c = cpg.getConstantPool().getConstant(nameIndex); - return Type.getType(((com.sun.org.apache.bcel.internal.classfile.ConstantUtf8) c).getBytes()); + return Type.getType(Type.internalTypeNameToSignature(((com.sun.org.apache.bcel.internal.classfile.ConstantUtf8) c).getBytes())); + case com.sun.org.apache.bcel.internal.Const.CONSTANT_Dynamic: + // Really not sure what to return here, maybe a BootstrapMethod instance but how do we get it? + return c; default: // Never reached throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex()); } @@ -129,7 +134,7 @@ protected void initFromFile(final ByteSequence bytes, final boolean wide) throws } /** - * Set the index to constant pool and adjust size. + * Sets the index to constant pool and adjust size. */ @Override public final void setIndex(final int index) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LineNumberGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LineNumberGen.java index 3773c21e7b3..68bb2abf513 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LineNumberGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LineNumberGen.java @@ -54,7 +54,7 @@ public Object clone() { try { return super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } } @@ -71,7 +71,7 @@ public InstructionHandle getInstruction() { } /** - * Get LineNumber attribute. + * Gets LineNumber attribute. * * This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods * has been called for the instruction list. diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableGen.java index 830564d42c9..71cfa0cf1c2 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableGen.java @@ -85,7 +85,7 @@ public Object clone() { try { return super.clone(); } catch (final CloneNotSupportedException e) { - throw new Error("Clone Not Supported"); // never happens + throw new UnsupportedOperationException("Clone Not Supported", e); // never happens } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableInstruction.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableInstruction.java index 67184c0b9f1..f952a65880b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableInstruction.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -28,7 +28,7 @@ /** * Abstract super class for instructions dealing with local variables. * - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public abstract class LocalVariableInstruction extends Instruction implements TypedInstruction, IndexedInstruction { @@ -162,7 +162,7 @@ protected void initFromFile(final ByteSequence bytes, final boolean wide) throws } /** - * Set the local variable index. also updates opcode and length TODO Why? + * Sets the local variable index. also updates opcode and length TODO Why? * * @see #setIndexOnly(int) */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java index f6e8333be79..be09b0a5159 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,6 +27,7 @@ import java.util.List; import java.util.Objects; import java.util.Stack; +import java.util.stream.Collectors; import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry; @@ -46,6 +47,7 @@ import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleParameterAnnotations; import com.sun.org.apache.bcel.internal.classfile.Utility; import com.sun.org.apache.bcel.internal.util.BCELComparator; +import jdk.xml.internal.Utils; /** * Template class for building up a method. This is done by defining exception handlers, adding thrown exceptions, local @@ -57,7 +59,7 @@ * * @see InstructionList * @see Method - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class MethodGen extends FieldGenOrMethodGen { @@ -102,19 +104,16 @@ static final class BranchTarget { } } - private static BCELComparator bcelComparator = new BCELComparator() { + private static BCELComparator bcelComparator = new BCELComparator() { @Override - public boolean equals(final Object o1, final Object o2) { - final FieldGenOrMethodGen THIS = (FieldGenOrMethodGen) o1; - final FieldGenOrMethodGen THAT = (FieldGenOrMethodGen) o2; - return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature()); + public boolean equals(final FieldGenOrMethodGen a, final FieldGenOrMethodGen b) { + return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature()); } @Override - public int hashCode(final Object o) { - final FieldGenOrMethodGen THIS = (FieldGenOrMethodGen) o; - return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); + public int hashCode(final FieldGenOrMethodGen o) { + return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0; } }; @@ -127,9 +126,9 @@ private static byte[] getByteCodes(final Method method) { } /** - * @return Comparison strategy object + * @return Comparison strategy object. */ - public static BCELComparator getComparator() { + public static BCELComparator getComparator() { return bcelComparator; } @@ -206,9 +205,9 @@ public static int getMaxStack(final ConstantPoolGen cp, final InstructionList il } /** - * @param comparator Comparison strategy object + * @param comparator Comparison strategy object. */ - public static void setComparator(final BCELComparator comparator) { + public static void setComparator(final BCELComparator comparator) { bcelComparator = comparator; } @@ -636,7 +635,7 @@ private void ensureExistingParameterAnnotationsUnpacked() { */ @Override public boolean equals(final Object obj) { - return bcelComparator.equals(this, obj); + return obj instanceof FieldGenOrMethodGen && bcelComparator.equals(this, (FieldGenOrMethodGen) obj); } // J5TODO: Should paramAnnotations be an array of arrays? Rather than an array of lists, this @@ -790,7 +789,7 @@ public int getMaxStack() { } /** - * Get method object. Never forget to call setMaxStack() or setMaxStack(max), respectively, before calling this method + * Gets method object. Never forget to call setMaxStack() or setMaxStack(max), respectively, before calling this method * (the same applies for max locals). * * @return method object @@ -888,7 +887,7 @@ public String getSignature() { } /** - * Return value as defined by given BCELComparator strategy. By default return the hashcode of the method's name XOR + * Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR * signature. * * @see Object#hashCode() @@ -899,11 +898,7 @@ public int hashCode() { } private List makeMutableVersion(final AnnotationEntry[] mutableArray) { - final List result = new ArrayList<>(); - for (final AnnotationEntry element : mutableArray) { - result.add(new AnnotationEntryGen(element, getConstantPool(), false)); - } - return result; + return Utils.streamOfIfNonNull(mutableArray).map(ae -> new AnnotationEntryGen(ae, getConstantPool(), false)).collect(Collectors.toList()); } /** @@ -1027,10 +1022,8 @@ public void removeObserver(final MethodObserver o) { * * @since 6.5.0 */ - public void removeRuntimeAttributes(final Attribute[] attrs) { - for (final Attribute attr : attrs) { - removeAttribute(attr); - } + public void removeRuntimeAttributes(final Attribute[] attributes) { + Utils.streamOfIfNonNull(attributes).forEach(this::removeAttribute); } public void setArgumentName(final int i, final String name) { @@ -1038,7 +1031,7 @@ public void setArgumentName(final int i, final String name) { } public void setArgumentNames(final String[] argNames) { - this.argNames = argNames; + this.argNames = Utils.createEmptyArrayIfNull(argNames, String[].class); } public void setArgumentType(final int i, final Type type) { @@ -1046,7 +1039,7 @@ public void setArgumentType(final int i, final Type type) { } public void setArgumentTypes(final Type[] argTypes) { - this.argTypes = argTypes; + this.argTypes = argTypes != null ? argTypes : Type.NO_ARGS; } public void setClassName(final String className) { // TODO could be package-protected? @@ -1084,7 +1077,7 @@ public void setMaxLocals() { // TODO could be package-protected? (some tests wou } /** - * Set maximum number of local variables. + * Sets maximum number of local variables. */ public void setMaxLocals(final int m) { maxLocals = m; @@ -1102,7 +1095,7 @@ public void setMaxStack() { // TODO could be package-protected? (some tests woul } /** - * Set maximum stack size for this method. + * Sets maximum stack size for this method. */ public void setMaxStack(final int m) { // TODO could be package-protected? maxStack = m; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ObjectType.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ObjectType.java index 46378a1b71e..622a3cdd961 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ObjectType.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ObjectType.java @@ -27,7 +27,7 @@ import com.sun.org.apache.bcel.internal.classfile.Utility; /** - * Denotes reference such as java.lang.String. + * Denotes reference such as {@link String}. */ public class ObjectType extends ReferenceType { @@ -47,7 +47,7 @@ public static ObjectType getInstance(final String className) { /** * Constructs a new instance. * - * @param className fully qualified class name, e.g. java.lang.String + * @param className fully qualified class name, e.g. {@link String} */ public ObjectType(final String className) { super(Const.T_REFERENCE, "L" + Utility.packageToPath(className) + ";"); @@ -151,7 +151,7 @@ public boolean referencesInterfaceExact() throws ClassNotFoundException { * @throws ClassNotFoundException if any of this class's superclasses can't be found */ public boolean subclassOf(final ObjectType superclass) throws ClassNotFoundException { - if (this.referencesInterfaceExact() || superclass.referencesInterfaceExact()) { + if (referencesInterfaceExact() || superclass.referencesInterfaceExact()) { return false; } return Repository.instanceOf(this.className, superclass.className); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/RET.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/RET.java index a7cacc7c165..99a1efbed16 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/RET.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/RET.java @@ -110,7 +110,7 @@ protected void initFromFile(final ByteSequence bytes, final boolean wide) throws } /** - * Set index of local variable containg the return address + * Sets index of local variable containg the return address */ @Override public final void setIndex(final int n) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ReferenceType.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ReferenceType.java index fe75792e213..9b94a1dcf2d 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ReferenceType.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ReferenceType.java @@ -42,10 +42,10 @@ protected ReferenceType(final byte t, final String s) { /** * This commutative operation returns the first common superclass (narrowest ReferenceType referencing a class, not an - * interface). If one of the types is a superclass of the other, the former is returned. If "this" is Type.NULL, then t - * is returned. If t is Type.NULL, then "this" is returned. If "this" equals t ['this.equals(t)'] "this" is returned. If - * "this" or t is an ArrayType, then Type.OBJECT is returned. If "this" or t is a ReferenceType referencing an - * interface, then Type.OBJECT is returned. If not all of the two classes' superclasses cannot be found, "null" is + * interface). If one of the types is a superclass of the other, the former is returned. If "this" is NULL, then t + * is returned. If t is NULL, then "this" is returned. If "this" equals t ['this.equals(t)'] "this" is returned. If + * "this" or t is an ArrayType, then {@link #OBJECT} is returned. If "this" or t is a ReferenceType referencing an + * interface, then {@link #OBJECT} is returned. If not all of the two classes' superclasses cannot be found, "null" is * returned. See the JVM specification edition 2, "4.9.2 The Bytecode Verifier". * * @deprecated use getFirstCommonSuperclass(ReferenceType t) which has slightly changed semantics. @@ -53,46 +53,46 @@ protected ReferenceType(final byte t, final String s) { */ @Deprecated public ReferenceType firstCommonSuperclass(final ReferenceType t) throws ClassNotFoundException { - if (this.equals(Type.NULL)) { + if (equals(NULL)) { return t; } - if (t.equals(Type.NULL) || this.equals(t)) { + if (t.equals(NULL) || equals(t)) { return this; /* - * TODO: Above sounds a little arbitrary. On the other hand, there is no object referenced by Type.NULL so we can also - * say all the objects referenced by Type.NULL were derived from java.lang.Object. However, the Java Language's - * "instanceof" operator proves us wrong: "null" is not referring to an instance of java.lang.Object :) + * TODO: Above sounds a little arbitrary. On the other hand, there is no object referenced by {@link #NULL} so we can also + * say all the objects referenced by {@link #NULL} were derived from {@link Object}. However, the Java Language's + * "instanceof" operator proves us wrong: "null" is not referring to an instance of {@link Object} :) */ } if (this instanceof ArrayType || t instanceof ArrayType) { - return Type.OBJECT; - // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? + return OBJECT; + // TODO: Is there a proof of {@link #OBJECT} being the direct ancestor of every ArrayType? } return getFirstCommonSuperclassInternal(t); } /** * This commutative operation returns the first common superclass (narrowest ReferenceType referencing a class, not an - * interface). If one of the types is a superclass of the other, the former is returned. If "this" is Type.NULL, then t - * is returned. If t is Type.NULL, then "this" is returned. If "this" equals t ['this.equals(t)'] "this" is returned. If - * "this" or t is an ArrayType, then Type.OBJECT is returned; unless their dimensions match. Then an ArrayType of the + * interface). If one of the types is a superclass of the other, the former is returned. If "this" is NULL, then t + * is returned. If t is NULL, then "this" is returned. If "this" equals t ['this.equals(t)'] "this" is returned. If + * "this" or t is an ArrayType, then {@link #OBJECT} is returned; unless their dimensions match. Then an ArrayType of the * same number of dimensions is returned, with its basic type being the first common super class of the basic types of - * "this" and t. If "this" or t is a ReferenceType referencing an interface, then Type.OBJECT is returned. If not all of + * "this" and t. If "this" or t is a ReferenceType referencing an interface, then {@link #OBJECT} is returned. If not all of * the two classes' superclasses cannot be found, "null" is returned. See the JVM specification edition 2, "4.9.2 The * Bytecode Verifier". * * @throws ClassNotFoundException on failure to find superclasses of this type, or the type passed as a parameter */ public ReferenceType getFirstCommonSuperclass(final ReferenceType t) throws ClassNotFoundException { - if (this.equals(Type.NULL)) { + if (equals(NULL)) { return t; } - if (t.equals(Type.NULL) || this.equals(t)) { + if (t.equals(NULL) || equals(t)) { return this; /* - * TODO: Above sounds a little arbitrary. On the other hand, there is no object referenced by Type.NULL so we can also - * say all the objects referenced by Type.NULL were derived from java.lang.Object. However, the Java Language's - * "instanceof" operator proves us wrong: "null" is not referring to an instance of java.lang.Object :) + * TODO: Above sounds a little arbitrary. On the other hand, there is no object referenced by {@link #NULL} so we can also + * say all the objects referenced by {@link #NULL} were derived from {@link Object}. However, the Java Language's + * "instanceof" operator proves us wrong: "null" is not referring to an instance of {@link Object} :) */ } /* This code is from a bug report by Konstantin Shagin */ @@ -106,8 +106,8 @@ public ReferenceType getFirstCommonSuperclass(final ReferenceType t) throws Clas } } if (this instanceof ArrayType || t instanceof ArrayType) { - return Type.OBJECT; - // TODO: Is there a proof of OBJECT being the direct ancestor of every ArrayType? + return OBJECT; + // TODO: Is there a proof of {@link #OBJECT} being the direct ancestor of every ArrayType? } return getFirstCommonSuperclassInternal(t); } @@ -115,7 +115,7 @@ public ReferenceType getFirstCommonSuperclass(final ReferenceType t) throws Clas private ReferenceType getFirstCommonSuperclassInternal(final ReferenceType t) throws ClassNotFoundException { if (this instanceof ObjectType && ((ObjectType) this).referencesInterfaceExact() || t instanceof ObjectType && ((ObjectType) t).referencesInterfaceExact()) { - return Type.OBJECT; + return OBJECT; // TODO: The above line is correct comparing to the vmspec2. But one could // make class file verification a bit stronger here by using the notion of // superinterfaces or even castability or assignment compatibility. @@ -142,7 +142,7 @@ private ReferenceType getFirstCommonSuperclassInternal(final ReferenceType t) th } } } - // Huh? Did you ask for Type.OBJECT's superclass?? + // Huh? Did you ask for OBJECT's superclass?? return null; } @@ -158,7 +158,7 @@ public boolean isAssignmentCompatibleWith(final Type t) throws ClassNotFoundExce return false; } final ReferenceType T = (ReferenceType) t; - if (this.equals(Type.NULL)) { + if (equals(NULL)) { return true; // This is not explicitly stated, but clear. Isn't it? } /* @@ -169,7 +169,7 @@ public boolean isAssignmentCompatibleWith(final Type t) throws ClassNotFoundExce * If T is a class type, then this must be the same class as T, or this must be a subclass of T; */ if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() - && (this.equals(T) || Repository.instanceOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) { + && (equals(T) || Repository.instanceOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) { return true; } /* @@ -187,14 +187,14 @@ public boolean isAssignmentCompatibleWith(final Type t) throws ClassNotFoundExce /* * If T is a class type, then T must be Object (2.4.7). */ - if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() && T.equals(Type.OBJECT)) { + if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() && T.equals(OBJECT)) { return true; } /* * If T is an interface type, then T must be the same interface as this or a superinterface of this (2.13.2). */ if (T instanceof ObjectType && ((ObjectType) T).referencesInterfaceExact() - && (this.equals(T) || Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) { + && (equals(T) || Repository.implementationOf(((ObjectType) this).getClassName(), ((ObjectType) T).getClassName()))) { return true; } } @@ -205,7 +205,7 @@ public boolean isAssignmentCompatibleWith(final Type t) throws ClassNotFoundExce /* * If T is a class type, then T must be Object (2.4.7). */ - if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() && T.equals(Type.OBJECT)) { + if (T instanceof ObjectType && ((ObjectType) T).referencesClassExact() && T.equals(OBJECT)) { return true; } /* @@ -246,14 +246,14 @@ public boolean isAssignmentCompatibleWith(final Type t) throws ClassNotFoundExce /** * Return true iff this type is castable to another type t as defined in the JVM specification. The case where this is - * Type.NULL is not defined (see the CHECKCAST definition in the JVM specification). However, because e.g. CHECKCAST + * {@link #NULL} is not defined (see the CHECKCAST definition in the JVM specification). However, because e.g. CHECKCAST * doesn't throw a ClassCastException when casting a null reference to any Object, true is returned in this case. * * @throws ClassNotFoundException if any classes or interfaces required to determine assignment compatibility can't be * found */ public boolean isCastableTo(final Type t) throws ClassNotFoundException { - if (this.equals(Type.NULL)) { + if (equals(NULL)) { return t instanceof ReferenceType; // If this is ever changed in isAssignmentCompatible() } return isAssignmentCompatibleWith(t); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SWITCH.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SWITCH.java index aed1626ec0d..f929176c174 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SWITCH.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SWITCH.java @@ -95,7 +95,7 @@ public SWITCH(final int[] match, final InstructionHandle[] targets, final Instru * @param maxGap maximum gap that may between case branches */ public SWITCH(final int[] match, final InstructionHandle[] targets, final InstructionHandle target, final int maxGap) { - int[] matchClone = match.clone(); + final int[] matchClone = match.clone(); final InstructionHandle[] targetsClone = targets.clone(); final int matchLength = match.length; if (matchLength < 2) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Select.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Select.java index a90e795e99f..a3086ac1664 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Select.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Select.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -33,7 +33,7 @@ * @see LOOKUPSWITCH * @see TABLESWITCH * @see InstructionList - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public abstract class Select extends BranchInstruction implements VariableLengthInstruction, StackConsumer /* @since 6.0 */, StackProducer { @@ -87,7 +87,7 @@ public abstract class Select extends BranchInstruction implements VariableLength * @param defaultTarget default instruction target */ Select(final short opcode, final int[] match, final InstructionHandle[] targets, final InstructionHandle defaultTarget) { - // don't set default target before instuction is built + // don't set default target before instruction is built super(opcode, null); this.match = match; this.targets = targets; @@ -288,7 +288,7 @@ final int setMatchLength(final int matchLength) { } /** - * Set branch target for 'i'th case + * Sets branch target for 'i'th case */ public void setTarget(final int i, final InstructionHandle target) { // TODO could be package-protected? notifyTarget(targets[i], target, this); @@ -314,7 +314,11 @@ public String toString(final boolean verbose) { for (int i = 0; i < match_length; i++) { String s = "null"; if (targets[i] != null) { - s = targets[i].getInstruction().toString(); + if (targets[i].getInstruction() == this) { + s = ""; + } else { + s = targets[i].getInstruction().toString(); + } } buf.append("(").append(match[i]).append(", ").append(s).append(" = {").append(indices[i]).append("})"); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SimpleElementValueGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SimpleElementValueGen.java index a4de20315d7..363b3237632 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SimpleElementValueGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/SimpleElementValueGen.java @@ -166,7 +166,7 @@ public void dump(final DataOutputStream dos) throws IOException { dos.writeShort(idx); break; default: - throw new IllegalStateException("SimpleElementValueGen doesnt know how to write out type " + super.getElementValueType()); + throw new IllegalStateException("SimpleElementValueGen doesn't know how to write out type " + super.getElementValueType()); } } @@ -184,7 +184,7 @@ public int getIndex() { public int getValueInt() { if (super.getElementValueType() != PRIMITIVE_INT) { - throw new IllegalStateException("Dont call getValueString() on a non STRING ElementValue"); + throw new IllegalStateException("Don't call getValueString() on a non STRING ElementValue"); } final ConstantInteger c = (ConstantInteger) getConstantPool().getConstant(idx); return c.getBytes(); @@ -192,7 +192,7 @@ public int getValueInt() { public String getValueString() { if (super.getElementValueType() != STRING) { - throw new IllegalStateException("Dont call getValueString() on a non STRING ElementValue"); + throw new IllegalStateException("Don't call getValueString() on a non STRING ElementValue"); } final ConstantUtf8 c = (ConstantUtf8) getConstantPool().getConstant(idx); return c.getBytes(); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TargetLostException.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TargetLostException.java index 40ed6ff4c38..038bbe63148 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TargetLostException.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TargetLostException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -21,32 +21,32 @@ package com.sun.org.apache.bcel.internal.generic; /** - * Thrown by InstructionList.remove() when one or multiple disposed instructions are still being referenced by an - * InstructionTargeter object. I.e. the InstructionTargeter has to be notified that (one of) the InstructionHandle it is - * referencing is being removed from the InstructionList and thus not valid anymore. + * Thrown by {@link InstructionList} when one or multiple disposed instructions are still being referenced by an {@link InstructionTargeter} object. I.e. the + * {@link InstructionTargeter} has to be notified that (one of) the {@link InstructionHandle} it is referencing is being removed from the + * {@link InstructionList} and thus not valid anymore. * *

- * Making this an exception instead of a return value forces the user to handle these case explicitly in a try { ... } - * catch. The following code illustrates how this may be done: + * Making this an exception instead of a return value forces the user to handle these case explicitly in a try { ... } catch. The following code illustrates how + * this may be done: *

* - *
+ * 
  *     ...
  *     try {
  *         il.delete(start_ih, end_ih);
- *     } catch(TargetLostException e) {
+ *     } catch (TargetLostException e) {
  *         for (InstructionHandle target : e.getTargets()) {
  *             for (InstructionTargeter targeter : target.getTargeters()) {
  *                 targeter.updateTarget(target, new_target);
  *             }
  *         }
  *     }
- * 
+ *
* * @see InstructionHandle * @see InstructionList * @see InstructionTargeter - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public final class TargetLostException extends Exception { @@ -54,12 +54,14 @@ public final class TargetLostException extends Exception { @SuppressWarnings("serial") // Array component type is not Serializable private final InstructionHandle[] targets; - TargetLostException(final InstructionHandle[] t, final String mesg) { - super(mesg); - targets = t; + TargetLostException(final InstructionHandle[] targets, final String message) { + super(message); + this.targets = targets; } /** + * Gets the list of instructions still being targeted. + * * @return list of instructions still being targeted. */ public InstructionHandle[] getTargets() { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Type.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Type.java index ea20710af2e..b58645b402e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Type.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/Type.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -26,12 +26,14 @@ import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.classfile.ClassFormatException; +import com.sun.org.apache.bcel.internal.classfile.InvalidMethodSignatureException; import com.sun.org.apache.bcel.internal.classfile.Utility; +import jdk.xml.internal.Utils; /** - * Abstract super class for all possible java types, namely basic types such as int, object types like String and array + * Abstract super class for all possible Java types, namely basic types such as int, object types like String and array * types, e.g. int[] - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public abstract class Type { @@ -88,15 +90,15 @@ public static Type[] getArgumentTypes(final String signature) { // Skip any type arguments to read argument declarations between '(' and ')' index = signature.indexOf('(') + 1; if (index <= 0) { - throw new ClassFormatException("Invalid method signature: " + signature); + throw new InvalidMethodSignatureException(signature); } while (signature.charAt(index) != ')') { vec.add(getType(signature.substring(index))); - // corrected concurrent private static field acess + // corrected concurrent private static field access index += unwrap(CONSUMED_CHARS); // update position } } catch (final StringIndexOutOfBoundsException e) { // Should never occur - throw new ClassFormatException("Invalid method signature: " + signature, e); + throw new InvalidMethodSignatureException(signature, e); } final Type[] types = new Type[vec.size()]; vec.toArray(types); @@ -110,7 +112,7 @@ static int getArgumentTypesSize(final String signature) { // Skip any type arguments to read argument declarations between '(' and ')' index = signature.indexOf('(') + 1; if (index <= 0) { - throw new ClassFormatException("Invalid method signature: " + signature); + throw new InvalidMethodSignatureException(signature); } while (signature.charAt(index) != ')') { final int coded = getTypeSize(signature.substring(index)); @@ -118,7 +120,7 @@ static int getArgumentTypesSize(final String signature) { index += consumed(coded); } } catch (final StringIndexOutOfBoundsException e) { // Should never occur - throw new ClassFormatException("Invalid method signature: " + signature, e); + throw new InvalidMethodSignatureException(signature, e); } return res; } @@ -154,13 +156,13 @@ public static Type getReturnType(final String signature) { final int index = signature.lastIndexOf(')') + 1; return getType(signature.substring(index)); } catch (final StringIndexOutOfBoundsException e) { // Should never occur - throw new ClassFormatException("Invalid method signature: " + signature, e); + throw new InvalidMethodSignatureException(signature, e); } } static int getReturnTypeSize(final String signature) { final int index = signature.lastIndexOf(')') + 1; - return Type.size(getTypeSize(signature.substring(index))); + return size(getTypeSize(signature.substring(index))); } public static String getSignature(final java.lang.reflect.Method meth) { @@ -175,7 +177,7 @@ public static String getSignature(final java.lang.reflect.Method meth) { } /** - * Convert runtime java.lang.Class to BCEL Type object. + * Convert runtime {@link Class} to BCEL Type object. * * @param cls Java class * @return corresponding Type object @@ -183,7 +185,7 @@ public static String getSignature(final java.lang.reflect.Method meth) { public static Type getType(final Class cls) { Objects.requireNonNull(cls, "cls"); /* - * That's an amzingly easy case, because getName() returns the signature. That's what we would have liked anyway. + * That's an amazingly easy case, because getName() returns the signature. That's what we would have liked anyway. */ if (cls.isArray()) { return getType(cls.getName()); @@ -230,7 +232,7 @@ public static Type getType(final Class cls) { public static Type getType(final String signature) throws StringIndexOutOfBoundsException { final byte type = Utility.typeOfSignature(signature); if (type <= Const.T_VOID) { - // corrected concurrent private static field acess + // corrected concurrent private static field access wrap(CONSUMED_CHARS, 1); return BasicType.getType(type); } @@ -246,7 +248,7 @@ public static Type getType(final String signature) throws StringIndexOutOfBounds } while (signature.charAt(dim) == '['); // Recurse, but just once, if the signature is ok final Type t = getType(signature.substring(dim)); - // corrected concurrent private static field acess + // corrected concurrent private static field access // consumed_chars += dim; // update counter - is replaced by final int temp = unwrap(CONSUMED_CHARS) + dim; wrap(CONSUMED_CHARS, temp); @@ -254,7 +256,7 @@ public static Type getType(final String signature) throws StringIndexOutOfBounds } /** - * Convert runtime java.lang.Class[] to BCEL Type objects. + * Convert runtime {@code java.lang.Class[]} to BCEL Type objects. * * @param classes an array of runtime class objects * @return array of corresponding Type objects @@ -286,6 +288,24 @@ static int getTypeSize(final String signature) throws StringIndexOutOfBoundsExce return encode(1, index + 1); } + static String internalTypeNameToSignature(final String internalTypeName) { + if (Utils.isEmpty(internalTypeName) || Arrays.asList(Const.SHORT_TYPE_NAMES).contains(internalTypeName)) { + return internalTypeName; + } + switch (internalTypeName.charAt(0)) { + case '[': + return internalTypeName; + case 'L': + case 'T': + if (internalTypeName.charAt(internalTypeName.length() - 1) == ';') { + return internalTypeName; + } + return 'L' + internalTypeName + ';'; + default: + return 'L' + internalTypeName + ';'; + } + } + static int size(final int coded) { return coded & 3; } @@ -361,7 +381,7 @@ public byte getType() { } /** - * @return hashcode of Type + * @return hash code of Type */ @Override public int hashCode() { @@ -369,31 +389,23 @@ public int hashCode() { } /** - * boolean, short and char variable are considered as int in the stack or local variable area. Returns {@link Type#INT} - * for {@link Type#BOOLEAN}, {@link Type#SHORT} or {@link Type#CHAR}, otherwise returns the given type. + * boolean, short and char variable are considered as int in the stack or local variable area. Returns {@link #INT} + * for {@link #BOOLEAN}, {@link #SHORT} or {@link #CHAR}, otherwise returns the given type. * * @since 6.0 */ public Type normalizeForStackOrLocal() { - if (this == Type.BOOLEAN || this == Type.BYTE || this == Type.SHORT || this == Type.CHAR) { - return Type.INT; + if (this == BOOLEAN || this == BYTE || this == SHORT || this == CHAR) { + return INT; } return this; } - /* - * Currently only used by the ArrayType constructor. The signature has a complicated dependency on other parameter so - * it's tricky to do it in a call to the super ctor. - */ - void setSignature(final String signature) { - this.signature = signature; - } - /** * @return Type string, e.g. 'int[]' */ @Override public String toString() { - return this.equals(Type.NULL) || type >= Const.T_UNKNOWN ? signature : Utility.signatureToString(signature, false); + return equals(NULL) || type >= Const.T_UNKNOWN ? signature : Utility.signatureToString(signature, false); } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TypedInstruction.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TypedInstruction.java index 5a22942a6a7..27b952f3996 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TypedInstruction.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TypedInstruction.java @@ -22,7 +22,7 @@ package com.sun.org.apache.bcel.internal.generic; /** - * Get the type associated with an instruction, int for ILOAD, or the type of the field of a PUTFIELD instruction, e.g.. + * Gets the type associated with an instruction, int for ILOAD, or the type of the field of a PUTFIELD instruction, e.g.. */ public interface TypedInstruction { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/package-info.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/package-info.java new file mode 100644 index 00000000000..63d4dc876ce --- /dev/null +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/package-info.java @@ -0,0 +1,26 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Generic part of the Apache Byte Code Engineering Library (BCEL), classes to dynamically modify class objects + * and byte code instructions. + */ +package com.sun.org.apache.bcel.internal.generic; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/package-info.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/package-info.java new file mode 100644 index 00000000000..581037d7981 --- /dev/null +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/package-info.java @@ -0,0 +1,26 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Basic classes for the Apache Byte Code Engineering Library (BCEL) and constants defined by the + * JVM specification. + */ +package com.sun.org.apache.bcel.internal; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELComparator.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELComparator.java index 2e663bfdaa1..fb32dc35e0b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELComparator.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELComparator.java @@ -22,26 +22,27 @@ package com.sun.org.apache.bcel.internal.util; /** - * Used for BCEL comparison strategy + * Used for BCEL comparison strategy. * + * @param What type we are comparing. * @since 5.2 */ -public interface BCELComparator { +public interface BCELComparator { /** - * Compare two objects and return what THIS.equals(THAT) should return + * Compares two objects and return what a.equals(b) should return. * - * @param THIS - * @param THAT - * @return true if and only if THIS equals THAT + * @param a an object. + * @param b an object to be compared with {@code a} for equality. + * @return {@code true} if the arguments are equal to each other and {@code false} otherwise. */ - boolean equals(Object THIS, Object THAT); + boolean equals(T a, T b); /** - * Return hashcode for THIS.hashCode() + * Gets the hash code for o.hashCode() * - * @param THIS - * @return hashcode for THIS.hashCode() + * @param o + * @return hash code for o.hashCode() */ - int hashCode(Object THIS); + int hashCode(T o); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELFactory.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELFactory.java index c931fb1e422..93f22e7d0ad 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELFactory.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -63,9 +63,9 @@ * Factory creates il.append() statements, and sets instruction targets. A helper class for BCELifier. * * @see BCELifier - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ -class BCELFactory extends EmptyVisitor { +final class BCELFactory extends EmptyVisitor { private static final String CONSTANT_PREFIX = Const.class.getSimpleName() + "."; private final MethodGen methodGen; @@ -88,7 +88,7 @@ private void createConstant(final Object value) { if (value instanceof String) { embed = '"' + Utility.convertString(embed) + '"'; } else if (value instanceof Character) { - embed = "(char)0x" + Integer.toHexString(((Character) value).charValue()); + embed = "(char) 0x" + Integer.toHexString(((Character) value).charValue()); } else if (value instanceof Float) { final Float f = (Float) value; if (Float.isNaN(f)) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELifier.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELifier.java index 151083ea71b..0eb9bfb4ee1 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELifier.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/BCELifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,11 +30,15 @@ import com.sun.org.apache.bcel.internal.Const; import com.sun.org.apache.bcel.internal.Repository; import com.sun.org.apache.bcel.internal.classfile.ClassParser; +import com.sun.org.apache.bcel.internal.classfile.Code; import com.sun.org.apache.bcel.internal.classfile.ConstantValue; import com.sun.org.apache.bcel.internal.classfile.ExceptionTable; import com.sun.org.apache.bcel.internal.classfile.Field; import com.sun.org.apache.bcel.internal.classfile.JavaClass; import com.sun.org.apache.bcel.internal.classfile.Method; +import com.sun.org.apache.bcel.internal.classfile.StackMap; +import com.sun.org.apache.bcel.internal.classfile.StackMapEntry; +import com.sun.org.apache.bcel.internal.classfile.StackMapType; import com.sun.org.apache.bcel.internal.classfile.Utility; import com.sun.org.apache.bcel.internal.generic.ArrayType; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; @@ -46,7 +50,7 @@ * This gives new users of BCEL a useful example showing how things are done with BCEL. It does not cover all features * of BCEL, but tries to mimic hand-written code as close as possible. * - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class BCELifier extends com.sun.org.apache.bcel.internal.classfile.EmptyVisitor { @@ -74,7 +78,7 @@ static JavaClass getJavaClass(final String name) throws ClassNotFoundException, /** * Default main method */ - public static void _main(final String[] argv) throws Exception { + public static void main(final String[] argv) throws Exception { if (argv.length != 1) { System.out.println("Usage: BCELifier className"); System.out.println("\tThe class must exist on the classpath"); @@ -311,6 +315,13 @@ public void visitMethod(final Method method) { printWriter.println("\");"); } } + final Code code = method.getCode(); + if (code != null) { + final StackMap stackMap = code.getStackMap(); + if (stackMap != null) { + stackMap.accept(this); + } + } printWriter.println(); final BCELFactory factory = new BCELFactory(mg, printWriter); factory.start(); @@ -319,4 +330,78 @@ public void visitMethod(final Method method) { printWriter.println(" _cg.addMethod(method.getMethod());"); printWriter.println(" il.dispose();"); } + + @Override + public void visitStackMap(final StackMap stackMap) { + super.visitStackMap(stackMap); + printWriter.print(" method.addCodeAttribute("); + printWriter.print("new StackMap(_cp.addUtf8(\""); + printWriter.print(stackMap.getName()); + printWriter.print("\"), "); + printWriter.print(stackMap.getLength()); + printWriter.print(", "); + printWriter.print("new StackMapEntry[] {"); + final StackMapEntry[] table = stackMap.getStackMap(); + for (int i = 0; i < table.length; i++) { + table[i].accept(this); + if (i < table.length - 1) { + printWriter.print(", "); + } else { + printWriter.print(" }"); + } + } + printWriter.print(", _cp.getConstantPool())"); + printWriter.println(");"); + } + + @Override + public void visitStackMapEntry(final StackMapEntry stackMapEntry) { + super.visitStackMapEntry(stackMapEntry); + printWriter.print("new StackMapEntry("); + printWriter.print(stackMapEntry.getFrameType()); + printWriter.print(", "); + printWriter.print(stackMapEntry.getByteCodeOffset()); + printWriter.print(", "); + visitStackMapTypeArray(stackMapEntry.getTypesOfLocals()); + printWriter.print(", "); + visitStackMapTypeArray(stackMapEntry.getTypesOfStackItems()); + printWriter.print(", _cp.getConstantPool())"); + } + + /** + * Visits a {@link StackMapType} object. + * @param stackMapType object to visit + * @since 6.7.1 + */ + @Override + public void visitStackMapType(final StackMapType stackMapType) { + super.visitStackMapType(stackMapType); + printWriter.print("new StackMapType((byte)"); + printWriter.print(stackMapType.getType()); + printWriter.print(", "); + if (stackMapType.hasIndex()) { + printWriter.print("_cp.addClass(\""); + printWriter.print(stackMapType.getClassName()); + printWriter.print("\")"); + } else { + printWriter.print("-1"); + } + printWriter.print(", _cp.getConstantPool())"); + } + + private void visitStackMapTypeArray(final StackMapType[] types) { + if (types == null || types.length == 0) { + printWriter.print("null"); // null translates to StackMapType.EMPTY_ARRAY + } else { + printWriter.print("new StackMapType[] {"); + for (int i = 0; i < types.length; i++) { + types[i].accept(this); + if (i < types.length - 1) { + printWriter.print(", "); + } else { + printWriter.print(" }"); + } + } + } + } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Class2HTML.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Class2HTML.java index f644c698b72..10d31974d47 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Class2HTML.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Class2HTML.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -53,7 +53,7 @@ * All subfiles reference each other appropriately, e.g. clicking on a method in the Method's frame will jump to the * appropriate method in the Code frame. * - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class Class2HTML { @@ -73,7 +73,7 @@ public class Class2HTML { basicTypes.add("float"); } - public static void _main(final String[] argv) throws IOException { + public static void main(final String[] argv) throws IOException { final String[] fileName = new String[argv.length]; int files = 0; ClassParser parser = null; @@ -89,7 +89,7 @@ public static void _main(final String[] argv) throws IOException { if (argv[i].equals("-d")) { // Specify target directory, default '.' dir = argv[++i]; if (!dir.endsWith("" + sep)) { - dir = dir + sep; + dir += sep; } final File store = new File(dir); if (!store.isDirectory()) { @@ -115,7 +115,7 @@ public static void _main(final String[] argv) throws IOException { if (zipFile == null) { parser = new ClassParser(fileName[i]); // Create parser object from file } else { - parser = new ClassParser(zipFile, fileName[i]); // Create parser object from zip file + parser = new ClassParser(zipFile, fileName[i]); // Create parser object from ZIP file } javaClass = parser.parse(); new Class2HTML(javaClass, dir); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/ClassSet.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/ClassSet.java index 178ccc786b1..e95e8fbd0a0 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/ClassSet.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/ClassSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -30,7 +30,7 @@ * Utility class implementing a (type-safe) set of JavaClass objects. Since JavaClass has no equals() method, the name of the class is used for comparison. * * @see ClassStack - * @LastModified: Feb 2023 + * @LastModified: Sept 2025 */ public class ClassSet { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/CodeHTML.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/CodeHTML.java index 723fc07509b..1935d724b3b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/CodeHTML.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/CodeHTML.java @@ -542,7 +542,7 @@ private void writeMethod(final Method method, final int methodNumber) throws IOE final String str = codeToHTML(stream, methodNumber); String anchor = ""; /* - * Set an anchor mark if this line is targetted by a goto, jsr, etc. Defining an anchor for every line is very + * Sets an anchor mark if this line is targetted by a goto, jsr, etc. Defining an anchor for every line is very * inefficient! */ if (gotoSet.get(offset)) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/InstructionFinder.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/InstructionFinder.java index 5b045bf08cc..510fe4a03a6 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/InstructionFinder.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/InstructionFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -63,14 +63,13 @@ * * @see com.sun.org.apache.bcel.internal.generic.Instruction * @see InstructionList - * @LastModified: May 2021 + * @LastModified: Sept 2025 */ public class InstructionFinder { /** * Code patterns found may be checked using an additional user-defined constraint object whether they really match the * needed criterion. I.e., check constraints that can not expressed with regular expressions. - * */ public interface CodeConstraint { @@ -374,7 +373,7 @@ public final Iterator search(final String pattern, final In // } // private static final String pattern2string( String pattern, boolean make_string ) { -// StringBuffer buf = new StringBuffer(); +// StringBuilder buf = new StringBuilder(); // for (int i = 0; i < pattern.length(); i++) { // char ch = pattern.charAt(i); // if (ch >= OFFSET) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Repository.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Repository.java index 8d1ddf493cd..c44e36d0a81 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Repository.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/Repository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -25,8 +25,8 @@ * Abstract definition of a class repository. Instances may be used to load classes from different sources and may be * used in the Repository.setRepository method. * - * @see org.apache.bcel.Repository - * @LastModified: Feb 2023 + * @see com.sun.org.apache.bcel.internal.Repository + * @LastModified: Sept 2025 */ public interface Repository { diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/package-info.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/package-info.java new file mode 100644 index 00000000000..2bd92f155bc --- /dev/null +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/util/package-info.java @@ -0,0 +1,32 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Utility classes for the Apache Byte Code Engineering Library (BCEL), namely: + *
    + *
  • Collection classes for JavaClass objects
  • + *
  • A converter for class files to HTML
  • + *
  • A tool to find instructions patterns via regular expressions
  • + *
  • A class to find classes as defined in the CLASSPATH
  • + *
  • A class loader that allows to create classes at run time
  • + *
+ */ +package com.sun.org.apache.bcel.internal.util; diff --git a/src/java.xml/share/classes/jdk/xml/internal/Utils.java b/src/java.xml/share/classes/jdk/xml/internal/Utils.java index f55ab95a58f..96d9b1b9521 100644 --- a/src/java.xml/share/classes/jdk/xml/internal/Utils.java +++ b/src/java.xml/share/classes/jdk/xml/internal/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,11 @@ package jdk.xml.internal; +import java.lang.reflect.Array; import java.util.Arrays; +import java.util.Objects; import java.util.function.Supplier; +import java.util.stream.Stream; /** * General utility. Use JdkXmlUtils for XML processing related functions. @@ -76,4 +79,59 @@ public static Class[] arraysAppend(final Class[] original, final Class. System.arraycopy(items, 0, result, original.length, items.length); return result; } + + /** + * Returns the original array, or an empty array if it is {@code null}. + * @param array the specified array + * @return the original array, or an empty array if it is {@code null} + */ + public static byte[] createEmptyArrayIfNull(byte[] array) { + return (array != null) ? array : new byte[0]; + } + + /** + * Returns the original array, or an empty array if it is {@code null}. + * @param array the specified array + * @return the original array, or an empty array if it is {@code null} + */ + public static int[] createEmptyArrayIfNull(int[] array) { + return (array != null) ? array : new int[0]; + } + + /** + * Returns the original array, or an empty array if it is {@code null}. + * @param the class type + * @param array the specified array + * @param type the type of the array + * @return the original array, or an empty array if it is {@code null} + */ + public static T[] createEmptyArrayIfNull(final T[] array, final Class type) { + Objects.requireNonNull(type, "The type argument should not be null."); + + return (array != null) ? array : type.cast(Array.newInstance(type.getComponentType(), 0)); + } + + /** + * Returns the new stream created by {@code Stream.of(values)} or an empty + * sequential stream created by {@code Stream.empty()} if values is null. + * + * @param the type of stream elements + * @param values the elements of the new stream + * @return the new stream created by {@code Stream.of(values)} or an empty + * sequential stream created by {@code Stream.empty()} if values is null. + */ + @SafeVarargs + @SuppressWarnings("varargs") // Creating a stream from an array is safe + public static Stream streamOfIfNonNull(final T... values) { + return values == null ? Stream.empty() : Stream.of(values); + } + + /** + * Checks if a CharSequence is empty ("") or null. + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is empty or null + */ + public static boolean isEmpty(final CharSequence cs) { + return cs == null || cs.length() == 0; + } } diff --git a/src/java.xml/share/legal/bcel.md b/src/java.xml/share/legal/bcel.md index 2c673d6b1af..b64fc3640d4 100644 --- a/src/java.xml/share/legal/bcel.md +++ b/src/java.xml/share/legal/bcel.md @@ -1,4 +1,4 @@ -## Apache Commons Byte Code Engineering Library (BCEL) Version 6.7.0 +## Apache Commons Byte Code Engineering Library (BCEL) Version 6.10.0 ### Apache Commons BCEL Notice
diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/UsesTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/UsesTree.java
index 9b52eb29e1b..d14257de626 100644
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/UsesTree.java
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/UsesTree.java
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
index 8eab238f82a..3a8b4e5dbea 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
@@ -147,50 +147,27 @@ protected Lint(Lint other) {
 
     // Process command line options on demand to allow use of root Lint early during startup
     private void initializeRootIfNeeded() {
-
-        // Already initialized?
-        if (values != null)
-            return;
-
-        // Initialize enabled categories based on "-Xlint" flags
-        if (options.isSet(Option.XLINT) || options.isSet(Option.XLINT_CUSTOM, Option.LINT_CUSTOM_ALL)) {
-            // If -Xlint or -Xlint:all is given, enable all categories by default
-            values = EnumSet.allOf(LintCategory.class);
-        } else if (options.isSet(Option.XLINT_CUSTOM, Option.LINT_CUSTOM_NONE)) {
-            // if -Xlint:none is given, disable all categories by default
-            values = LintCategory.newEmptySet();
-        } else {
-            // otherwise, enable on-by-default categories
-            values = LintCategory.newEmptySet();
-
-            Source source = Source.instance(context);
-            if (source.compareTo(Source.JDK9) >= 0) {
-                values.add(LintCategory.DEP_ANN);
-            }
-            if (Source.Feature.REDUNDANT_STRICTFP.allowedInSource(source)) {
-                values.add(LintCategory.STRICTFP);
-            }
-            values.add(LintCategory.REQUIRES_TRANSITIVE_AUTOMATIC);
-            values.add(LintCategory.OPENS);
-            values.add(LintCategory.MODULE);
-            values.add(LintCategory.REMOVAL);
-            if (!options.isSet(Option.PREVIEW)) {
-                values.add(LintCategory.PREVIEW);
-            }
-            values.add(LintCategory.IDENTITY);
-            values.add(LintCategory.INCUBATING);
-        }
-
-        // Look for specific overrides
-        for (LintCategory lc : LintCategory.values()) {
-            if (options.isLintExplicitlyEnabled(lc)) {
-                values.add(lc);
-            } else if (options.isLintExplicitlyDisabled(lc)) {
-                values.remove(lc);
-            }
+        if (values == null) {
+            values = options.getLintCategoriesOf(Option.XLINT, this::getDefaults);
+            suppressedValues = LintCategory.newEmptySet();
         }
+    }
 
-        suppressedValues = LintCategory.newEmptySet();
+    // Obtain the set of on-by-default categories. Note that for a few categories,
+    // whether the category is on-by-default depends on other compiler options.
+    private EnumSet getDefaults() {
+        EnumSet defaults = LintCategory.newEmptySet();
+        Source source = Source.instance(context);
+        Stream.of(LintCategory.values())
+          .filter(lc ->
+            switch (lc) {
+                case DEP_ANN  -> source.compareTo(Source.JDK9) >= 0;
+                case STRICTFP -> Source.Feature.REDUNDANT_STRICTFP.allowedInSource(source);
+                case PREVIEW  -> !options.isSet(Option.PREVIEW);
+                default       -> lc.enabledByDefault;
+            })
+          .forEach(defaults::add);
+        return defaults;
     }
 
     @Override
@@ -221,7 +198,7 @@ public enum LintCategory {
          * 

* This category is not supported by {@code @SuppressWarnings}. */ - CLASSFILE("classfile", false), + CLASSFILE("classfile", false, false), /** * Warn about "dangling" documentation comments, @@ -238,7 +215,7 @@ public enum LintCategory { * Warn about items which are documented with an {@code @deprecated} JavaDoc * comment, but which do not have {@code @Deprecated} annotation. */ - DEP_ANN("dep-ann"), + DEP_ANN("dep-ann", true, true), /** * Warn about division by constant integer 0. @@ -268,7 +245,7 @@ public enum LintCategory { /** * Warn about uses of @ValueBased classes where an identity class is expected. */ - IDENTITY("identity", true, "synchronization"), + IDENTITY("identity", true, true, "synchronization"), /** * Warn about use of incubating modules. @@ -276,7 +253,7 @@ public enum LintCategory { *

* This category is not supported by {@code @SuppressWarnings}. */ - INCUBATING("incubating", false), + INCUBATING("incubating", false, true), /** * Warn about compiler possible lossy conversions. @@ -291,12 +268,12 @@ public enum LintCategory { /** * Warn about module system related issues. */ - MODULE("module"), + MODULE("module", true, true), /** * Warn about issues regarding module opens. */ - OPENS("opens"), + OPENS("opens", true, true), /** * Warn about issues relating to use of command line options. @@ -304,7 +281,7 @@ public enum LintCategory { *

* This category is not supported by {@code @SuppressWarnings}. */ - OPTIONS("options", false), + OPTIONS("options", false, false), /** * Warn when any output file is written to more than once. @@ -312,7 +289,7 @@ public enum LintCategory { *

* This category is not supported by {@code @SuppressWarnings}. */ - OUTPUT_FILE_CLASH("output-file-clash", false), + OUTPUT_FILE_CLASH("output-file-clash", false, false), /** * Warn about issues regarding method overloads. @@ -330,12 +307,15 @@ public enum LintCategory { *

* This category is not supported by {@code @SuppressWarnings}. */ - PATH("path", false), + PATH("path", false, false), /** * Warn about issues regarding annotation processing. + * + *

+ * This category is not supported by {@code @SuppressWarnings}. */ - PROCESSING("processing"), + PROCESSING("processing", false, false), /** * Warn about unchecked operations on raw types. @@ -345,7 +325,7 @@ public enum LintCategory { /** * Warn about use of deprecated-for-removal items. */ - REMOVAL("removal"), + REMOVAL("removal", true, true), /** * Warn about use of automatic modules in the requires clauses. @@ -355,7 +335,7 @@ public enum LintCategory { /** * Warn about automatic modules in requires transitive. */ - REQUIRES_TRANSITIVE_AUTOMATIC("requires-transitive-automatic"), + REQUIRES_TRANSITIVE_AUTOMATIC("requires-transitive-automatic", true, true), /** * Warn about Serializable classes that do not provide a serial version ID. @@ -370,7 +350,7 @@ public enum LintCategory { /** * Warn about unnecessary uses of the strictfp modifier */ - STRICTFP("strictfp"), + STRICTFP("strictfp", true, true), /** * Warn about issues relating to use of text blocks @@ -400,7 +380,7 @@ public enum LintCategory { /** * Warn about use of preview features. */ - PREVIEW("preview"), + PREVIEW("preview", true, true), /** * Warn about use of restricted methods. @@ -408,12 +388,13 @@ public enum LintCategory { RESTRICTED("restricted"); LintCategory(String option) { - this(option, true); + this(option, true, false); } - LintCategory(String option, boolean annotationSuppression, String... aliases) { + LintCategory(String option, boolean annotationSuppression, boolean enabledByDefault, String... aliases) { this.option = option; this.annotationSuppression = annotationSuppression; + this.enabledByDefault = enabledByDefault; ArrayList optionList = new ArrayList<>(1 + aliases.length); optionList.add(option); Collections.addAll(optionList, aliases); @@ -450,6 +431,12 @@ public static EnumSet newEmptySet() { /** Does this category support being suppressed by the {@code @SuppressWarnings} annotation? */ public final boolean annotationSuppression; + + /** + * Is this category included in the default set of enabled lint categories? + * Note that for some categories, command line options can alter this at runtime. + */ + public final boolean enabledByDefault; } /** diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java index b15ddae02e1..06caa70d478 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java @@ -25,18 +25,14 @@ package com.sun.tools.javac.code; -import java.util.ArrayList; -import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; -import java.util.stream.Stream; -import javax.tools.DiagnosticListener; import javax.tools.JavaFileObject; import com.sun.tools.javac.tree.EndPosTable; @@ -126,9 +122,10 @@ public boolean isKnown(JavaFileObject sourceFile) { */ public Optional lintAt(JavaFileObject sourceFile, DiagnosticPosition pos) { initializeIfNeeded(); - return Optional.of(sourceFile) - .map(fileInfoMap::get) - .flatMap(fileInfo -> fileInfo.lintAt(pos)); + FileInfo fileInfo = fileInfoMap.get(sourceFile); + if (fileInfo != null) + return fileInfo.lintAt(pos); + return Optional.empty(); } /** @@ -180,15 +177,15 @@ public void finishParsingFile(JCCompilationUnit tree) { private static class FileInfo { final LintRange rootRange; // the root LintRange (covering the entire source file) - final List unmappedDecls = new ArrayList<>(); // unmapped top-level declarations awaiting attribution + final List unmappedDecls = new LinkedList<>(); // unmapped top-level declarations awaiting attribution // After parsing: Add top-level declarations to our "unmappedDecls" list FileInfo(Lint rootLint, JCCompilationUnit tree) { rootRange = new LintRange(rootLint); - tree.defs.stream() - .filter(this::isTopLevelDecl) - .map(decl -> new Span(decl, tree.endPositions)) - .forEach(unmappedDecls::add); + for (JCTree decl : tree.defs) { + if (isTopLevelDecl(decl)) + unmappedDecls.add(new Span(decl, tree.endPositions)); + } } // After attribution: Discard the span from "unmappedDecls" and populate the declaration's subtree under "rootRange" @@ -205,8 +202,11 @@ void afterAttr(JCTree tree, EndPosTable endPositions) { // Find the most specific Lint configuration applying to the given position, unless the position has not been mapped yet Optional lintAt(DiagnosticPosition pos) { - boolean mapped = unmappedDecls.stream().noneMatch(span -> span.contains(pos)); - return mapped ? Optional.of(rootRange.bestMatch(pos).lint) : Optional.empty(); + for (Span span : unmappedDecls) { + if (span.contains(pos)) + return Optional.empty(); + } + return Optional.of(rootRange.bestMatch(pos).lint); } boolean isTopLevelDecl(JCTree tree) { @@ -252,21 +252,27 @@ private record LintRange( // Create a node representing the entire file, using the root lint configuration LintRange(Lint rootLint) { - this(Span.MAXIMAL, rootLint, new ArrayList<>()); + this(Span.MAXIMAL, rootLint, new LinkedList<>()); } // Create a node representing the given declaration and its corresponding Lint configuration LintRange(JCTree tree, EndPosTable endPositions, Lint lint) { - this(new Span(tree, endPositions), lint, new ArrayList<>()); + this(new Span(tree, endPositions), lint, new LinkedList<>()); } // Find the most specific node in this tree (including me) that contains the given position, if any LintRange bestMatch(DiagnosticPosition pos) { - return children.stream() - .map(child -> child.bestMatch(pos)) - .filter(Objects::nonNull) - .reduce((a, b) -> a.span.contains(b.span) ? b : a) - .orElseGet(() -> span.contains(pos) ? this : null); + LintRange bestMatch = null; + for (LintRange child : children) { + if (!child.span.contains(pos)) // don't recurse unless necessary + continue; + LintRange childBestMatch = child.bestMatch(pos); + if (childBestMatch != null && (bestMatch == null || bestMatch.span.contains(childBestMatch.span))) + bestMatch = childBestMatch; + } + if (bestMatch == null) + bestMatch = span.contains(pos) ? this : null; + return bestMatch; } // Populate a sparse subtree corresponding to the given nested declaration. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index ee11304dce9..2469dc9e031 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -31,6 +31,7 @@ import java.nio.file.ReadOnlyFileSystemException; import java.util.Collection; import java.util.Comparator; +import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -55,6 +56,7 @@ import com.sun.source.util.TaskEvent; import com.sun.tools.javac.api.MultiTaskListener; import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Source.Feature; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.CompletionFailure; @@ -440,7 +442,8 @@ public JavaCompiler(Context context) { context.get(DiagnosticListener.class) != null; devVerbose = options.isSet("dev"); processPcks = options.isSet("process.packages"); - werror = options.isSet(WERROR); + werrorAny = options.isSet(WERROR) || options.isSet(WERROR_CUSTOM, Option.LINT_CUSTOM_ALL); + werrorLint = options.getLintCategoriesOf(WERROR, LintCategory::newEmptySet); verboseCompilePolicy = options.isSet("verboseCompilePolicy"); @@ -513,9 +516,13 @@ public boolean exists() { */ protected boolean processPcks; - /** Switch: treat warnings as errors + /** Switch: treat any kind of warning (lint or non-lint) as an error. */ - protected boolean werror; + protected boolean werrorAny; + + /** Switch: treat lint warnings in the specified {@link LintCategory}s as errors. + */ + protected EnumSet werrorLint; /** Switch: is annotation processing requested explicitly via * CompilationTask.setProcessors? @@ -581,12 +588,20 @@ protected boolean shouldStop(CompileState cs) { */ public int errorCount() { log.reportOutstandingWarnings(); - if (werror && log.nerrors == 0 && log.nwarnings > 0) { + if (log.nerrors == 0 && log.nwarnings > 0 && + (werrorAny || werrorLint.clone().removeAll(log.lintWarnings))) { log.error(Errors.WarningsAndWerror); } return log.nerrors; } + /** + * Should warnings in the given lint category be treated as errors due to a {@code -Werror} flag? + */ + public boolean isWerror(LintCategory lc) { + return werrorAny || werrorLint.contains(lc); + } + protected final Queue stopIfError(CompileState cs, Queue queue) { return shouldStop(cs) ? new ListBuffer() : queue; } 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 f4122cebb64..c14767a7a8c 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 @@ -39,10 +39,12 @@ import java.util.EnumSet; import java.util.Iterator; import java.util.LinkedHashSet; +import java.util.List; import java.util.Locale; 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; @@ -484,24 +486,54 @@ public void process(OptionHelper helper, String option) throws InvalidValueExcep }, HELP_LINT("--help-lint", "opt.help.lint", EXTENDED, INFO) { - private final String LINT_KEY_FORMAT = SMALL_INDENT + SMALL_INDENT + "%-" + + private final String HELP_INDENT = SMALL_INDENT + SMALL_INDENT; + private final String LINT_KEY_FORMAT = HELP_INDENT + "%-" + (DEFAULT_SYNOPSIS_WIDTH - LARGE_INDENT.length()) + "s %s"; @Override public void process(OptionHelper helper, String option) throws InvalidValueException { Log log = helper.getLog(); + + // Print header log.printRawLines(WriterKind.STDOUT, log.localize(PrefixKind.JAVAC, "opt.help.lint.header")); + + // Print "all" option log.printRawLines(WriterKind.STDOUT, String.format(LINT_KEY_FORMAT, LINT_CUSTOM_ALL, log.localize(PrefixKind.JAVAC, "opt.Xlint.all"))); - LintCategory.options().forEach(ident -> log.printRawLines(WriterKind.STDOUT, - String.format(LINT_KEY_FORMAT, - ident, - log.localize(PrefixKind.JAVAC, "opt.Xlint.desc." + ident)))); + + // Alphabetize all the category names and their aliases together, and then list them with their descriptions + TreeMap keyMap = new TreeMap<>(); + Stream.of(LintCategory.values()).forEach(lc -> + lc.optionList.stream() + .forEach(key -> keyMap.put(key, + String.format(LINT_KEY_FORMAT, + key, + key.equals(lc.option) ? + log.localize(PrefixKind.JAVAC, "opt.Xlint.desc." + key) : + log.localize(PrefixKind.JAVAC, "opt.Xlint.alias.of", lc.option, key))))); + keyMap.values().forEach(desc -> log.printRawLines(WriterKind.STDOUT, desc)); + + // Print "none" option log.printRawLines(WriterKind.STDOUT, String.format(LINT_KEY_FORMAT, LINT_CUSTOM_NONE, log.localize(PrefixKind.JAVAC, "opt.Xlint.none"))); + + // Show which lint categories are enabled by default + log.printRawLines(WriterKind.STDOUT, log.localize(PrefixKind.JAVAC, "opt.help.lint.enabled.by.default")); + String defaults = Stream.of(LintCategory.values()) + .filter(lc -> lc.enabledByDefault) + .map(lc -> lc.option) + .sorted() + .collect(Collectors.joining(", ")); + log.printRawLines(WriterKind.STDOUT, + String.format("%s%s.", HELP_INDENT, defaults)); + + // Add trailing blurb about aliases + List aliasExample = LintCategory.IDENTITY.optionList; + log.printRawLines(WriterKind.STDOUT, + log.localize(PrefixKind.JAVAC, "opt.help.lint.footer", aliasExample.get(0), aliasExample.get(1))); super.process(helper, option); } }, @@ -531,6 +563,8 @@ public void process(OptionHelper helper, String option) throws InvalidValueExcep // treat warnings as errors WERROR("-Werror", "opt.Werror", STANDARD, BASIC), + WERROR_CUSTOM("-Werror:", "opt.arg.Werror", "opt.Werror.custom", STANDARD, BASIC, ANYOF, getXLintChoices()), + // prompt after each error // new Option("-prompt", "opt.prompt"), PROMPT("-prompt", null, HIDDEN, BASIC), @@ -1100,6 +1134,22 @@ public Option getCustom() { return Option.valueOf(name() + "_CUSTOM"); } + /** + * Like {@link #getCustom} but also requires that the custom option supports lint categories. + * + *

+ * In practice, that means {@code option} must be {@link Option#LINT} or {@link Option#WERROR}. + * + * @param option regular option + * @return corresponding lint custom option + * @throws IllegalArgumentException if no such option exists + */ + public Option getLintCustom() { + if (this == XLINT || this == WERROR) + return getCustom(); + throw new IllegalArgumentException(); + } + public boolean isInBasicOptionGroup() { return group == BASIC; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index b28f19bd3af..74d082d4b64 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -211,7 +211,7 @@ protected JavacProcessingEnvironment(Context context) { } fatalErrors = options.isSet("fatalEnterError"); showResolveErrors = options.isSet("showResolveErrors"); - werror = options.isSet(Option.WERROR); + werror = compiler.isWerror(PROCESSING); fileManager = context.get(JavaFileManager.class); platformAnnotations = initPlatformAnnotations(); 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 6c3238cfdfe..6d4276c794b 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 @@ -95,7 +95,13 @@ javac.opt.source=\ Provide source compatibility with the specified Java SE release.\n\ Supported releases: \n {0} javac.opt.Werror=\ - Terminate compilation if warnings occur + Terminate compilation if any warnings occur +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\ + Use --help-lint to see the supported keys. javac.opt.A=\ Options to pass to annotation processors javac.opt.implicit=\ @@ -168,18 +174,20 @@ javac.opt.Xbootclasspath.p=\ javac.opt.Xbootclasspath.a=\ Append to the bootstrap class path javac.opt.Xlint=\ - Enable recommended warning categories + Enable recommended lint warning categories. In this release, all\n\ + available lint warning categories are recommended. javac.opt.Xlint.all=\ - Enable all warning categories + Enable all lint warning categories javac.opt.Xlint.none=\ - Disable all warning categories + Disable all lint warning categories #L10N: do not localize: -Xlint javac.opt.arg.Xlint=\ (,)* javac.opt.Xlint.custom=\ - Warning categories to enable or disable, separated by comma.\n\ - Precede a key by ''-'' to disable the specified warning.\n\ - Use --help-lint to see the supported keys. + Lint warning categories to enable or disable, separated by comma.\n\ + Precede a key by ''-'' to disable the specified category. Use\n\ + ''--help-lint'' to show supported keys and which categories are\n\ + enabled by default. javac.opt.Xlint.desc.auxiliaryclass=\ Warn about an auxiliary class that is hidden in a source file, and is used from other files. @@ -291,16 +299,13 @@ javac.opt.Xlint.desc.preview=\ javac.opt.Xlint.desc.restricted=\ Warn about use of restricted methods. -# L10N: do not localize: identity synchronization -javac.opt.Xlint.desc.synchronization=\ - Warn about synchronization attempts on instances of value-based classes.\n\ -\ This key is a deprecated alias for ''identity'', which has the same uses and\n\ -\ effects. Users are encouraged to use the ''identity'' category for all future\n\ -\ and existing uses of ''synchronization''. - javac.opt.Xlint.desc.identity=\ Warn about uses of value-based classes where an identity class is expected. +javac.opt.Xlint.alias.of=\ + Deprecated alias for ''{0}'' with an identical effect. Users are encouraged to use\n\ +\ ''{0}'' instead of ''{1}'' for all current and future uses. + javac.opt.Xdoclint=\ Enable recommended checks for problems in javadoc comments # L10N: do not localize: all none @@ -331,9 +336,14 @@ javac.opt.X=\ javac.opt.help=\ Print this help message javac.opt.help.lint=\ - Print the supported keys for -Xlint + Print the supported keys for -Xlint and -Werror javac.opt.help.lint.header=\ The supported keys for -Xlint are: +javac.opt.help.lint.enabled.by.default=\ + The following lint warning categories are enabled by default: +javac.opt.help.lint.footer=\ + Categories and their aliases can be used interchangeably; for example, the flag\n\ + ''-Xlint:{0},{1}'' would be redundant. javac.opt.print=\ Print out a textual representation of specified types javac.opt.printRounds=\ @@ -346,8 +356,9 @@ javac.opt.userpathsfirst=\ javac.opt.prefer=\ Specify which file to read when both a source file and class file\n\ are found for an implicitly compiled class +# L10N: do not localize: ''preview'' javac.opt.preview=\ - Enable preview language features.\n\ + Enable preview language features. 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/classes/com/sun/tools/javac/util/Log.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java index 95458f339a1..a4109a35ccb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java @@ -142,6 +142,16 @@ public final void report(JCDiagnostic diag) { if (category != null) { // this is a lint warning; find the applicable Lint DiagnosticPosition pos = diag.getDiagnosticPosition(); if (pos != null && category.annotationSuppression) { // we should apply the Lint from the warning's position + + // Optimization: We don't need to go through the trouble of calculating the Lint instance at "pos" if + // (a) "category" is disabled at the root level, and (b) the diagnostic doesn't have the DEFAULT_ENABLED + // flag: @SuppressWarnings can only disable lint categories, so "category" is disabled in the entire file. + if (!rootLint().isEnabled(category) && + !diag.isFlagSet(DEFAULT_ENABLED) && + !diag.getCode().equals(RequiresTransitiveAutomatic.key())) // accommodate the "requires" hack below + return; + + // Wait for the Lint instance at "pos" to be calculated, then proceed if ((lint = lintFor(diag)) == null) { addLintWaiter(currentSourceFile(), diag); // ...but we don't know it yet, so defer return; @@ -171,7 +181,7 @@ public final void reportWithLint(JCDiagnostic diag, Lint lint) { lint.isEnabled(category) : // then emit if the category is enabled category.annotationSuppression ? // else emit if the category is not suppressed, where !lint.isSuppressed(category) : // ...suppression happens via @SuppressWarnings - !options.isLintDisabled(category); // ...suppression happens via -Xlint:-category + !options.isDisabled(Option.XLINT, category); // ...suppression happens via -Xlint:-category if (!emit) return; } @@ -553,10 +563,14 @@ protected int getDefaultMaxWarnings() { */ public int nerrors = 0; - /** The number of warnings encountered so far. + /** The total number of warnings encountered so far. */ public int nwarnings = 0; + /** Tracks whether any warnings have been encountered in each {@link LintCategory}. + */ + public final EnumSet lintWarnings = LintCategory.newEmptySet(); + /** The number of errors encountered after MaxErrors was reached. */ public int nsuppressederrors = 0; @@ -885,6 +899,7 @@ private WarningAggregator aggregatorFor(LintCategory lc) { public void clear() { recorded.clear(); sourceMap.clear(); + lintWarnings.clear(); nerrors = 0; nwarnings = 0; nsuppressederrors = 0; @@ -940,7 +955,6 @@ protected void reportReady(JCDiagnostic diagnostic) { // Strict warnings are always emitted if (diagnostic.isFlagSet(STRICT)) { writeDiagnostic(diagnostic); - nwarnings++; return; } @@ -948,7 +962,6 @@ protected void reportReady(JCDiagnostic diagnostic) { if (emitWarnings || diagnostic.isMandatory()) { if (nwarnings < MaxWarnings) { writeDiagnostic(diagnostic); - nwarnings++; } else { nsuppressedwarns++; } @@ -959,7 +972,6 @@ protected void reportReady(JCDiagnostic diagnostic) { if (diagnostic.isFlagSet(API) || shouldReport(diagnostic)) { if (nerrors < MaxErrors) { writeDiagnostic(diagnostic); - nerrors++; } else { nsuppressederrors++; } @@ -973,9 +985,25 @@ protected void reportReady(JCDiagnostic diagnostic) { } /** - * Write out a diagnostic. + * Write out a diagnostic and bump the warning and error counters as needed. */ protected void writeDiagnostic(JCDiagnostic diag) { + + // Increment counter(s) + switch (diag.getType()) { + case WARNING: + nwarnings++; + Optional.of(diag) + .map(JCDiagnostic::getLintCategory) + .ifPresent(lintWarnings::add); + break; + case ERROR: + nerrors++; + break; + default: + break; + } + if (diagListener != null) { diagListener.report(diag); return; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java index 32a31028b68..030e5b21758 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java @@ -173,66 +173,139 @@ public boolean isUnset(Option option, String value) { /** * Determine if a specific {@link LintCategory} is enabled via a custom - * option flag of the form {@code -Xlint}, {@code -Xlint:all}, or {@code -Xlint:key}. + * option flag of the form {@code -Flag}, {@code -Flag:all}, or {@code -Flag:key}. + * + *

+ * The given {@code option} must have a custom lint variant (available via {@link Option#getLintCustom}). * *

* Note: It's possible the category was also disabled; this method does not check that. * + * @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT}) * @param lc the {@link LintCategory} in question - * @return true if {@code lc} has been enabled + * @return true if {@code lc} is enabled via {@code option}'s lint custom variant (e.g., {@link Option#XLINT_CUSTOM}) + * @throws IllegalArgumentException if there is no lint custom variant of {@code option} */ - public boolean isLintEnabled(LintCategory lc) { - return isLintExplicitlyEnabled(lc) || - isSet(Option.XLINT_CUSTOM) || - isSet(Option.XLINT_CUSTOM, Option.LINT_CUSTOM_ALL); + public boolean isEnabled(Option option, LintCategory lc) { + Option custom = option.getLintCustom(); + return isExplicitlyEnabled(option, lc) || isSet(custom) || isSet(custom, Option.LINT_CUSTOM_ALL); } /** * Determine if a specific {@link LintCategory} is disabled via a custom - * option flag of the form {@code -Xlint:none} or {@code -Xlint:-key}. + * option flag of the form {@code -Flag:none} or {@code -Flag:-key}. + * + *

+ * The given {@code option} must have a custom lint variant (available via {@link Option#getLintCustom}). * *

* Note: It's possible the category was also enabled; this method does not check that. * + * @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT}) * @param lc the {@link LintCategory} in question - * @return true if {@code lc} has been disabled + * @return true if {@code lc} is disabled via {@code option}'s lint custom variant (e.g., {@link Option#XLINT_CUSTOM}) + * @throws IllegalArgumentException if there is no lint custom variant of {@code option} */ - public boolean isLintDisabled(LintCategory lc) { - return isLintExplicitlyDisabled(lc) || isSet(Option.XLINT_CUSTOM, Option.LINT_CUSTOM_NONE); + public boolean isDisabled(Option option, LintCategory lc) { + return isExplicitlyDisabled(option, lc) || isSet(option.getLintCustom(), Option.LINT_CUSTOM_NONE); } /** * Determine if a specific {@link LintCategory} is explicitly enabled via a custom - * option flag of the form {@code -Xlint:key}. + * option flag of the form {@code -Flag:key}. * *

- * Note: This does not check for option flags of the form {@code -Xlint} or {@code -Xlint:all}. + * The given {@code option} must have a custom lint variant (available via {@link Option#getLintCustom}). + * + *

+ * Note: This does not check for option flags of the form {@code -Flag} or {@code -Flag:all}. * *

* Note: It's possible the category was also disabled; this method does not check that. * + * @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT}) * @param lc the {@link LintCategory} in question - * @return true if {@code lc} has been explicitly enabled + * @return true if {@code lc} is explicitly enabled via {@code option}'s lint custom variant (e.g., {@link Option#XLINT_CUSTOM}) + * @throws IllegalArgumentException if there is no lint custom variant of {@code option} */ - public boolean isLintExplicitlyEnabled(LintCategory lc) { - return lc.optionList.stream().anyMatch(alias -> isSet(Option.XLINT_CUSTOM, alias)); + public boolean isExplicitlyEnabled(Option option, LintCategory lc) { + Option customOption = option.getLintCustom(); + return lc.optionList.stream().anyMatch(alias -> isSet(customOption, alias)); } /** * Determine if a specific {@link LintCategory} is explicitly disabled via a custom - * option flag of the form {@code -Xlint:-key}. + * option flag of the form {@code -Flag:-key}. + * + *

+ * The given {@code option} must have a custom lint variant (available via {@link Option#getLintCustom}). * *

- * Note: This does not check for an option flag of the form {@code -Xlint:none}. + * Note: This does not check for an option flag of the form {@code -Flag:none}. * *

* Note: It's possible the category was also enabled; this method does not check that. * + * @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT}) * @param lc the {@link LintCategory} in question - * @return true if {@code lc} has been explicitly disabled + * @return true if {@code lc} is explicitly disabled via {@code option}'s lint custom variant (e.g., {@link Option#XLINT_CUSTOM}) + * @throws IllegalArgumentException if there is no lint custom variant of {@code option} + */ + public boolean isExplicitlyDisabled(Option option, LintCategory lc) { + Option customOption = option.getLintCustom(); + return lc.optionList.stream().anyMatch(alias -> isSet(customOption, "-" + alias)); + } + + /** + * Collect the set of {@link LintCategory}s specified by option flag(s) of the form + * {@code -Flag} and/or {@code -Flag:[-]key,[-]key,...}. + * + *

+ * The given {@code option} must have a custom lint variant (available via {@link Option#getLintCustom}). + * + *

+ * The set of categories is calculated as follows. First, an initial set is created: + *

    + *
  • If {@code -Flag} or {@code -Flag:all} appears, the initial set contains all categories; otherwise, + *
  • If {@code -Flag:none} appears, the initial set is empty; otherwise, + *
  • The {@code defaults} parameter is invoked to construct an initial set. + *
+ * Next, for each lint category key {@code key}: + *
    + *
  • If {@code -Flag:key} flag appears, the corresponding category is added to the set; otherwise + *
  • If {@code -Flag:-key} flag appears, the corresponding category is removed to the set + *
+ * Unrecognized {@code key}s are ignored. + * + * @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT}) + * @param defaults populates the default set, or null for an empty default set + * @return the specified set of categories + * @throws IllegalArgumentException if there is no lint custom variant of {@code option} */ - public boolean isLintExplicitlyDisabled(LintCategory lc) { - return lc.optionList.stream().anyMatch(alias -> isSet(Option.XLINT_CUSTOM, "-" + alias)); + public EnumSet getLintCategoriesOf(Option option, Supplier> defaults) { + + // Create the initial set + EnumSet categories; + Option customOption = option.getLintCustom(); + if (isSet(option) || isSet(customOption, Option.LINT_CUSTOM_ALL)) { + categories = EnumSet.allOf(LintCategory.class); + } else if (isSet(customOption, Option.LINT_CUSTOM_NONE)) { + categories = EnumSet.noneOf(LintCategory.class); + } else { + categories = defaults.get(); + } + + // Apply specific overrides + for (LintCategory category : LintCategory.values()) { + if (isExplicitlyEnabled(option, category)) { + categories.add(category); + } else if (isExplicitlyDisabled(option, category)) { + categories.remove(category); + } + } + + // Done + return categories; } public void put(String name, String value) { diff --git a/src/jdk.compiler/share/classes/module-info.java b/src/jdk.compiler/share/classes/module-info.java index 33cff9379f2..46ada3a12e7 100644 --- a/src/jdk.compiler/share/classes/module-info.java +++ b/src/jdk.compiler/share/classes/module-info.java @@ -141,7 +141,8 @@ * * In addition, javac also supports other strings that can be used * to suppress other kinds of warnings. The following table lists all the - * strings that can be used with {@code @SuppressWarnings}. + * strings that are recognized by javac in {@code @SuppressWarnings} + * annotations. Unrecognized strings are ignored. * * * @@ -152,7 +153,6 @@ * *
Strings supported by {@code SuppressWarnings}
{@code auxiliaryclass} an auxiliary class that is hidden in a source file, and is used * from other files *
{@code cast} use of unnecessary casts - *
{@code classfile} issues related to classfile contents *
{@code dangling-doc-comments} issues related to "dangling" documentation comments, * not attached to a declaration *
{@code deprecation} use of deprecated items @@ -165,7 +165,6 @@ * the next *
{@code finally} {@code finally} clauses that do not terminate normally *
{@code identity} use of a value-based class where an identity class is expected - *
{@code incubating} use of incubating modules *
{@code lossy-conversions} possible lossy conversions in compound assignment *
{@code missing-explicit-ctor} missing explicit constructors in public and protected classes * in exported packages @@ -173,13 +172,12 @@ *
{@code opens} issues regarding module opens *
{@code overloads} issues regarding method overloads *
{@code overrides} issues regarding method overrides - *
{@code path} invalid path elements on the command line *
{@code preview} use of preview language features *
{@code rawtypes} use of raw types *
{@code removal} use of API that has been marked for removal - *
{@code restricted} use of restricted methods *
{@code requires-automatic} use of automatic modules in the {@code requires} clauses *
{@code requires-transitive-automatic} automatic modules in {@code requires transitive} + *
{@code restricted} use of restricted methods *
{@code serial} {@link java.base/java.io.Serializable Serializable} classes * that do not have a {@code serialVersionUID} field, or other * suspect declarations in {@code Serializable} and @@ -187,11 +185,9 @@ * and interfaces *
{@code static} accessing a static member using an instance *
{@code strictfp} unnecessary use of the {@code strictfp} modifier - *
{@code synchronization} synchronization attempts on instances of value-based classes; - * this key is a deprecated alias for {@code identity}, which has - * the same uses and effects. Users are encouraged to use the - * {@code identity} category for all future and existing uses of - * {@code synchronization} + *
{@code synchronization} deprecated alias for {@code identity} with an identical effect. + * Users are encouraged to use {@code identity} instead of + * {@code synchronization} for all current and future uses. *
{@code text-blocks} inconsistent white space characters in text block indentation *
{@code this-escape} superclass constructor leaking {@code this} before subclass initialized *
{@code try} issues relating to use of {@code try} blocks @@ -207,6 +203,25 @@ *
* + * All of the non-{@code docllint:} strings listed above may also be used with the {@code -Xlint} command line flag. + * The {@code -Xlint} flag also supports these strings not supported by {@code @SuppressWarnings}: + * + * + * + * + * + * + * + *
Strings supported by {@code -Xlint} but not {@code SuppressWarnings}
StringWarnings Related To ... + *
{@code classfile} issues related to classfile contents + *
{@code incubating} use of incubating modules + *
{@code options} issues relating to use of command line options + *
{@code output-file-clash} output files being overwritten due to filename clashes + *
{@code path} invalid path elements on the command line + *
{@code processing} issues regarding annotation processing + *
{@code restricted} use of restricted methods + *
+ * * @toolGuide javac * * @provides java.util.spi.ToolProvider diff --git a/src/jdk.compiler/share/data/symbols/include.list b/src/jdk.compiler/share/data/symbols/include.list index b99422a60e3..b2502f18fa4 100644 --- a/src/jdk.compiler/share/data/symbols/include.list +++ b/src/jdk.compiler/share/data/symbols/include.list @@ -267,6 +267,7 @@ +com/sun/management/ +com/sun/nio/sctp/ +jdk/ ++jdk/net/ # #Exported(true) in 8u40: # diff --git a/src/jdk.compiler/share/data/symbols/java.base-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-8.sym.txt index 051003c2799..3f0b74098ef 100644 --- a/src/jdk.compiler/share/data/symbols/java.base-8.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.base-8.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2020, 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 @@ -1711,6 +1711,7 @@ field name SHARADA descriptor Ljava/lang/Character$UnicodeBlock; flags 19 field name TAKRI descriptor Ljava/lang/Character$UnicodeBlock; flags 19 field name MIAO descriptor Ljava/lang/Character$UnicodeBlock; flags 19 field name ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E descriptor Ljava/lang/Character$UnicodeBlock; flags 19 method name of descriptor (C)Ljava/lang/Character$UnicodeBlock; flags 9 method name of descriptor (I)Ljava/lang/Character$UnicodeBlock; flags 9 method name forName descriptor (Ljava/lang/String;)Ljava/lang/Character$UnicodeBlock; flags 19 @@ -2078,7 +2079,7 @@ field name POSITIVE_INFINITY descriptor F constantValue Infinity flags 19 field name NEGATIVE_INFINITY descriptor F constantValue -Infinity flags 19 field name NaN descriptor F constantValue NaN flags 19 field name MAX_VALUE descriptor F constantValue 3.4028235E38 flags 19 -field name MIN_NORMAL descriptor F constantValue 1.17549435E-38 flags 19 +field name MIN_NORMAL descriptor F constantValue 1.1754944E-38 flags 19 field name MIN_VALUE descriptor F constantValue 1.4E-45 flags 19 field name MAX_EXPONENT descriptor I constantValue 127 flags 19 field name MIN_EXPONENT descriptor I constantValue -126 flags 19 @@ -3574,6 +3575,7 @@ method name get descriptor ()Ljava/lang/Object; flags 1 signature ()TT; method name clear descriptor ()V flags 1 method name isEnqueued descriptor ()Z flags 1 method name enqueue descriptor ()Z flags 1 +method name clone descriptor ()Ljava/lang/Object; thrownTypes java/lang/CloneNotSupportedException flags 4 class name java/lang/ref/ReferenceQueue header extends java/lang/Object flags 21 signature Ljava/lang/Object; classAnnotations @Ljdk/Profile+Annotation;(value=I1) diff --git a/src/jdk.compiler/share/data/symbols/java.base-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-9.sym.txt index 99a4f8e9f0e..7ea597bda46 100644 --- a/src/jdk.compiler/share/data/symbols/java.base-9.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.base-9.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2020, 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 @@ -165,10 +165,6 @@ header extends java/lang/Object implements java/io/Serializable,java/lang/Compar innerclass innerClass java/lang/Character$UnicodeScript outerClass java/lang/Character innerClassName UnicodeScript flags 4019 innerclass innerClass java/lang/Character$UnicodeBlock outerClass java/lang/Character innerClassName UnicodeBlock flags 19 innerclass innerClass java/lang/Character$Subset outerClass java/lang/Character innerClassName Subset flags 9 -field name DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE descriptor B constantValue 19 flags 19 -field name DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE descriptor B constantValue 20 flags 19 -field name DIRECTIONALITY_FIRST_STRONG_ISOLATE descriptor B constantValue 21 flags 19 -field name DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE descriptor B constantValue 22 flags 19 -method name descriptor (C)V -method name valueOf descriptor (C)Ljava/lang/Character; -method name charValue descriptor ()C @@ -176,6 +172,10 @@ field name DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE descriptor B constantValue 22 -method name isJavaLetterOrDigit descriptor (C)Z -method name isSpace descriptor (C)Z -method name reverseBytes descriptor (C)C +field name DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE descriptor B constantValue 19 flags 19 +field name DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE descriptor B constantValue 20 flags 19 +field name DIRECTIONALITY_FIRST_STRONG_ISOLATE descriptor B constantValue 21 flags 19 +field name DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE descriptor B constantValue 22 flags 19 method name descriptor (C)V flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") method name valueOf descriptor (C)Ljava/lang/Character; flags 9 runtimeAnnotations @Ljdk/internal/HotSpotIntrinsicCandidate; method name charValue descriptor ()C flags 1 runtimeAnnotations @Ljdk/internal/HotSpotIntrinsicCandidate; @@ -229,7 +229,6 @@ field name EARLY_DYNASTIC_CUNEIFORM descriptor Ljava/lang/Character$UnicodeBlock field name ANATOLIAN_HIEROGLYPHS descriptor Ljava/lang/Character$UnicodeBlock; flags 19 field name SUTTON_SIGNWRITING descriptor Ljava/lang/Character$UnicodeBlock; flags 19 field name SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS descriptor Ljava/lang/Character$UnicodeBlock; flags 19 -field name CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E descriptor Ljava/lang/Character$UnicodeBlock; flags 19 class name java/lang/Character$UnicodeScript field name CAUCASIAN_ALBANIAN descriptor Ljava/lang/Character$UnicodeScript; flags 4019 @@ -711,7 +710,6 @@ innerclass innerClass java/lang/module/ModuleDescriptor$Opens outerClass java/la innerclass innerClass java/lang/module/ModuleDescriptor$Exports outerClass java/lang/module/ModuleDescriptor innerClassName Exports flags 19 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -field name inCheck descriptor Z -field name inCheck descriptor Z flags 4 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="1.2") -method name getInCheck descriptor ()Z -method name getClassContext descriptor ()[Ljava/lang/Class; -method name currentClassLoader descriptor ()Ljava/lang/ClassLoader; @@ -725,6 +723,7 @@ field name inCheck descriptor Z flags 4 deprecated true runtimeAnnotations @Ljav -method name checkSystemClipboardAccess descriptor ()V -method name checkAwtEventQueueAccess descriptor ()V -method name checkMemberAccess descriptor (Ljava/lang/Class;I)V +field name inCheck descriptor Z flags 4 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="1.2") method name getInCheck descriptor ()Z flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="1.2") method name getClassContext descriptor ()[Ljava/lang/Class; flags 104 signature ()[Ljava/lang/Class<*>; method name currentClassLoader descriptor ()Ljava/lang/ClassLoader; flags 4 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="1.2") @@ -1404,6 +1403,7 @@ method name clean descriptor ()V flags 401 class name java/lang/ref/Reference -method name get descriptor ()Ljava/lang/Object; +-method name clone descriptor ()Ljava/lang/Object; method name get descriptor ()Ljava/lang/Object; flags 1 signature ()TT; runtimeAnnotations @Ljdk/internal/HotSpotIntrinsicCandidate; method name reachabilityFence descriptor (Ljava/lang/Object;)V flags 9 runtimeAnnotations @Ljdk/internal/vm/annotation/DontInline; @@ -1515,6 +1515,9 @@ class name java/math/BigDecimal -field name ROUND_HALF_DOWN descriptor I -field name ROUND_HALF_EVEN descriptor I -field name ROUND_UNNECESSARY descriptor I +-method name divide descriptor (Ljava/math/BigDecimal;II)Ljava/math/BigDecimal; +-method name divide descriptor (Ljava/math/BigDecimal;I)Ljava/math/BigDecimal; +-method name setScale descriptor (II)Ljava/math/BigDecimal; field name ROUND_UP descriptor I constantValue 0 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name ROUND_DOWN descriptor I constantValue 1 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name ROUND_CEILING descriptor I constantValue 2 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") @@ -1523,9 +1526,6 @@ field name ROUND_HALF_UP descriptor I constantValue 4 flags 19 deprecated true r field name ROUND_HALF_DOWN descriptor I constantValue 5 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name ROUND_HALF_EVEN descriptor I constantValue 6 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name ROUND_UNNECESSARY descriptor I constantValue 7 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") --method name divide descriptor (Ljava/math/BigDecimal;II)Ljava/math/BigDecimal; --method name divide descriptor (Ljava/math/BigDecimal;I)Ljava/math/BigDecimal; --method name setScale descriptor (II)Ljava/math/BigDecimal; method name divide descriptor (Ljava/math/BigDecimal;II)Ljava/math/BigDecimal; flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") method name divide descriptor (Ljava/math/BigDecimal;I)Ljava/math/BigDecimal; flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") method name sqrt descriptor (Ljava/math/MathContext;)Ljava/math/BigDecimal; flags 1 @@ -2189,8 +2189,8 @@ innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang class name java/time/LocalDate header extends java/lang/Object implements java/time/temporal/Temporal,java/time/temporal/TemporalAdjuster,java/time/chrono/ChronoLocalDate,java/io/Serializable flags 31 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -field name EPOCH descriptor Ljava/time/LocalDate; flags 19 -method name getEra descriptor ()Ljava/time/chrono/Era; +field name EPOCH descriptor Ljava/time/LocalDate; flags 19 method name ofInstant descriptor (Ljava/time/Instant;Ljava/time/ZoneId;)Ljava/time/LocalDate; flags 9 method name getEra descriptor ()Ljava/time/chrono/IsoEra; flags 1 method name datesUntil descriptor (Ljava/time/LocalDate;)Ljava/util/stream/Stream; flags 1 signature (Ljava/time/LocalDate;)Ljava/util/stream/Stream; diff --git a/src/jdk.compiler/share/data/symbols/java.desktop-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-8.sym.txt index 3daa15e5081..782c96da30c 100644 --- a/src/jdk.compiler/share/data/symbols/java.desktop-8.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.desktop-8.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2020, 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 @@ -666,7 +666,6 @@ innerclass innerClass java/awt/Component$BaselineResizeBehavior outerClass java/ innerclass innerClass java/awt/Component$FlipBufferStrategy outerClass java/awt/Component innerClassName FlipBufferStrategy flags 4 innerclass innerClass java/awt/Component$BltBufferStrategy outerClass java/awt/Component innerClassName BltBufferStrategy flags 4 innerclass innerClass java/awt/Component$AccessibleAWTComponent outerClass java/awt/Component innerClassName AccessibleAWTComponent flags 404 -innerclass innerClass sun/awt/CausedFocusEvent$Cause outerClass sun/awt/CausedFocusEvent innerClassName Cause flags 4019 field name TOP_ALIGNMENT descriptor F constantValue 0.0 flags 19 field name CENTER_ALIGNMENT descriptor F constantValue 0.5 flags 19 field name BOTTOM_ALIGNMENT descriptor F constantValue 1.0 flags 19 @@ -2116,7 +2115,6 @@ method name postProcessKeyEvent descriptor (Ljava/awt/event/KeyEvent;)Z flags 40 class name java/awt/KeyboardFocusManager header extends java/lang/Object implements java/awt/KeyEventDispatcher,java/awt/KeyEventPostProcessor flags 421 classAnnotations @Ljdk/Profile+Annotation;(value=I4) -innerclass innerClass sun/awt/CausedFocusEvent$Cause outerClass sun/awt/CausedFocusEvent innerClassName Cause flags 4019 field name FORWARD_TRAVERSAL_KEYS descriptor I constantValue 0 flags 19 field name BACKWARD_TRAVERSAL_KEYS descriptor I constantValue 1 flags 19 field name UP_CYCLE_TRAVERSAL_KEYS descriptor I constantValue 2 flags 19 @@ -7473,7 +7471,6 @@ method name select descriptor (I)V flags 401 class name java/awt/peer/ComponentPeer header extends java/lang/Object flags 601 classAnnotations @Ljdk/Profile+Annotation;(value=I4)@Lsun/Proprietary+Annotation; -innerclass innerClass sun/awt/CausedFocusEvent$Cause outerClass sun/awt/CausedFocusEvent innerClassName Cause flags 4019 innerclass innerClass java/awt/BufferCapabilities$FlipContents outerClass java/awt/BufferCapabilities innerClassName FlipContents flags 19 field name SET_LOCATION descriptor I constantValue 1 flags 19 field name SET_SIZE descriptor I constantValue 2 flags 19 @@ -15617,6 +15614,7 @@ method name descriptor (Ljavax/swing/JSpinner;)V flags 1 method name descriptor (Ljavax/swing/JSpinner;Ljava/lang/String;)V flags 1 method name getFormat descriptor ()Ljava/text/DecimalFormat; flags 1 method name getModel descriptor ()Ljavax/swing/SpinnerNumberModel; flags 1 +method name setComponentOrientation descriptor (Ljava/awt/ComponentOrientation;)V flags 1 class name javax/swing/JSplitPane header extends javax/swing/JComponent implements javax/accessibility/Accessible flags 21 classAnnotations @Ljdk/Profile+Annotation;(value=I4) diff --git a/src/jdk.compiler/share/data/symbols/java.desktop-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-9.sym.txt index cf0ab3466a8..039610548bb 100644 --- a/src/jdk.compiler/share/data/symbols/java.desktop-9.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.desktop-9.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2020, 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 @@ -789,6 +789,7 @@ innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang -field name BUTTON1_MASK descriptor I -field name BUTTON2_MASK descriptor I -field name BUTTON3_MASK descriptor I +-method name getModifiers descriptor ()I field name SHIFT_MASK descriptor I constantValue 1 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name CTRL_MASK descriptor I constantValue 2 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name META_MASK descriptor I constantValue 4 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") @@ -797,7 +798,6 @@ field name ALT_GRAPH_MASK descriptor I constantValue 32 flags 19 deprecated true field name BUTTON1_MASK descriptor I constantValue 16 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name BUTTON2_MASK descriptor I constantValue 8 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name BUTTON3_MASK descriptor I constantValue 4 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") --method name getModifiers descriptor ()I method name getModifiers descriptor ()I flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") class name java/awt/event/InputMethodEvent @@ -1354,10 +1354,10 @@ innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang class name java/beans/beancontext/BeanContextServiceAvailableEvent -field name serviceClass descriptor Ljava/lang/Class; -field name serviceClass descriptor Ljava/lang/Class; flags 4 signature Ljava/lang/Class<*>; -method name descriptor (Ljava/beans/beancontext/BeanContextServices;Ljava/lang/Class;)V -method name getServiceClass descriptor ()Ljava/lang/Class; -method name getCurrentServiceSelectors descriptor ()Ljava/util/Iterator; +field name serviceClass descriptor Ljava/lang/Class; flags 4 signature Ljava/lang/Class<*>; method name descriptor (Ljava/beans/beancontext/BeanContextServices;Ljava/lang/Class;)V flags 1 signature (Ljava/beans/beancontext/BeanContextServices;Ljava/lang/Class<*>;)V method name getServiceClass descriptor ()Ljava/lang/Class; flags 1 signature ()Ljava/lang/Class<*>; method name getCurrentServiceSelectors descriptor ()Ljava/util/Iterator; flags 1 signature ()Ljava/util/Iterator<*>; @@ -1370,10 +1370,10 @@ method name getCurrentServiceSelectors descriptor (Ljava/beans/beancontext/BeanC class name java/beans/beancontext/BeanContextServiceRevokedEvent -field name serviceClass descriptor Ljava/lang/Class; -field name serviceClass descriptor Ljava/lang/Class; flags 4 signature Ljava/lang/Class<*>; -method name descriptor (Ljava/beans/beancontext/BeanContextServices;Ljava/lang/Class;Z)V -method name getServiceClass descriptor ()Ljava/lang/Class; -method name isServiceClass descriptor (Ljava/lang/Class;)Z +field name serviceClass descriptor Ljava/lang/Class; flags 4 signature Ljava/lang/Class<*>; method name descriptor (Ljava/beans/beancontext/BeanContextServices;Ljava/lang/Class;Z)V flags 1 signature (Ljava/beans/beancontext/BeanContextServices;Ljava/lang/Class<*>;Z)V method name getServiceClass descriptor ()Ljava/lang/Class; flags 1 signature ()Ljava/lang/Class<*>; method name isServiceClass descriptor (Ljava/lang/Class;)Z flags 1 signature (Ljava/lang/Class<*>;)Z @@ -1402,8 +1402,6 @@ innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassNam innerclass innerClass java/beans/beancontext/BeanContextSupport$BCSIterator outerClass java/beans/beancontext/BeanContextSupport innerClassName BCSIterator flags 1c -field name services descriptor Ljava/util/HashMap; -field name bcsListeners descriptor Ljava/util/ArrayList; -field name services descriptor Ljava/util/HashMap; flags 84 signature Ljava/util/HashMap; -field name bcsListeners descriptor Ljava/util/ArrayList; flags 84 signature Ljava/util/ArrayList; -method name createBCSSServiceProvider descriptor (Ljava/lang/Class;Ljava/beans/beancontext/BeanContextServiceProvider;)Ljava/beans/beancontext/BeanContextServicesSupport$BCSSServiceProvider; -method name addService descriptor (Ljava/lang/Class;Ljava/beans/beancontext/BeanContextServiceProvider;)Z -method name addService descriptor (Ljava/lang/Class;Ljava/beans/beancontext/BeanContextServiceProvider;Z)Z @@ -1414,6 +1412,8 @@ field name bcsListeners descriptor Ljava/util/ArrayList; flags 84 signature Ljav -method name getCurrentServiceSelectors descriptor (Ljava/lang/Class;)Ljava/util/Iterator; -method name fireServiceAdded descriptor (Ljava/lang/Class;)V -method name fireServiceRevoked descriptor (Ljava/lang/Class;Z)V +field name services descriptor Ljava/util/HashMap; flags 84 signature Ljava/util/HashMap; +field name bcsListeners descriptor Ljava/util/ArrayList; flags 84 signature Ljava/util/ArrayList; method name createBCSSServiceProvider descriptor (Ljava/lang/Class;Ljava/beans/beancontext/BeanContextServiceProvider;)Ljava/beans/beancontext/BeanContextServicesSupport$BCSSServiceProvider; flags 4 signature (Ljava/lang/Class<*>;Ljava/beans/beancontext/BeanContextServiceProvider;)Ljava/beans/beancontext/BeanContextServicesSupport$BCSSServiceProvider; method name addService descriptor (Ljava/lang/Class;Ljava/beans/beancontext/BeanContextServiceProvider;)Z flags 1 signature (Ljava/lang/Class<*>;Ljava/beans/beancontext/BeanContextServiceProvider;)Z method name addService descriptor (Ljava/lang/Class;Ljava/beans/beancontext/BeanContextServiceProvider;Z)Z flags 4 signature (Ljava/lang/Class<*>;Ljava/beans/beancontext/BeanContextServiceProvider;Z)Z @@ -1448,12 +1448,12 @@ innerclass innerClass java/beans/beancontext/BeanContextSupport$BCSIterator oute innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 -field name children descriptor Ljava/util/HashMap; -field name bcmListeners descriptor Ljava/util/ArrayList; -field name children descriptor Ljava/util/HashMap; flags 84 signature Ljava/util/HashMap; -field name bcmListeners descriptor Ljava/util/ArrayList; flags 84 signature Ljava/util/ArrayList; -method name iterator descriptor ()Ljava/util/Iterator; -method name bcsChildren descriptor ()Ljava/util/Iterator; -method name serialize descriptor (Ljava/io/ObjectOutputStream;Ljava/util/Collection;)V -method name classEquals descriptor (Ljava/lang/Class;Ljava/lang/Class;)Z +field name children descriptor Ljava/util/HashMap; flags 84 signature Ljava/util/HashMap; +field name bcmListeners descriptor Ljava/util/ArrayList; flags 84 signature Ljava/util/ArrayList; method name iterator descriptor ()Ljava/util/Iterator; flags 1 signature ()Ljava/util/Iterator; method name bcsChildren descriptor ()Ljava/util/Iterator; flags 4 signature ()Ljava/util/Iterator; method name serialize descriptor (Ljava/io/ObjectOutputStream;Ljava/util/Collection;)V thrownTypes java/io/IOException flags 14 signature (Ljava/io/ObjectOutputStream;Ljava/util/Collection<*>;)V @@ -2028,10 +2028,10 @@ method name getTagNames descriptor ()Ljava/util/SortedSet; flags 1 signature ()L class name javax/imageio/spi/ImageReaderSpi -field name STANDARD_INPUT_TYPE descriptor [Ljava/lang/Class; -field name inputTypes descriptor [Ljava/lang/Class; -field name STANDARD_INPUT_TYPE descriptor [Ljava/lang/Class; flags 19 deprecated true signature [Ljava/lang/Class<*>; runtimeAnnotations @Ljava/lang/Deprecated; -field name inputTypes descriptor [Ljava/lang/Class; flags 4 signature [Ljava/lang/Class<*>; -method name descriptor (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Class;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V -method name getInputTypes descriptor ()[Ljava/lang/Class; +field name STANDARD_INPUT_TYPE descriptor [Ljava/lang/Class; flags 19 deprecated true signature [Ljava/lang/Class<*>; runtimeAnnotations @Ljava/lang/Deprecated; +field name inputTypes descriptor [Ljava/lang/Class; flags 4 signature [Ljava/lang/Class<*>; method name descriptor (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Class;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V flags 1 signature (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Class<*>;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V method name getInputTypes descriptor ()[Ljava/lang/Class; flags 1 signature ()[Ljava/lang/Class<*>; @@ -2042,10 +2042,10 @@ innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang class name javax/imageio/spi/ImageWriterSpi -field name STANDARD_OUTPUT_TYPE descriptor [Ljava/lang/Class; -field name outputTypes descriptor [Ljava/lang/Class; -field name STANDARD_OUTPUT_TYPE descriptor [Ljava/lang/Class; flags 19 deprecated true signature [Ljava/lang/Class<*>; runtimeAnnotations @Ljava/lang/Deprecated; -field name outputTypes descriptor [Ljava/lang/Class; flags 4 signature [Ljava/lang/Class<*>; -method name descriptor (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Class;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V -method name getOutputTypes descriptor ()[Ljava/lang/Class; +field name STANDARD_OUTPUT_TYPE descriptor [Ljava/lang/Class; flags 19 deprecated true signature [Ljava/lang/Class<*>; runtimeAnnotations @Ljava/lang/Deprecated; +field name outputTypes descriptor [Ljava/lang/Class; flags 4 signature [Ljava/lang/Class<*>; method name descriptor (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Class;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V flags 1 signature (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Class<*>;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V method name getOutputTypes descriptor ()[Ljava/lang/Class; flags 1 signature ()[Ljava/lang/Class<*>; @@ -3485,7 +3485,6 @@ innerclass innerClass javax/swing/JSpinner$NumberEditor outerClass javax/swing/J innerclass innerClass javax/swing/JSpinner$DefaultEditor outerClass javax/swing/JSpinner innerClassName DefaultEditor flags 9 innerclass innerClass javax/swing/JFormattedTextField$AbstractFormatter outerClass javax/swing/JFormattedTextField innerClassName AbstractFormatter flags 409 innerclass innerClass javax/swing/JFormattedTextField$AbstractFormatterFactory outerClass javax/swing/JFormattedTextField innerClassName AbstractFormatterFactory flags 409 -method name setComponentOrientation descriptor (Ljava/awt/ComponentOrientation;)V flags 1 class name javax/swing/JSplitPane header extends javax/swing/JComponent implements javax/accessibility/Accessible flags 21 runtimeAnnotations @Ljava/beans/JavaBean;(defaultProperty="UI") @@ -3592,8 +3591,6 @@ innerclass innerClass javax/swing/UIDefaults$LazyValue outerClass javax/swing/UI innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -field name defaultRenderersByColumnClass descriptor Ljava/util/Hashtable; -field name defaultEditorsByColumnClass descriptor Ljava/util/Hashtable; -field name defaultRenderersByColumnClass descriptor Ljava/util/Hashtable; flags 84 signature Ljava/util/Hashtable; -field name defaultEditorsByColumnClass descriptor Ljava/util/Hashtable; flags 84 signature Ljava/util/Hashtable; -method name descriptor (Ljava/util/Vector;Ljava/util/Vector;)V -method name setTableHeader descriptor (Ljavax/swing/table/JTableHeader;)V -method name setRowHeight descriptor (I)V @@ -3638,6 +3635,8 @@ field name defaultEditorsByColumnClass descriptor Ljava/util/Hashtable; flags 84 -method name setFillsViewportHeight descriptor (Z)V -method name setCellEditor descriptor (Ljavax/swing/table/TableCellEditor;)V -method name getAccessibleContext descriptor ()Ljavax/accessibility/AccessibleContext; +field name defaultRenderersByColumnClass descriptor Ljava/util/Hashtable; flags 84 signature Ljava/util/Hashtable; +field name defaultEditorsByColumnClass descriptor Ljava/util/Hashtable; flags 84 signature Ljava/util/Hashtable; method name descriptor (Ljava/util/Vector;Ljava/util/Vector;)V flags 1 signature (Ljava/util/Vector<+Ljava/util/Vector;>;Ljava/util/Vector<*>;)V method name setTableHeader descriptor (Ljavax/swing/table/JTableHeader;)V flags 1 runtimeAnnotations @Ljava/beans/BeanProperty;(description="The\u005C;u0020;JTableHeader\u005C;u0020;instance\u005C;u0020;which\u005C;u0020;renders\u005C;u0020;the\u005C;u0020;column\u005C;u0020;headers.") method name setRowHeight descriptor (I)V flags 1 runtimeAnnotations @Ljava/beans/BeanProperty;(description="The\u005C;u0020;height\u005C;u0020;of\u005C;u0020;the\u005C;u0020;specified\u005C;u0020;row.") @@ -4230,12 +4229,12 @@ innerclass innerClass javax/swing/plaf/basic/BasicComboBoxRenderer$UIResource ou innerclass innerClass javax/swing/plaf/basic/BasicComboBoxEditor$UIResource outerClass javax/swing/plaf/basic/BasicComboBoxEditor innerClassName UIResource flags 9 -field name comboBox descriptor Ljavax/swing/JComboBox; -field name listBox descriptor Ljavax/swing/JList; -field name comboBox descriptor Ljavax/swing/JComboBox; flags 4 signature Ljavax/swing/JComboBox; -field name listBox descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; -method name createRenderer descriptor ()Ljavax/swing/ListCellRenderer; -method name isPopupVisible descriptor (Ljavax/swing/JComboBox;)Z -method name setPopupVisible descriptor (Ljavax/swing/JComboBox;Z)V -method name isFocusTraversable descriptor (Ljavax/swing/JComboBox;)Z +field name comboBox descriptor Ljavax/swing/JComboBox; flags 4 signature Ljavax/swing/JComboBox; +field name listBox descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; method name createRenderer descriptor ()Ljavax/swing/ListCellRenderer; flags 4 signature ()Ljavax/swing/ListCellRenderer; method name isPopupVisible descriptor (Ljavax/swing/JComboBox;)Z flags 1 signature (Ljavax/swing/JComboBox<*>;)Z method name setPopupVisible descriptor (Ljavax/swing/JComboBox;Z)V flags 1 signature (Ljavax/swing/JComboBox<*>;Z)V @@ -4254,13 +4253,13 @@ innerclass innerClass javax/swing/plaf/basic/BasicComboPopup$InvocationMouseMoti innerclass innerClass javax/swing/plaf/basic/BasicComboPopup$InvocationMouseHandler outerClass javax/swing/plaf/basic/BasicComboPopup innerClassName InvocationMouseHandler flags 4 -field name comboBox descriptor Ljavax/swing/JComboBox; -field name list descriptor Ljavax/swing/JList; -field name comboBox descriptor Ljavax/swing/JComboBox; flags 4 signature Ljavax/swing/JComboBox; -field name list descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; -method name getList descriptor ()Ljavax/swing/JList; -method name uninstallComboBoxModelListeners descriptor (Ljavax/swing/ComboBoxModel;)V -method name descriptor (Ljavax/swing/JComboBox;)V -method name createList descriptor ()Ljavax/swing/JList; -method name installComboBoxModelListeners descriptor (Ljavax/swing/ComboBoxModel;)V +field name comboBox descriptor Ljavax/swing/JComboBox; flags 4 signature Ljavax/swing/JComboBox; +field name list descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; method name getList descriptor ()Ljavax/swing/JList; flags 1 signature ()Ljavax/swing/JList; method name uninstallComboBoxModelListeners descriptor (Ljavax/swing/ComboBoxModel;)V flags 4 signature (Ljavax/swing/ComboBoxModel<*>;)V method name descriptor (Ljavax/swing/JComboBox;)V flags 1 signature (Ljavax/swing/JComboBox;)V @@ -4357,11 +4356,11 @@ innerclass innerClass javax/swing/plaf/basic/BasicListUI$MouseInputHandler outer innerclass innerClass javax/swing/JList$DropLocation outerClass javax/swing/JList innerClassName DropLocation flags 19 innerclass innerClass java/awt/Component$BaselineResizeBehavior outerClass java/awt/Component innerClassName BaselineResizeBehavior flags 4019 -field name list descriptor Ljavax/swing/JList; -field name list descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; -method name paintCell descriptor (Ljava/awt/Graphics;ILjava/awt/Rectangle;Ljavax/swing/ListCellRenderer;Ljavax/swing/ListModel;Ljavax/swing/ListSelectionModel;I)V -method name locationToIndex descriptor (Ljavax/swing/JList;Ljava/awt/Point;)I -method name indexToLocation descriptor (Ljavax/swing/JList;I)Ljava/awt/Point; -method name getCellBounds descriptor (Ljavax/swing/JList;II)Ljava/awt/Rectangle; +field name list descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; method name paintCell descriptor (Ljava/awt/Graphics;ILjava/awt/Rectangle;Ljavax/swing/ListCellRenderer;Ljavax/swing/ListModel;Ljavax/swing/ListSelectionModel;I)V flags 4 signature (Ljava/awt/Graphics;ILjava/awt/Rectangle;Ljavax/swing/ListCellRenderer;Ljavax/swing/ListModel;Ljavax/swing/ListSelectionModel;I)V method name locationToIndex descriptor (Ljavax/swing/JList;Ljava/awt/Point;)I flags 1 signature (Ljavax/swing/JList<*>;Ljava/awt/Point;)I method name indexToLocation descriptor (Ljavax/swing/JList;I)Ljava/awt/Point; flags 1 signature (Ljavax/swing/JList<*>;I)Ljava/awt/Point; @@ -4615,12 +4614,12 @@ innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang class name javax/swing/plaf/metal/MetalComboBoxButton -field name comboBox descriptor Ljavax/swing/JComboBox; -field name listBox descriptor Ljavax/swing/JList; -field name comboBox descriptor Ljavax/swing/JComboBox; flags 4 signature Ljavax/swing/JComboBox; -field name listBox descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; -method name getComboBox descriptor ()Ljavax/swing/JComboBox; -method name setComboBox descriptor (Ljavax/swing/JComboBox;)V -method name descriptor (Ljavax/swing/JComboBox;Ljavax/swing/Icon;Ljavax/swing/CellRendererPane;Ljavax/swing/JList;)V -method name descriptor (Ljavax/swing/JComboBox;Ljavax/swing/Icon;ZLjavax/swing/CellRendererPane;Ljavax/swing/JList;)V +field name comboBox descriptor Ljavax/swing/JComboBox; flags 4 signature Ljavax/swing/JComboBox; +field name listBox descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; method name getComboBox descriptor ()Ljavax/swing/JComboBox; flags 11 signature ()Ljavax/swing/JComboBox; method name setComboBox descriptor (Ljavax/swing/JComboBox;)V flags 11 signature (Ljavax/swing/JComboBox;)V method name descriptor (Ljavax/swing/JComboBox;Ljavax/swing/Icon;Ljavax/swing/CellRendererPane;Ljavax/swing/JList;)V flags 1 signature (Ljavax/swing/JComboBox;Ljavax/swing/Icon;Ljavax/swing/CellRendererPane;Ljavax/swing/JList;)V @@ -4740,10 +4739,10 @@ field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector class name javax/swing/plaf/multi/MultiComboBoxUI -field name uis descriptor Ljava/util/Vector; -field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; -method name isFocusTraversable descriptor (Ljavax/swing/JComboBox;)Z -method name setPopupVisible descriptor (Ljavax/swing/JComboBox;Z)V -method name isPopupVisible descriptor (Ljavax/swing/JComboBox;)Z +field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; method name isFocusTraversable descriptor (Ljavax/swing/JComboBox;)Z flags 1 signature (Ljavax/swing/JComboBox<*>;)Z method name setPopupVisible descriptor (Ljavax/swing/JComboBox;Z)V flags 1 signature (Ljavax/swing/JComboBox<*>;Z)V method name isPopupVisible descriptor (Ljavax/swing/JComboBox;)Z flags 1 signature (Ljavax/swing/JComboBox<*>;)Z @@ -4770,10 +4769,10 @@ field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector class name javax/swing/plaf/multi/MultiListUI -field name uis descriptor Ljava/util/Vector; -field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; -method name locationToIndex descriptor (Ljavax/swing/JList;Ljava/awt/Point;)I -method name indexToLocation descriptor (Ljavax/swing/JList;I)Ljava/awt/Point; -method name getCellBounds descriptor (Ljavax/swing/JList;II)Ljava/awt/Rectangle; +field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; method name locationToIndex descriptor (Ljavax/swing/JList;Ljava/awt/Point;)I flags 1 signature (Ljavax/swing/JList<*>;Ljava/awt/Point;)I method name indexToLocation descriptor (Ljavax/swing/JList;I)Ljava/awt/Point; flags 1 signature (Ljavax/swing/JList<*>;I)Ljava/awt/Point; method name getCellBounds descriptor (Ljavax/swing/JList;II)Ljava/awt/Rectangle; flags 1 signature (Ljavax/swing/JList<*>;II)Ljava/awt/Rectangle; @@ -4852,11 +4851,11 @@ field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector class name javax/swing/plaf/multi/MultiTextUI -field name uis descriptor Ljava/util/Vector; -field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; -method name modelToView descriptor (Ljavax/swing/text/JTextComponent;I)Ljava/awt/Rectangle; -method name modelToView descriptor (Ljavax/swing/text/JTextComponent;ILjavax/swing/text/Position$Bias;)Ljava/awt/Rectangle; -method name viewToModel descriptor (Ljavax/swing/text/JTextComponent;Ljava/awt/Point;)I -method name viewToModel descriptor (Ljavax/swing/text/JTextComponent;Ljava/awt/Point;[Ljavax/swing/text/Position$Bias;)I +field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; method name modelToView descriptor (Ljavax/swing/text/JTextComponent;I)Ljava/awt/Rectangle; thrownTypes javax/swing/text/BadLocationException flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") method name modelToView descriptor (Ljavax/swing/text/JTextComponent;ILjavax/swing/text/Position$Bias;)Ljava/awt/Rectangle; thrownTypes javax/swing/text/BadLocationException flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") method name modelToView2D descriptor (Ljavax/swing/text/JTextComponent;ILjavax/swing/text/Position$Bias;)Ljava/awt/geom/Rectangle2D; thrownTypes javax/swing/text/BadLocationException flags 1 @@ -4982,7 +4981,6 @@ innerclass innerClass javax/swing/JTable$DropLocation outerClass javax/swing/JTa class name javax/swing/table/DefaultTableModel -field name dataVector descriptor Ljava/util/Vector; -field name dataVector descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; -method name descriptor (Ljava/util/Vector;I)V -method name descriptor (Ljava/util/Vector;Ljava/util/Vector;)V -method name getDataVector descriptor ()Ljava/util/Vector; @@ -4993,6 +4991,7 @@ field name dataVector descriptor Ljava/util/Vector; flags 4 signature Ljava/util -method name addColumn descriptor (Ljava/lang/Object;Ljava/util/Vector;)V -method name convertToVector descriptor ([Ljava/lang/Object;)Ljava/util/Vector; -method name convertToVector descriptor ([[Ljava/lang/Object;)Ljava/util/Vector; +field name dataVector descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; method name descriptor (Ljava/util/Vector;I)V flags 1 signature (Ljava/util/Vector<*>;I)V method name descriptor (Ljava/util/Vector;Ljava/util/Vector;)V flags 1 signature (Ljava/util/Vector<+Ljava/util/Vector;>;Ljava/util/Vector<*>;)V method name getDataVector descriptor ()Ljava/util/Vector; flags 1 signature ()Ljava/util/Vector; @@ -5832,13 +5831,13 @@ class name javax/swing/tree/DefaultMutableTreeNode header extends java/lang/Object implements java/lang/Cloneable,javax/swing/tree/MutableTreeNode,java/io/Serializable flags 21 innerclass innerClass java/io/ObjectInputStream$GetField outerClass java/io/ObjectInputStream innerClassName GetField flags 409 -field name children descriptor Ljava/util/Vector; -field name children descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; -method name children descriptor ()Ljava/util/Enumeration; -method name preorderEnumeration descriptor ()Ljava/util/Enumeration; -method name postorderEnumeration descriptor ()Ljava/util/Enumeration; -method name breadthFirstEnumeration descriptor ()Ljava/util/Enumeration; -method name depthFirstEnumeration descriptor ()Ljava/util/Enumeration; -method name pathFromAncestorEnumeration descriptor (Ljavax/swing/tree/TreeNode;)Ljava/util/Enumeration; +field name children descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; method name children descriptor ()Ljava/util/Enumeration; flags 1 signature ()Ljava/util/Enumeration; method name preorderEnumeration descriptor ()Ljava/util/Enumeration; flags 1 signature ()Ljava/util/Enumeration; method name postorderEnumeration descriptor ()Ljava/util/Enumeration; flags 1 signature ()Ljava/util/Enumeration; diff --git a/src/jdk.compiler/share/data/symbols/java.xml.bind-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.bind-9.sym.txt index f6c007544d9..f6a8ebd2f2c 100644 --- a/src/jdk.compiler/share/data/symbols/java.xml.bind-9.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.xml.bind-9.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2017, 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 @@ -35,10 +35,10 @@ innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang class name javax/xml/bind/JAXBContext -field name JAXB_CONTEXT_FACTORY descriptor Ljava/lang/String; -field name JAXB_CONTEXT_FACTORY descriptor Ljava/lang/String; constantValue javax.xml.bind.JAXBContextFactory flags 19 -method name newInstance descriptor ([Ljava/lang/Class;)Ljavax/xml/bind/JAXBContext; -method name newInstance descriptor ([Ljava/lang/Class;Ljava/util/Map;)Ljavax/xml/bind/JAXBContext; -method name createValidator descriptor ()Ljavax/xml/bind/Validator; +field name JAXB_CONTEXT_FACTORY descriptor Ljava/lang/String; constantValue javax.xml.bind.JAXBContextFactory flags 19 method name newInstance descriptor ([Ljava/lang/Class;)Ljavax/xml/bind/JAXBContext; thrownTypes javax/xml/bind/JAXBException flags 89 signature ([Ljava/lang/Class<*>;)Ljavax/xml/bind/JAXBContext; method name newInstance descriptor ([Ljava/lang/Class;Ljava/util/Map;)Ljavax/xml/bind/JAXBContext; thrownTypes javax/xml/bind/JAXBException flags 9 signature ([Ljava/lang/Class<*>;Ljava/util/Map;)Ljavax/xml/bind/JAXBContext; method name createValidator descriptor ()Ljavax/xml/bind/Validator; thrownTypes javax/xml/bind/JAXBException flags 401 deprecated true runtimeAnnotations @Ljava/lang/Deprecated; diff --git a/src/jdk.compiler/share/data/symbols/jdk.management-8.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-8.sym.txt index ac0bdef06ac..15811f99cb7 100644 --- a/src/jdk.compiler/share/data/symbols/jdk.management-8.sym.txt +++ b/src/jdk.compiler/share/data/symbols/jdk.management-8.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2017, 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 @@ -91,6 +91,10 @@ method name getThreadAllocatedBytes descriptor ([J)[J flags 401 method name isThreadAllocatedMemorySupported descriptor ()Z flags 401 method name isThreadAllocatedMemoryEnabled descriptor ()Z flags 401 method name setThreadAllocatedMemoryEnabled descriptor (Z)V flags 401 +method name getCurrentThreadAllocatedBytes descriptor ()J flags 1 +method name getTotalThreadAllocatedBytes descriptor ()J flags 1 +method name getThreadInfo descriptor ([JZZI)[Ljava/lang/management/ThreadInfo; flags 1 +method name dumpAllThreads descriptor (ZZI)[Ljava/lang/management/ThreadInfo; flags 1 class name com/sun/management/UnixOperatingSystemMXBean header extends java/lang/Object implements com/sun/management/OperatingSystemMXBean flags 601 classAnnotations @Ljdk/Profile+Annotation;(value=I3) runtimeAnnotations @Ljdk/Exported; diff --git a/src/jdk.compiler/share/data/symbols/jdk.management-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-9.sym.txt index 6df3114e44a..8ef9e4bb504 100644 --- a/src/jdk.compiler/share/data/symbols/jdk.management-9.sym.txt +++ b/src/jdk.compiler/share/data/symbols/jdk.management-9.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2017, 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 @@ -48,6 +48,10 @@ header extends java/lang/Object implements java/lang/management/OperatingSystemM class name com/sun/management/ThreadMXBean header extends java/lang/Object implements java/lang/management/ThreadMXBean flags 601 +-method name getCurrentThreadAllocatedBytes descriptor ()J +-method name getTotalThreadAllocatedBytes descriptor ()J +-method name getThreadInfo descriptor ([JZZI)[Ljava/lang/management/ThreadInfo; +-method name dumpAllThreads descriptor (ZZI)[Ljava/lang/management/ThreadInfo; class name com/sun/management/UnixOperatingSystemMXBean header extends java/lang/Object implements com/sun/management/OperatingSystemMXBean flags 601 diff --git a/src/jdk.compiler/share/data/symbols/jdk.net-8.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.net-8.sym.txt new file mode 100644 index 00000000000..a579e8f59ec --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.net-8.sym.txt @@ -0,0 +1,76 @@ +# +# 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/net/ExtendedSocketOptions +header extends java/lang/Object flags 31 classAnnotations @Ljdk/Profile+Annotation;(value=I1) runtimeAnnotations @Ljdk/Exported; +field name SO_FLOW_SLA descriptor Ljava/net/SocketOption; flags 19 signature Ljava/net/SocketOption; +field name TCP_KEEPIDLE descriptor Ljava/net/SocketOption; flags 19 signature Ljava/net/SocketOption; +field name TCP_KEEPINTERVAL descriptor Ljava/net/SocketOption; flags 19 signature Ljava/net/SocketOption; +field name TCP_KEEPCOUNT descriptor Ljava/net/SocketOption; flags 19 signature Ljava/net/SocketOption; + +class name jdk/net/NetworkPermission +header extends java/security/BasicPermission flags 31 classAnnotations @Ljdk/Profile+Annotation;(value=I1) runtimeAnnotations @Ljdk/Exported; +method name descriptor (Ljava/lang/String;)V flags 1 +method name descriptor (Ljava/lang/String;Ljava/lang/String;)V flags 1 + +class name jdk/net/SocketFlow +header extends java/lang/Object flags 21 classAnnotations @Ljdk/Profile+Annotation;(value=I1) runtimeAnnotations @Ljdk/Exported; +innerclass innerClass jdk/net/SocketFlow$Status outerClass jdk/net/SocketFlow innerClassName Status flags 4019 +field name NORMAL_PRIORITY descriptor I constantValue 1 flags 19 +field name HIGH_PRIORITY descriptor I constantValue 2 flags 19 +method name create descriptor ()Ljdk/net/SocketFlow; flags 9 +method name priority descriptor (I)Ljdk/net/SocketFlow; flags 1 +method name bandwidth descriptor (J)Ljdk/net/SocketFlow; flags 1 +method name priority descriptor ()I flags 1 +method name bandwidth descriptor ()J flags 1 +method name status descriptor ()Ljdk/net/SocketFlow$Status; flags 1 + +class name jdk/net/SocketFlow$Status +header extends java/lang/Enum flags 4031 signature Ljava/lang/Enum; runtimeAnnotations @Ljdk/Exported; +innerclass innerClass jdk/net/SocketFlow$Status outerClass jdk/net/SocketFlow innerClassName Status flags 4019 +field name NO_STATUS descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name OK descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name NO_PERMISSION descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name NOT_CONNECTED descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name NOT_SUPPORTED descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name ALREADY_CREATED descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name IN_PROGRESS descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name OTHER descriptor Ljdk/net/SocketFlow$Status; flags 4019 +method name values descriptor ()[Ljdk/net/SocketFlow$Status; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljdk/net/SocketFlow$Status; flags 9 + +class name jdk/net/Sockets +header extends java/lang/Object flags 21 classAnnotations @Ljdk/Profile+Annotation;(value=I1) runtimeAnnotations @Ljdk/Exported; +method name setOption descriptor (Ljava/net/Socket;Ljava/net/SocketOption;Ljava/lang/Object;)V thrownTypes java/io/IOException flags 9 signature (Ljava/net/Socket;Ljava/net/SocketOption;TT;)V +method name getOption descriptor (Ljava/net/Socket;Ljava/net/SocketOption;)Ljava/lang/Object; thrownTypes java/io/IOException flags 9 signature (Ljava/net/Socket;Ljava/net/SocketOption;)TT; +method name setOption descriptor (Ljava/net/ServerSocket;Ljava/net/SocketOption;Ljava/lang/Object;)V thrownTypes java/io/IOException flags 9 signature (Ljava/net/ServerSocket;Ljava/net/SocketOption;TT;)V +method name getOption descriptor (Ljava/net/ServerSocket;Ljava/net/SocketOption;)Ljava/lang/Object; thrownTypes java/io/IOException flags 9 signature (Ljava/net/ServerSocket;Ljava/net/SocketOption;)TT; +method name setOption descriptor (Ljava/net/DatagramSocket;Ljava/net/SocketOption;Ljava/lang/Object;)V thrownTypes java/io/IOException flags 9 signature (Ljava/net/DatagramSocket;Ljava/net/SocketOption;TT;)V +method name getOption descriptor (Ljava/net/DatagramSocket;Ljava/net/SocketOption;)Ljava/lang/Object; thrownTypes java/io/IOException flags 9 signature (Ljava/net/DatagramSocket;Ljava/net/SocketOption;)TT; +method name supportedOptions descriptor (Ljava/lang/Class;)Ljava/util/Set; flags 9 signature (Ljava/lang/Class<*>;)Ljava/util/Set;>; + diff --git a/src/jdk.compiler/share/data/symbols/jdk.net-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.net-9.sym.txt index d52c33c546a..7db67409789 100644 --- a/src/jdk.compiler/share/data/symbols/jdk.net-9.sym.txt +++ b/src/jdk.compiler/share/data/symbols/jdk.net-9.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2017, 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 @@ -32,51 +32,26 @@ header exports jdk/net requires name\u0020;java.base\u0020;flags\u0020;8000 flag class name jdk/net/ExtendedSocketOptions header extends java/lang/Object flags 31 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -field name SO_FLOW_SLA descriptor Ljava/net/SocketOption; flags 19 signature Ljava/net/SocketOption; +-field name TCP_KEEPIDLE descriptor Ljava/net/SocketOption; +-field name TCP_KEEPINTERVAL descriptor Ljava/net/SocketOption; +-field name TCP_KEEPCOUNT descriptor Ljava/net/SocketOption; class name jdk/net/NetworkPermission header extends java/security/BasicPermission flags 31 -method name descriptor (Ljava/lang/String;)V flags 1 -method name descriptor (Ljava/lang/String;Ljava/lang/String;)V flags 1 class name jdk/net/SocketFlow header extends java/lang/Object flags 21 innerclass innerClass jdk/net/SocketFlow$Status outerClass jdk/net/SocketFlow innerClassName Status flags 4019 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 field name UNSET descriptor I constantValue -1 flags 19 -field name NORMAL_PRIORITY descriptor I constantValue 1 flags 19 -field name HIGH_PRIORITY descriptor I constantValue 2 flags 19 -method name create descriptor ()Ljdk/net/SocketFlow; flags 9 -method name priority descriptor (I)Ljdk/net/SocketFlow; flags 1 -method name bandwidth descriptor (J)Ljdk/net/SocketFlow; flags 1 -method name priority descriptor ()I flags 1 -method name bandwidth descriptor ()J flags 1 -method name status descriptor ()Ljdk/net/SocketFlow$Status; flags 1 method name toString descriptor ()Ljava/lang/String; flags 1 class name jdk/net/SocketFlow$Status header extends java/lang/Enum flags 4031 signature Ljava/lang/Enum; innerclass innerClass jdk/net/SocketFlow$Status outerClass jdk/net/SocketFlow innerClassName Status flags 4019 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -field name NO_STATUS descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name OK descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name NO_PERMISSION descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name NOT_CONNECTED descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name NOT_SUPPORTED descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name ALREADY_CREATED descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name IN_PROGRESS descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name OTHER descriptor Ljdk/net/SocketFlow$Status; flags 4019 -method name values descriptor ()[Ljdk/net/SocketFlow$Status; flags 9 -method name valueOf descriptor (Ljava/lang/String;)Ljdk/net/SocketFlow$Status; flags 9 class name jdk/net/Sockets header extends java/lang/Object flags 21 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -method name setOption descriptor (Ljava/net/Socket;Ljava/net/SocketOption;Ljava/lang/Object;)V thrownTypes java/io/IOException flags 9 signature (Ljava/net/Socket;Ljava/net/SocketOption;TT;)V -method name getOption descriptor (Ljava/net/Socket;Ljava/net/SocketOption;)Ljava/lang/Object; thrownTypes java/io/IOException flags 9 signature (Ljava/net/Socket;Ljava/net/SocketOption;)TT; -method name setOption descriptor (Ljava/net/ServerSocket;Ljava/net/SocketOption;Ljava/lang/Object;)V thrownTypes java/io/IOException flags 9 signature (Ljava/net/ServerSocket;Ljava/net/SocketOption;TT;)V -method name getOption descriptor (Ljava/net/ServerSocket;Ljava/net/SocketOption;)Ljava/lang/Object; thrownTypes java/io/IOException flags 9 signature (Ljava/net/ServerSocket;Ljava/net/SocketOption;)TT; -method name setOption descriptor (Ljava/net/DatagramSocket;Ljava/net/SocketOption;Ljava/lang/Object;)V thrownTypes java/io/IOException flags 9 signature (Ljava/net/DatagramSocket;Ljava/net/SocketOption;TT;)V -method name getOption descriptor (Ljava/net/DatagramSocket;Ljava/net/SocketOption;)Ljava/lang/Object; thrownTypes java/io/IOException flags 9 signature (Ljava/net/DatagramSocket;Ljava/net/SocketOption;)TT; -method name supportedOptions descriptor (Ljava/lang/Class;)Ljava/util/Set; flags 9 signature (Ljava/lang/Class<*>;)Ljava/util/Set;>; diff --git a/src/jdk.compiler/share/data/symbols/symbols b/src/jdk.compiler/share/data/symbols/symbols index 7793033d22f..34619bed887 100644 --- a/src/jdk.compiler/share/data/symbols/symbols +++ b/src/jdk.compiler/share/data/symbols/symbols @@ -30,7 +30,7 @@ #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 -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.scripting.nashorn-8.sym.txt:jdk.sctp-8.sym.txt:jdk.security.auth-8.sym.txt:jdk.security.jgss-8.sym.txt +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 platform version B base A files java.activation-B.sym.txt:java.base-B.sym.txt:java.compiler-B.sym.txt:java.corba-B.sym.txt:java.datatransfer-B.sym.txt:java.desktop-B.sym.txt:java.instrument-B.sym.txt:java.logging-B.sym.txt:java.management-B.sym.txt:java.management.rmi-B.sym.txt:java.naming-B.sym.txt:java.net.http-B.sym.txt:java.prefs-B.sym.txt:java.rmi-B.sym.txt:java.scripting-B.sym.txt:java.se-B.sym.txt:java.se.ee-B.sym.txt:java.security.jgss-B.sym.txt:java.security.sasl-B.sym.txt:java.smartcardio-B.sym.txt:java.sql-B.sym.txt:java.sql.rowset-B.sym.txt:java.transaction-B.sym.txt:java.transaction.xa-B.sym.txt:java.xml-B.sym.txt:java.xml.bind-B.sym.txt:java.xml.crypto-B.sym.txt:java.xml.ws-B.sym.txt:java.xml.ws.annotation-B.sym.txt:jdk.accessibility-B.sym.txt:jdk.attach-B.sym.txt:jdk.charsets-B.sym.txt:jdk.compiler-B.sym.txt:jdk.crypto.cryptoki-B.sym.txt:jdk.crypto.ec-B.sym.txt:jdk.dynalink-B.sym.txt:jdk.editpad-B.sym.txt:jdk.hotspot.agent-B.sym.txt:jdk.httpserver-B.sym.txt:jdk.incubator.httpclient-B.sym.txt:jdk.jartool-B.sym.txt:jdk.javadoc-B.sym.txt:jdk.jcmd-B.sym.txt:jdk.jconsole-B.sym.txt:jdk.jdeps-B.sym.txt:jdk.jdi-B.sym.txt:jdk.jdwp.agent-B.sym.txt:jdk.jfr-B.sym.txt:jdk.jlink-B.sym.txt:jdk.jshell-B.sym.txt:jdk.jsobject-B.sym.txt:jdk.jstatd-B.sym.txt:jdk.localedata-B.sym.txt:jdk.management-B.sym.txt:jdk.management.agent-B.sym.txt:jdk.management.jfr-B.sym.txt:jdk.naming.dns-B.sym.txt:jdk.naming.rmi-B.sym.txt:jdk.net-B.sym.txt:jdk.pack-B.sym.txt:jdk.rmic-B.sym.txt:jdk.scripting.nashorn-B.sym.txt:jdk.sctp-B.sym.txt:jdk.security.auth-B.sym.txt:jdk.security.jgss-B.sym.txt:jdk.unsupported-B.sym.txt:jdk.xml.dom-B.sym.txt:jdk.zipfs-B.sym.txt diff --git a/src/jdk.compiler/share/man/javac.md b/src/jdk.compiler/share/man/javac.md index 997023487b0..46246624e53 100644 --- a/src/jdk.compiler/share/man/javac.md +++ b/src/jdk.compiler/share/man/javac.md @@ -1,5 +1,5 @@ --- -# Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1994, 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 @@ -208,8 +208,8 @@ file system locations may be directories, JAR files or JMOD files. `-deprecation` option is shorthand for `-Xlint:deprecation`. `--enable-preview` -: Enables preview language features. Used in conjunction with either - [`-source`](#option-source) or [`--release`](#option-release). +: Enables preview language features. Also disables the `preview` lint category. + Used in conjunction with either [`-source`](#option-source) or [`--release`](#option-release). `-encoding` *encoding* : Specifies character encoding used by source files, such as EUC-JP and @@ -448,7 +448,16 @@ file system locations may be directories, JAR files or JMOD files. : Prints version information. `-Werror` -: Terminates compilation when warnings occur. +: Terminates compilation when any warnings occur; this includes warnings in all lint + categories, as well as non-lint warnings. + +`-Werror:`\[`-`\]*key*(`,`\[`-`\]*key*)\* +: Specify lint categories for which warnings should terminate compilation. The keys + `all` and `none` include or exclude all categories (respectively); other keys include + the corresponding category, or exclude it if preceded by a hyphen (`-`). By default, + no categories are included. In order to terminate compilation, the category must also + be enabled (via [`-Xlint`](#option-Xlint-custom), if necessary). + See [`-Xlint`](#option-Xlint-custom) below for the list of lint category keys. ### Extra Options @@ -557,11 +566,11 @@ file system locations may be directories, JAR files or JMOD files. section of the `javadoc` command documentation. `-Xlint` -: Enables all recommended warnings. In this release, enabling all available - warnings is recommended. +: Enables recommended lint warning categories. In this release, all available + lint warning categories are recommended. `-Xlint:`\[`-`\]*key*(`,`\[`-`\]*key*)\* -: Enables and/or disables warning categories using the one or more of the keys described +: Enables and/or disables lint warning categories using the one or more of the keys described below separated by commas. The keys `all` and `none` enable or disable all categories (respectively); other keys enable the corresponding category, or disable it if preceded by a hyphen (`-`). @@ -648,10 +657,9 @@ file system locations may be directories, JAR files or JMOD files. - `strictfp`: Warns about unnecessary use of the `strictfp` modifier. - - `synchronization`: Warns about synchronization attempts on instances - of value-based classes. This key is a deprecated alias for `identity`, - which has the same uses and effects. Users are encouraged to use the - `identity` category for all future and existing uses of `synchronization`. + - `synchronization`: Deprecated alias for `identity` with an identical + effect. Users are encouraged to use `identity` instead of `synchronization` + for all current and future uses. - `text-blocks`: Warns about inconsistent white space characters in text block indentation. @@ -667,9 +675,13 @@ file system locations may be directories, JAR files or JMOD files. - `none`: Disables all warning categories. - With the exception of `all` and `none`, the keys can be used with - the `@SuppressWarnings` annotation to suppress warnings in a part - of the source code being compiled. + The keys listed above may be used in `@SuppressWarnings` annotations to suppress + warnings within the annotated declaration, with the exception of: `all`, `none`, + `classfile`, `incubating`, `options`, `output-file-clash`, `processing`, and `path`. + + By default, the following lint warning categories are enabled: `dep-ann`, `identity`, + `incubating`, `module`, `opens`, `preview`, `removal`, `requires-transitive-automatic`, + and `strictfp`. See [Examples of Using -Xlint keys]. diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java index 183135ce7e1..51d92691473 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyAgreement.java @@ -200,6 +200,7 @@ protected byte[] engineGenerateSecret() throws IllegalStateException { CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET), + new CK_ATTRIBUTE(CKA_VALUE_LEN, secretLen), }; attributes = token.getAttributes (O_GENERATE, CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes); @@ -213,22 +214,11 @@ protected byte[] engineGenerateSecret() throws IllegalStateException { token.p11.C_GetAttributeValue(session.id(), keyID, attributes); byte[] secret = attributes[0].getByteArray(); token.p11.C_DestroyObject(session.id(), keyID); - // Some vendors, e.g. NSS, trim off the leading 0x00 byte(s) from - // the generated secret. Thus, we need to check the secret length - // and trim/pad it so the returned value has the same length as - // the modulus size - if (secret.length == secretLen) { - return secret; - } else { - if (secret.length > secretLen) { - // Shouldn't happen; but check just in case - throw new ProviderException("generated secret is out-of-range"); - } - byte[] newSecret = new byte[secretLen]; - System.arraycopy(secret, 0, newSecret, secretLen - secret.length, - secret.length); - return newSecret; + if (secret.length != secretLen) { + // Shouldn't happen; but check just in case + throw new ProviderException("generated secret is out-of-range"); } + return secret; } catch (PKCS11Exception e) { throw new ProviderException("Could not derive key", e); } finally { @@ -321,10 +311,20 @@ private SecretKey nativeGenerateSecret(String algorithm) long privKeyID = privateKey.getKeyID(); try { session = token.getObjSession(); - CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { - new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), - new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), - }; + CK_ATTRIBUTE[] attributes; + if ("TlsPremasterSecret".equalsIgnoreCase(algorithm)) { + attributes = new CK_ATTRIBUTE[]{ + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), + }; + } else { + // keep the leading zeroes + attributes = new CK_ATTRIBUTE[]{ + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), + new CK_ATTRIBUTE(CKA_VALUE_LEN, secretLen), + }; + } attributes = token.getAttributes (O_GENERATE, CKO_SECRET_KEY, keyType, attributes); long keyID = token.p11.C_DeriveKey(session.id(), @@ -337,19 +337,6 @@ private SecretKey nativeGenerateSecret(String algorithm) int keyLen = (int)lenAttributes[0].getLong(); SecretKey key = P11Key.secretKey (session, keyID, algorithm, keyLen << 3, attributes); - if ("RAW".equals(key.getFormat()) - && algorithm.equalsIgnoreCase("TlsPremasterSecret")) { - // Workaround for Solaris bug 6318543. - // Strip leading zeroes ourselves if possible (key not sensitive). - // This should be removed once the Solaris fix is available - // as here we always retrieve the CKA_VALUE even for tokens - // that do not have that bug. - byte[] keyBytes = key.getEncoded(); - byte[] newBytes = KeyUtil.trimZeroes(keyBytes); - if (keyBytes != newBytes) { - key = new SecretKeySpec(newBytes, algorithm); - } - } return key; } catch (PKCS11Exception e) { throw new InvalidKeyException("Could not derive key", e); diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c index c3aaaf440a3..9c4f0b0d357 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c @@ -420,9 +420,15 @@ static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* li // Coredump stores value of p_memsz elf field // rounded up to page boundary. + // Account for the PH being at some vaddr offset from mapping in core file. + uint64_t lib_memsz = lib_php->p_memsz; + if (target_vaddr > existing_map->vaddr) { + lib_memsz += target_vaddr - existing_map->vaddr; + } + if ((existing_map->memsz != page_size) && (existing_map->fd != lib_fd) && - (ROUNDUP(existing_map->memsz, page_size) != ROUNDUP(lib_php->p_memsz, page_size))) { + (ROUNDUP(existing_map->memsz, page_size) != ROUNDUP(lib_memsz, page_size))) { print_error("address conflict @ 0x%lx (existing map size = %ld, size = %ld, flags = %d)\n", target_vaddr, existing_map->memsz, lib_php->p_memsz, lib_php->p_flags); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java index a3228765e91..939b47fdd2a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java @@ -37,6 +37,7 @@ public class NMethod extends CodeBlob { private static long pcDescSize; + private static long immutableDataReferencesCounterSize; private static AddressField methodField; /** != InvocationEntryBci if this nmethod is an on-stack replacement method */ private static CIntegerField entryBCIField; @@ -48,7 +49,6 @@ public class NMethod extends CodeBlob { /** Offsets for different nmethod parts */ private static CIntegerField exceptionOffsetField; private static CIntegerField deoptHandlerOffsetField; - private static CIntegerField deoptMhHandlerOffsetField; private static CIntegerField origPCOffsetField; private static CIntegerField stubOffsetField; private static CIntField handlerTableOffsetField; @@ -79,25 +79,25 @@ public void update(Observable o, Object data) { private static void initialize(TypeDataBase db) { Type type = db.lookupType("nmethod"); - methodField = type.getAddressField("_method"); - entryBCIField = type.getCIntegerField("_entry_bci"); - osrLinkField = type.getAddressField("_osr_link"); - immutableDataField = type.getAddressField("_immutable_data"); - immutableDataSizeField = type.getCIntegerField("_immutable_data_size"); - exceptionOffsetField = type.getCIntegerField("_exception_offset"); - deoptHandlerOffsetField = type.getCIntegerField("_deopt_handler_offset"); - deoptMhHandlerOffsetField = type.getCIntegerField("_deopt_mh_handler_offset"); - origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); - stubOffsetField = type.getCIntegerField("_stub_offset"); - scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset"); - scopesDataOffsetField = type.getCIntegerField("_scopes_data_offset"); - handlerTableOffsetField = new CIntField(type.getCIntegerField("_handler_table_offset"), 0); - nulChkTableOffsetField = new CIntField(type.getCIntegerField("_nul_chk_table_offset"), 0); - entryOffsetField = new CIntField(type.getCIntegerField("_entry_offset"), 0); - verifiedEntryOffsetField = new CIntField(type.getCIntegerField("_verified_entry_offset"), 0); - osrEntryPointField = type.getAddressField("_osr_entry_point"); - compLevelField = new CIntField(type.getCIntegerField("_comp_level"), 0); - pcDescSize = db.lookupType("PcDesc").getSize(); + methodField = type.getAddressField("_method"); + entryBCIField = type.getCIntegerField("_entry_bci"); + osrLinkField = type.getAddressField("_osr_link"); + immutableDataField = type.getAddressField("_immutable_data"); + immutableDataSizeField = type.getCIntegerField("_immutable_data_size"); + exceptionOffsetField = type.getCIntegerField("_exception_offset"); + deoptHandlerOffsetField = type.getCIntegerField("_deopt_handler_offset"); + origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); + stubOffsetField = type.getCIntegerField("_stub_offset"); + scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset"); + scopesDataOffsetField = type.getCIntegerField("_scopes_data_offset"); + handlerTableOffsetField = new CIntField(type.getCIntegerField("_handler_table_offset"), 0); + nulChkTableOffsetField = new CIntField(type.getCIntegerField("_nul_chk_table_offset"), 0); + entryOffsetField = new CIntField(type.getCIntegerField("_entry_offset"), 0); + verifiedEntryOffsetField = new CIntField(type.getCIntegerField("_verified_entry_offset"), 0); + osrEntryPointField = type.getAddressField("_osr_entry_point"); + compLevelField = new CIntField(type.getCIntegerField("_comp_level"), 0); + pcDescSize = db.lookupType("PcDesc").getSize(); + immutableDataReferencesCounterSize = VM.getVM().getIntSize(); } public NMethod(Address addr) { @@ -125,7 +125,6 @@ public Method getMethod() { public Address instsEnd() { return headerBegin().addOffsetTo(getStubOffset()); } public Address exceptionBegin() { return headerBegin().addOffsetTo(getExceptionOffset()); } public Address deoptHandlerBegin() { return headerBegin().addOffsetTo(getDeoptHandlerOffset()); } - public Address deoptMhHandlerBegin() { return headerBegin().addOffsetTo(getDeoptMhHandlerOffset()); } public Address stubBegin() { return headerBegin().addOffsetTo(getStubOffset()); } public Address stubEnd() { return dataBegin(); } public Address oopsBegin() { return dataBegin(); } @@ -142,7 +141,7 @@ public Method getMethod() { public Address scopesDataBegin() { return immutableDataBegin().addOffsetTo(getScopesDataOffset()); } public Address scopesDataEnd() { return immutableDataBegin().addOffsetTo(getScopesPCsOffset()); } public Address scopesPCsBegin() { return immutableDataBegin().addOffsetTo(getScopesPCsOffset()); } - public Address scopesPCsEnd() { return immutableDataEnd(); } + public Address scopesPCsEnd() { return immutableDataEnd().addOffsetTo(-immutableDataReferencesCounterSize); } public Address metadataBegin() { return mutableDataBegin().addOffsetTo(getRelocationSize()); } public Address metadataEnd() { return mutableDataEnd(); } @@ -172,7 +171,8 @@ public int immutableDataSize() { scopesPCsSize() + dependenciesSize() + handlerTableSize() + - nulChkTableSize(); + nulChkTableSize() + + (int) immutableDataReferencesCounterSize; } public boolean constantsContains (Address addr) { return constantsBegin() .lessThanOrEqual(addr) && constantsEnd() .greaterThan(addr); } @@ -250,22 +250,10 @@ public NMethod getOSRLink() { return VMObjectFactory.newObject(NMethod.class, osrLinkField.getValue(addr)); } - // MethodHandle - public boolean isMethodHandleReturn(Address returnPc) { - // Hard to read a bit fields from Java and it's only there for performance - // so just go directly to the PCDesc - // if (!hasMethodHandleInvokes()) return false; - PCDesc pd = getPCDescAt(returnPc); - if (pd == null) - return false; - return pd.isMethodHandleInvoke(); - } - // Deopt // Return true is the PC is one would expect if the frame is being deopted. - public boolean isDeoptPc (Address pc) { return isDeoptEntry(pc) || isDeoptMhEntry(pc); } + public boolean isDeoptPc (Address pc) { return isDeoptEntry(pc); } public boolean isDeoptEntry (Address pc) { return pc == deoptHandlerBegin(); } - public boolean isDeoptMhEntry (Address pc) { return pc == deoptMhHandlerBegin(); } /** Tells whether frames described by this nmethod can be deoptimized. Note: native wrappers cannot be deoptimized. */ @@ -494,7 +482,6 @@ public String getName() { private int getEntryBCI() { return (int) entryBCIField .getValue(addr); } private int getExceptionOffset() { return (int) exceptionOffsetField .getValue(addr); } private int getDeoptHandlerOffset() { return (int) deoptHandlerOffsetField .getValue(addr); } - private int getDeoptMhHandlerOffset() { return (int) deoptMhHandlerOffsetField.getValue(addr); } private int getStubOffset() { return (int) stubOffsetField .getValue(addr); } private int getScopesDataOffset() { return (int) scopesDataOffsetField .getValue(addr); } private int getScopesPCsOffset() { return (int) scopesPCsOffsetField .getValue(addr); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/PCDesc.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/PCDesc.java index 58f358c01aa..037c26b53f5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/PCDesc.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/PCDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, 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 @@ -41,7 +41,6 @@ public class PCDesc extends VMObject { private static CIntegerField objDecodeOffsetField; private static CIntegerField pcFlagsField; private static int reexecuteMask; - private static int isMethodHandleInvokeMask; private static int returnOopMask; static { @@ -61,7 +60,6 @@ private static void initialize(TypeDataBase db) { pcFlagsField = type.getCIntegerField("_flags"); reexecuteMask = db.lookupIntConstant("PcDesc::PCDESC_reexecute"); - isMethodHandleInvokeMask = db.lookupIntConstant("PcDesc::PCDESC_is_method_handle_invoke"); returnOopMask = db.lookupIntConstant("PcDesc::PCDESC_return_oop"); } @@ -93,11 +91,6 @@ public boolean getReexecute() { return (flags & reexecuteMask) != 0; } - public boolean isMethodHandleInvoke() { - int flags = (int)pcFlagsField.getValue(addr); - return (flags & isMethodHandleInvokeMask) != 0; - } - public void print(NMethod code) { printOn(System.out, code); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java index 5f3c9786d6e..3dfb83c9f5a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, 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 @@ -145,17 +145,12 @@ public CFrame sender(ThreadProxy thread) { } DwarfParser nextDwarf = null; - - if ((dwarf != null) && dwarf.isIn(nextPC)) { - nextDwarf = dwarf; - } else { - Address libptr = dbg.findLibPtrByAddress(nextPC); - if (libptr != null) { - try { - nextDwarf = new DwarfParser(libptr); - } catch (DebuggerException e) { - // Bail out to Java frame - } + Address libptr = dbg.findLibPtrByAddress(nextPC); + if (libptr != null) { + try { + nextDwarf = new DwarfParser(libptr); + } catch (DebuggerException e) { + // Bail out to Java frame } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java index 1ea34fe6cd2..c41372810a3 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, 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 @@ -151,12 +151,6 @@ public boolean mustBePreserved() { public boolean hasLocker() { return ((value() & lockMaskInPlace) == lockedValue); } - public BasicLock locker() { - if (Assert.ASSERTS_ENABLED) { - Assert.that(hasLocker(), "check"); - } - return new BasicLock(valueAsAddress()); - } public boolean hasMonitor() { return ((value() & monitorValue) != 0); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java index 979e08cfb8a..6ca53b4c545 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, 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 @@ -36,23 +36,11 @@ public class BasicLock extends VMObject { static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); } }); } - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("BasicLock"); - displacedHeaderField = type.getCIntegerField("_metadata"); - } - - private static CIntegerField displacedHeaderField; - public BasicLock(Address addr) { super(addr); } - - public Mark displacedHeader() { - return new Mark(addr.addOffsetTo(displacedHeaderField.getOffset())); - } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java index a8c17a9f59e..27efb631f79 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, 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 @@ -81,6 +81,24 @@ public static int pcReturnOffset() { return pcReturnOffset; } + protected void adjustForDeopt() { + if (pc != null) { + // Look for a deopt pc and if it is deopted convert to original pc + CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); + if (cb != null && cb.isJavaMethod()) { + NMethod nm = (NMethod) cb; + if (pc.equals(nm.deoptHandlerBegin())) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); + } + // adjust pc if frame is deoptimized. + pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); + deoptimized = true; + } + } + } + } + private static synchronized void initialize(TypeDataBase db) { Type ConstMethodType = db.lookupType("ConstMethod"); // FIXME: not sure whether alignment here is correct or how to diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java index dca5f2efa3b..a5aa7ce4405 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -106,30 +106,11 @@ private static synchronized void initialize(TypeDataBase db) { private AARCH64Frame() { } - private void adjustForDeopt() { - if ( pc != null) { - // Look for a deopt pc and if it is deopted convert to original pc - CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); - if (cb != null && cb.isJavaMethod()) { - NMethod nm = (NMethod) cb; - if (pc.equals(nm.deoptHandlerBegin())) { - if (Assert.ASSERTS_ENABLED) { - Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); - } - // adjust pc if frame is deoptimized. - pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); - deoptimized = true; - } - } - } - } - public AARCH64Frame(Address raw_sp, Address raw_fp, Address pc) { this.raw_sp = raw_sp; this.raw_unextendedSP = raw_sp; this.raw_fp = raw_fp; this.pc = pc; - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -153,8 +134,6 @@ public AARCH64Frame(Address raw_sp, Address raw_fp) { this.pc = savedPC; } - adjustUnextendedSP(); - // Frame must be fully constructed before this call adjustForDeopt(); @@ -169,7 +148,6 @@ public AARCH64Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Ad this.raw_unextendedSP = raw_unextendedSp; this.raw_fp = raw_fp; this.pc = pc; - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -355,24 +333,6 @@ private Frame senderForUpcallStub(AARCH64RegisterMap map, UpcallStub stub) { return fr; } - //------------------------------------------------------------------------------ - // frame::adjust_unextended_sp - private void adjustUnextendedSP() { - // Sites calling method handle intrinsics and lambda forms are - // treated as any other call site. Therefore, no special action is - // needed when we are returning to any of these call sites. - - CodeBlob cb = cb(); - NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull(); - if (senderNm != null) { - // If the sender PC is a deoptimization point, get the original PC. - if (senderNm.isDeoptEntry(getPC()) || - senderNm.isDeoptMhEntry(getPC())) { - // DEBUG_ONLY(verifyDeoptriginalPc(senderNm, raw_unextendedSp)); - } - } - } - private Frame senderForInterpreterFrame(AARCH64RegisterMap map) { if (DEBUG) { System.out.println("senderForInterpreterFrame"); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java index a47a632c286..f4ce5337e2f 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.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 @@ -85,24 +85,6 @@ private static synchronized void initialize(TypeDataBase db) { private PPC64Frame() { } - private void adjustForDeopt() { - if ( pc != null) { - // Look for a deopt pc and if it is deopted convert to original pc - CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); - if (cb != null && cb.isJavaMethod()) { - NMethod nm = (NMethod) cb; - if (pc.equals(nm.deoptHandlerBegin())) { - if (Assert.ASSERTS_ENABLED) { - Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); - } - // adjust pc if frame is deoptimized. - pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); - deoptimized = true; - } - } - } - } - public PPC64Frame(Address raw_sp, Address raw_fp, Address pc) { this.raw_sp = raw_sp; this.raw_unextendedSP = raw_sp; @@ -116,7 +98,6 @@ public PPC64Frame(Address raw_sp, Address raw_fp, Address pc) { } else { this.pc = pc; } - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -136,7 +117,6 @@ public PPC64Frame(Address raw_sp, Address raw_fp) { this.raw_fp = raw_fp; } this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize()); - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -160,7 +140,6 @@ public PPC64Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Addr } else { this.pc = pc; } - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -342,12 +321,6 @@ private Frame senderForUpcallStub(PPC64RegisterMap map, UpcallStub stub) { return fr; } - //------------------------------------------------------------------------------ - // frame::adjust_unextended_sp - private void adjustUnextendedSP() { - // Nothing to do. senderForInterpreterFrame finds the correct unextendedSP. - } - private Frame senderForInterpreterFrame(PPC64RegisterMap map) { if (DEBUG) { System.out.println("senderForInterpreterFrame"); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java index 948a3008016..e02e056f028 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019, Red Hat Inc. * Copyright (c) 2021, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -101,30 +101,11 @@ private static synchronized void initialize(TypeDataBase db) { private RISCV64Frame() { } - private void adjustForDeopt() { - if ( pc != null) { - // Look for a deopt pc and if it is deopted convert to original pc - CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); - if (cb != null && cb.isJavaMethod()) { - NMethod nm = (NMethod) cb; - if (pc.equals(nm.deoptHandlerBegin())) { - if (Assert.ASSERTS_ENABLED) { - Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); - } - // adjust pc if frame is deoptimized. - pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); - deoptimized = true; - } - } - } - } - public RISCV64Frame(Address raw_sp, Address raw_fp, Address pc) { this.raw_sp = raw_sp; this.raw_unextendedSP = raw_sp; this.raw_fp = raw_fp; this.pc = pc; - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -148,8 +129,6 @@ public RISCV64Frame(Address raw_sp, Address raw_fp) { this.pc = savedPC; } - adjustUnextendedSP(); - // Frame must be fully constructed before this call adjustForDeopt(); @@ -164,7 +143,6 @@ public RISCV64Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Ad this.raw_unextendedSP = raw_unextendedSp; this.raw_fp = raw_fp; this.pc = pc; - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); @@ -347,24 +325,6 @@ private Frame senderForUpcallStub(RISCV64RegisterMap map, UpcallStub stub) { return fr; } - //------------------------------------------------------------------------------ - // frame::adjust_unextended_sp - private void adjustUnextendedSP() { - // Sites calling method handle intrinsics and lambda forms are - // treated as any other call site. Therefore, no special action is - // needed when we are returning to any of these call sites. - - CodeBlob cb = cb(); - NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull(); - if (senderNm != null) { - // If the sender PC is a deoptimization point, get the original PC. - if (senderNm.isDeoptEntry(getPC()) || - senderNm.isDeoptMhEntry(getPC())) { - // DEBUG_ONLY(verifyDeoptriginalPc(senderNm, raw_unextendedSp)); - } - } - } - private Frame senderForInterpreterFrame(RISCV64RegisterMap map) { if (DEBUG) { System.out.println("senderForInterpreterFrame"); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java index 169ecea1565..3ee4f0a8158 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, 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 @@ -102,24 +102,6 @@ private static synchronized void initialize(TypeDataBase db) { private X86Frame() { } - private void adjustForDeopt() { - if ( pc != null) { - // Look for a deopt pc and if it is deopted convert to original pc - CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); - if (cb != null && cb.isJavaMethod()) { - NMethod nm = (NMethod) cb; - if (pc.equals(nm.deoptHandlerBegin())) { - if (Assert.ASSERTS_ENABLED) { - Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); - } - // adjust pc if frame is deoptimized. - pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); - deoptimized = true; - } - } - } - } - private void initFrame(Address raw_sp, Address raw_fp, Address pc, Address raw_unextendedSp, Address live_bcp) { this.raw_sp = raw_sp; this.raw_fp = raw_fp; @@ -134,11 +116,10 @@ private void initFrame(Address raw_sp, Address raw_fp, Address pc, Address raw_u this.pc = pc; } this.live_bcp = live_bcp; - adjustUnextendedSP(); // Frame must be fully constructed before this call adjustForDeopt(); -} + } public X86Frame(Address raw_sp, Address raw_fp, Address pc) { @@ -352,24 +333,6 @@ private Frame senderForUpcallStub(X86RegisterMap map, UpcallStub stub) { return fr; } - //------------------------------------------------------------------------------ - // frame::adjust_unextended_sp - private void adjustUnextendedSP() { - // On x86, sites calling method handle intrinsics and lambda forms are treated - // as any other call site. Therefore, no special action is needed when we are - // returning to any of these call sites. - - CodeBlob cb = cb(); - NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull(); - if (senderNm != null) { - // If the sender PC is a deoptimization point, get the original PC. - if (senderNm.isDeoptEntry(getPC()) || - senderNm.isDeoptMhEntry(getPC())) { - // DEBUG_ONLY(verifyDeoptriginalPc(senderNm, raw_unextendedSp)); - } - } - } - private Frame senderForInterpreterFrame(X86RegisterMap map) { if (DEBUG) { System.out.println("senderForInterpreterFrame"); diff --git a/src/jdk.hotspot.agent/test/libproc/LibprocClient.java b/src/jdk.hotspot.agent/test/libproc/LibprocClient.java deleted file mode 100644 index 751c23ee92f..00000000000 --- a/src/jdk.hotspot.agent/test/libproc/LibprocClient.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.tools.*; -import sun.jvm.hotspot.utilities.*; - -/** - We don't run any of the "standard" SA command line tools for sanity - check. This is because the standard tools print addresses in hex - which could change legally. Also, textual comparison of output may - not match because of other reasons as well. This tool checks - validity of threads and frames logically. This class has reference - frame names from "known" threads. The debuggee is assumed to run - "LibprocTest.java". -*/ - -public class LibprocClient extends Tool { - - public void run() { - // try to get VM version and check - String version = VM.getVM().getVMRelease(); - Assert.that(version.startsWith("1.5"), "1.5 expected"); - - // try getting threads - Threads threads = VM.getVM().getThreads(); - boolean mainTested = false; - - // check frames of each thread - for (JavaThread cur = threads.first(); cur != null; cur = cur.next()) { - if (cur.isJavaThread()) { - String name = cur.getThreadName(); - // testing of basic frame walking for all threads - for (JavaVFrame vf = getLastJavaVFrame(cur); vf != null; vf = vf.javaSender()) { - checkFrame(vf); - } - - // special testing for "known" threads. For now, only "main" thread. - if (name.equals("main")) { - checkMainThread(cur); - mainTested = true; - } - } - } - Assert.that(mainTested, "main thread missing"); - } - - public static void main(String[] args) { - try { - LibprocClient lc = new LibprocClient(); - lc.start(args); - lc.getAgent().detach(); - System.out.println("\nPASSED\n"); - } catch (Exception exp) { - System.out.println("\nFAILED\n"); - exp.printStackTrace(); - } - } - - // -- Internals only below this point - private static JavaVFrame getLastJavaVFrame(JavaThread cur) { - RegisterMap regMap = cur.newRegisterMap(true); - Frame f = cur.getCurrentFrameGuess(); - if (f == null) { - System.err.println(" (Unable to get a top most frame)"); - return null; - } - VFrame vf = VFrame.newVFrame(f, regMap, cur, true, true); - if (vf == null) { - System.err.println(" (Unable to create vframe for topmost frame guess)"); - return null; - } - if (vf.isJavaFrame()) { - return (JavaVFrame) vf; - } - return (JavaVFrame) vf.javaSender(); - } - - private void checkMethodSignature(Symbol sig) { - SignatureIterator itr = new SignatureIterator(sig) { - public void doBool () {} - public void doChar () {} - public void doFloat () {} - public void doDouble() {} - public void doByte () {} - public void doShort () {} - public void doInt () {} - public void doLong () {} - public void doVoid () {} - public void doObject(int begin, int end) {} - public void doArray (int begin, int end) {} - }; - // this will throw RuntimeException for any invalid item in signature. - itr.iterate(); - } - - private void checkBCI(Method m, int bci) { - if (! m.isNative()) { - byte[] buf = m.getByteCode(); - Assert.that(bci >= 0 && bci < buf.length, "invalid bci, not in code range"); - if (m.hasLineNumberTable()) { - int lineNum = m.getLineNumberFromBCI(bci); - Assert.that(lineNum >= 0, "expecting non-negative line number"); - } - } - } - - private void checkMethodHolder(Method method) { - Klass klass = method.getMethodHolder(); - Assert.that(klass != null, "expecting non-null instance klass"); - } - - private void checkFrame(JavaVFrame vf) { - Method method = vf.getMethod(); - Assert.that(method != null, "expecting a non-null method here"); - Assert.that(method.getName() != null, "expecting non-null method name"); - checkMethodHolder(method); - checkMethodSignature(method.getSignature()); - checkBCI(method, vf.getBCI()); - } - - // from the test case LibprocTest.java - in the main thread we - // should see frames as below - private static String[] mainThreadMethods = new String[] { - "java.lang.Object.wait(long)", - "java.lang.Object.wait()", - "LibprocTest.main(java.lang.String[])" - }; - - private void checkMainThread(JavaThread thread) { - checkFrames(thread, mainThreadMethods); - } - - private void checkFrames(JavaThread thread, String[] expectedMethodNames) { - int i = 0; - for (JavaVFrame vf = getLastJavaVFrame(thread); vf != null; vf = vf.javaSender(), i++) { - Method m = vf.getMethod(); - Assert.that(m.externalNameAndSignature().equals(expectedMethodNames[i]), - "expected frame missing"); - } - } -} diff --git a/src/jdk.hotspot.agent/test/libproc/Makefile b/src/jdk.hotspot.agent/test/libproc/Makefile deleted file mode 100644 index c7b171bc633..00000000000 --- a/src/jdk.hotspot.agent/test/libproc/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -all: - javac LibprocTest.java - javac -classpath ../../build/classes LibprocClient.java - -clean: - rm -rf *.class diff --git a/src/jdk.hotspot.agent/test/libproc/README b/src/jdk.hotspot.agent/test/libproc/README deleted file mode 100644 index 928c43d3fe7..00000000000 --- a/src/jdk.hotspot.agent/test/libproc/README +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. -# 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. -# -# - -After making any changes to libproc.so, the shell scripts described -below can be run to verify that it does not break Java Serviceability -Agent. - -Setup: - -You need to have jdk 1.5 installed to run this test. Set environment -variable SA_JAVA to point to the java executable of jdk -1.5. Otherwise, the script picks-up 'java' from PATH. - -Running the tests: - -run libproctest.sh (32-bit debuggee) and libproctest64.sh (64-bit -debuggee) - -Interpreting result: - -"PASSED" or "FAILED" is printed in standard output. diff --git a/src/jdk.hotspot.agent/test/libproc/libproctest.sh b/src/jdk.hotspot.agent/test/libproc/libproctest.sh deleted file mode 100644 index 0ed1d1a4cf4..00000000000 --- a/src/jdk.hotspot.agent/test/libproc/libproctest.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/ksh - -# -# Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -# This script is used to run consistency check of Serviceabilty Agent -# after making any libproc.so changes. Prints "PASSED" or "FAILED" in -# standard output. - -usage() { - echo "usage: $0" - echo " set SA_JAVA to be java executable from JDK 1.5" - exit 1 -} - -STARTDIR=`dirname $0` - -if [ "$1" == "-help" ]; then - usage -fi - -if [ "x$SA_JAVA" = "x" ]; then - SA_JAVA=java -fi - -# create java process with test case -tmp=/tmp/libproctest -rm -f $tmp -$SA_JAVA -classpath $STARTDIR LibprocTest > $tmp & -pid=$! -while [ ! -s $tmp ] ; do - # Kludge alert! - sleep 2 -done - -# dump core -gcore $pid -kill -9 $pid - - -# run libproc client -$SA_JAVA -showversion -cp $STARTDIR/../../build/classes::$STARTDIR/../sa.jar:$STARTDIR LibprocClient x core.$pid - -# delete core -rm -f core.$pid diff --git a/src/jdk.hotspot.agent/test/libproc/libproctest64.sh b/src/jdk.hotspot.agent/test/libproc/libproctest64.sh deleted file mode 100644 index 7791190743b..00000000000 --- a/src/jdk.hotspot.agent/test/libproc/libproctest64.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/ksh - -# -# Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -# This script is used to run consistency check of Serviceabilty Agent -# after making any libproc.so changes. Prints "PASSED" or "FAILED" in -# standard output. - -usage() { - echo "usage: $0" - echo " set SA_JAVA to be the java executable from JDK 1.5" - exit 1 -} - -if [ "$1" == "-help" ]; then - usage -fi - -if [ "x$SA_JAVA" = "x" ]; then - SA_JAVA=java -fi - -STARTDIR=`dirname $0` - -# create java process with test case -tmp=/tmp/libproctest -rm -f $tmp -$SA_JAVA -d64 -classpath $STARTDIR LibprocTest > $tmp & -pid=$! -while [ ! -s $tmp ] ; do - # Kludge alert! - sleep 2 -done - -# dump core -gcore $pid -kill -9 $pid - -# run libproc client -$SA_JAVA -d64 -showversion -cp $STARTDIR/../../build/classes::$STARTDIR/../sa.jar:$STARTDIR LibprocClient x core.$pid - -# delete core -rm -f core.$pid diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java index 45dd52175cc..fe2a6bf5580 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java @@ -34,6 +34,9 @@ import static jdk.incubator.vector.Float16Consts.SIGN_BIT_MASK; import static jdk.incubator.vector.Float16Consts.EXP_BIT_MASK; import static jdk.incubator.vector.Float16Consts.SIGNIF_BIT_MASK; +import static jdk.incubator.vector.Float16Consts.MAG_BIT_MASK; +import static jdk.incubator.vector.Float16Consts.EXP_BIAS; +import static jdk.incubator.vector.Float16Consts.SIGNIFICAND_WIDTH; import static java.lang.Float.float16ToFloat; import static java.lang.Float.floatToFloat16; @@ -94,19 +97,26 @@ * IEEE Standard for Floating-Point Arithmetic */ -// Currently Float16 is a value-based class and in future it is +// Currently Float16 is a value-based class and in the future it is // expected to be aligned with Value Classes and Object as described in // JEP-401 (https://openjdk.org/jeps/401). @jdk.internal.ValueBased public final class Float16 extends Number implements Comparable { - /** @serial */ + + /** + * Primitive {@code short} field to hold the bits of the {@code Float16}. + * @serial + */ private final short value; + private static final long serialVersionUID = 16; // May not be needed when a value class? // Functionality for future consideration: - // IEEEremainder / remainder operator remainder + // IEEEremainder and separate % operator remainder (which are + // defined to use different rounding modes, see JLS sections 15.4 + // and 15.17.3). // Do *not* define any public constructors /** @@ -146,6 +156,16 @@ private Float16(short bits) { */ public static final Float16 NaN = valueOf(Float.NaN); + /** + * A constant holding a zero (0.0) of type {@code Float16}. + */ + private static final Float16 ZERO = valueOf(0); + + /** + * A constant holding a one (1.0) of type {@code Float16}. + */ + private static final Float16 ONE = valueOf(1); + /** * A constant holding the largest positive finite value of type * {@code Float16}, @@ -222,6 +242,16 @@ private Float16(short bits) { */ public static final int BYTES = SIZE / Byte.SIZE; + /** + * The overflow threshold (for round to nearest) is MAX_VALUE + 1/2 ulp. + */ + private static final double OVERFLOW_THRESH = 0x1.ffcp15 + 0x0.002p15; + + /** + * The underflow threshold (for round to nearest) is MIN_VALUE * 0.5. + */ + private static final double UNDERFLOW_THRESH = 0x1.0p-24d * 0.5d; + /** * Returns a string representation of the {@code Float16} * argument. @@ -301,10 +331,10 @@ public static Float16 valueOf(int value) { * @param value a {@code long} value. */ public static Float16 valueOf(long value) { - if (value <= -65_520L) { // -(Float16.MAX_VALUE + Float16.ulp(Float16.MAX_VALUE) / 2) + if (value <= -65_520L) { // -(MAX_VALUE + ulp(MAX_VALUE) / 2) return NEGATIVE_INFINITY; } else { - if (value >= 65_520L) { // Float16.MAX_VALUE + Float16.ulp(Float16.MAX_VALUE) / 2 + if (value >= 65_520L) { // MAX_VALUE + ulp(MAX_VALUE) / 2 return POSITIVE_INFINITY; } // Remaining range of long, the integers in approx. +/- @@ -340,51 +370,51 @@ public static Float16 valueOf(float f) { * @param d a {@code double} */ public static Float16 valueOf(double d) { - long doppel = Double.doubleToRawLongBits(d); - - short sign_bit = (short)((doppel & 0x8000_0000_0000_0000L) >> 48); - if (Double.isNaN(d)) { // Have existing float code handle any attempts to // preserve NaN bits. return valueOf((float)d); } + long doppel = Double.doubleToRawLongBits(d); + short sign_bit = (short)((doppel & 0x8000_0000_0000_0000L) >> (64 - 16)); double abs_d = Math.abs(d); - // The overflow threshold is binary16 MAX_VALUE + 1/2 ulp - if (abs_d >= (0x1.ffcp15 + 0x0.002p15) ) { + if (abs_d >= OVERFLOW_THRESH) { // correctly signed infinity return new Float16((short)(sign_bit | 0x7c00)); } - // Smallest magnitude nonzero representable binary16 value - // is equal to 0x1.0p-24; half-way and smaller rounds to zero. - if (abs_d <= 0x1.0p-24d * 0.5d) { // Covers double zeros and subnormals. - return new Float16(sign_bit); // Positive or negative zero + if (abs_d <= UNDERFLOW_THRESH) { // Covers double zeros and subnormals. + // positive or negative zero + return new Float16(sign_bit); } // Dealing with finite values in exponent range of binary16 // (when rounding is done, could still round up) int exp = Math.getExponent(d); - assert -25 <= exp && exp <= 15; - - // For binary16 subnormals, beside forcing exp to -15, retain - // the difference expdelta = E_min - exp. This is the excess - // shift value, in addition to 42, to be used in the + assert + (MIN_EXPONENT - PRECISION) <= exp && + exp <= MAX_EXPONENT; + + // For target format subnormals, beside forcing exp to + // MIN_EXPONENT-1, retain the difference expdelta = E_min - + // exp. This is the excess shift value, in addition to the + // difference in precision bits, to be used in the // computations below. Further the (hidden) msb with value 1 // in d must be involved as well. int expdelta = 0; long msb = 0x0000_0000_0000_0000L; - if (exp < -14) { - expdelta = -14 - exp; // FIXME? - exp = -15; - msb = 0x0010_0000_0000_0000L; // should be 0x0020_... ? + if (exp < MIN_EXPONENT) { + expdelta = MIN_EXPONENT - exp; + exp = MIN_EXPONENT - 1; + msb = 0x0010_0000_0000_0000L; } long f_signif_bits = doppel & 0x000f_ffff_ffff_ffffL | msb; + final int PRECISION_DIFF = Double.PRECISION - PRECISION; // 42 // Significand bits as if using rounding to zero (truncation). - short signif_bits = (short)(f_signif_bits >> (42 + expdelta)); + short signif_bits = (short)(f_signif_bits >> (PRECISION_DIFF + expdelta)); // For round to nearest even, determining whether or not to // round up (in magnitude) is a function of the least @@ -399,9 +429,9 @@ public static Float16 valueOf(double d) { // 1 1 1 // See "Computer Arithmetic Algorithms," Koren, Table 4.9 - long lsb = f_signif_bits & (1L << 42 + expdelta); - long round = f_signif_bits & (1L << 41 + expdelta); - long sticky = f_signif_bits & ((1L << 41 + expdelta) - 1); + long lsb = f_signif_bits & (1L << (PRECISION_DIFF + expdelta)); + long round = f_signif_bits & (1L << (PRECISION_DIFF - 1) + expdelta); + long sticky = f_signif_bits & ((1L << (PRECISION_DIFF - 1) + expdelta) - 1); if (round != 0 && ((lsb | sticky) != 0 )) { signif_bits++; @@ -412,7 +442,8 @@ public static Float16 valueOf(double d) { // to implement a carry out from rounding the significand. assert (0xf800 & signif_bits) == 0x0; - return new Float16((short)(sign_bit | ( ((exp + 15) << 10) + signif_bits ) )); + return new Float16((short)(sign_bit | + ( ((exp + EXP_BIAS) << (PRECISION - 1)) + signif_bits) )); } /** @@ -451,7 +482,7 @@ public static Float16 valueOf(String s) throws NumberFormatException { // characters rather than codepoints. if (trialResult == 0.0 // handles signed zeros - || Math.abs(trialResult) > (65504.0 + 32.0) || // Float.MAX_VALUE + ulp(MAX_VALUE), + || Math.abs(trialResult) > (65504.0 + 32.0) || // MAX_VALUE + ulp(MAX_VALUE), // handles infinities too Double.isNaN(trialResult) || noDoubleRoundingToFloat16(trialResult)) { @@ -600,7 +631,7 @@ private class BigDecimalConversion { * Float16}. */ private static final Float16[] FLOAT16_10_POW = { - Float16.valueOf(1), Float16.valueOf(10), Float16.valueOf(100), + Float16.ONE, Float16.valueOf(10), Float16.valueOf(100), Float16.valueOf(1_000), Float16.valueOf(10_000) }; @@ -637,14 +668,14 @@ private static BigInteger bigTenToThe(int scale) { private static Float16 fullFloat16Value(BigDecimal bd) { if (BigDecimal.ZERO.compareTo(bd) == 0) { - return Float16.valueOf(0); + return ZERO; } BigInteger w = bd.unscaledValue().abs(); int scale = bd.scale(); long qb = w.bitLength() - (long) Math.ceil(scale * L); Float16 signum = Float16.valueOf(bd.signum()); if (qb < Q_MIN_F16 - 2) { // qb < -26 - return Float16.multiply(signum, Float16.valueOf(0)); + return Float16.multiply(signum, ZERO); } if (qb > Q_MAX_F16 + P_F16 + 1) { // qb > 17 return Float16.multiply(signum, Float16.POSITIVE_INFINITY); @@ -717,7 +748,7 @@ public static Float16 valueOf(BigInteger bi) { public static boolean isNaN(Float16 f16) { final short bits = float16ToRawShortBits(f16); // A NaN value has all ones in its exponent and a non-zero significand - return ((bits & 0x7c00) == 0x7c00 && (bits & 0x03ff) != 0); + return ((bits & EXP_BIT_MASK) == EXP_BIT_MASK && (bits & SIGNIF_BIT_MASK) != 0); } /** @@ -736,8 +767,9 @@ public static boolean isNaN(Float16 f16) { * @see Double#isInfinite(double) */ public static boolean isInfinite(Float16 f16) { - return ((float16ToRawShortBits(f16) ^ - float16ToRawShortBits(POSITIVE_INFINITY)) & 0x7fff) == 0; + final short bits = float16ToRawShortBits(f16); + // An infinite value has all ones in its exponent and a zero significand + return ((bits & EXP_BIT_MASK) == EXP_BIT_MASK && (bits & SIGNIF_BIT_MASK) == 0); } /** @@ -757,7 +789,7 @@ public static boolean isInfinite(Float16 f16) { * @see Double#isFinite(double) */ public static boolean isFinite(Float16 f16) { - return (float16ToRawShortBits(f16) & (short)0x0000_7FFF) <= + return (float16ToRawShortBits(f16) & MAG_BIT_MASK) <= float16ToRawShortBits(MAX_VALUE); } @@ -881,7 +913,7 @@ public int hashCode() { */ public static int hashCode(Float16 value) { // Use bit-pattern of canonical NaN for hashing. - Float16 f16 = isNaN(value) ? Float16.NaN : value; + Float16 f16 = isNaN(value) ? NaN : value; return (int)float16ToRawShortBits(f16); } @@ -928,7 +960,7 @@ public static short float16ToRawShortBits(Float16 f16) { */ public static short float16ToShortBits(Float16 f16) { if (isNaN(f16)) { - return Float16.NaN.value; + return NaN.value; } return f16.value; } @@ -1076,7 +1108,7 @@ public static Float16 min(Float16 a, Float16 b) { * 2) performing the operation in the wider format * 3) converting the result from 2) to the narrower format * - * For example, this property hold between the formats used for the + * For example, this property holds between the formats used for the * float and double types. Therefore, the following is a valid * implementation of a float addition: * @@ -1460,7 +1492,7 @@ public static Float16 negate(Float16 f16) { // operation. Therefore, in this case do _not_ use the float // unary minus as an implementation as that is not guaranteed // to flip the sign bit of a NaN. - return shortBitsToFloat16((short)(f16.value ^ (short)0x0000_8000)); + return shortBitsToFloat16((short)(f16.value ^ SIGN_BIT_MASK)); } /** @@ -1478,7 +1510,7 @@ public static Float16 negate(Float16 f16) { public static Float16 abs(Float16 f16) { // Zero out sign bit. Per IEE 754-2019 section 5.5.1, abs is a // bit-level operation and not a logical operation. - return shortBitsToFloat16((short)(f16.value & (short)0x0000_7FFF)); + return shortBitsToFloat16((short)(f16.value & MAG_BIT_MASK)); } /** @@ -1513,8 +1545,8 @@ public static int getExponent(Float16 f16) { */ /*package*/ static int getExponent0(short bits) { // package private to be usable in java.lang.Float. - int bin16ExpBits = 0x0000_7c00 & bits; // Five exponent bits. - return (bin16ExpBits >> (PRECISION - 1)) - 15; + int bin16ExpBits = EXP_BIT_MASK & bits; // Five exponent bits. + return (bin16ExpBits >> (PRECISION - 1)) - EXP_BIAS; } /** @@ -1545,13 +1577,13 @@ public static Float16 ulp(Float16 f16) { int exp = getExponent(f16); return switch(exp) { - case MAX_EXPONENT + 1 -> abs(f16); // NaN or infinity - case MIN_EXPONENT - 1 -> Float16.MIN_VALUE; // zero or subnormal + case MAX_EXPONENT + 1 -> abs(f16); // NaN or infinity + case MIN_EXPONENT - 1 -> MIN_VALUE; // zero or subnormal default -> { - assert exp <= MAX_EXPONENT && exp >= MIN_EXPONENT; + assert exp <= MAX_EXPONENT && exp >= MIN_EXPONENT: "Out of range exponent"; // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x)) // Let float -> float16 conversion handle encoding issues. - yield scalb(valueOf(1), exp - (PRECISION - 1)); + yield scalb(ONE, exp - (PRECISION - 1)); } }; } @@ -1669,11 +1701,10 @@ public static Float16 scalb(Float16 v, int scaleFactor) { // nonzero value by it would be guaranteed to over or // underflow; due to rounding, scaling down takes an // additional power of two which is reflected here - final int MAX_SCALE = Float16.MAX_EXPONENT + -Float16.MIN_EXPONENT + - Float16Consts.SIGNIFICAND_WIDTH + 1; + final int MAX_SCALE = MAX_EXPONENT + -MIN_EXPONENT + SIGNIFICAND_WIDTH + 1; // Make sure scaling factor is in a reasonable range - scaleFactor = Math.max(Math.min(scaleFactor, MAX_SCALE), -MAX_SCALE); + scaleFactor = Math.clamp(scaleFactor, -MAX_SCALE, MAX_SCALE); int DoubleConsts_EXP_BIAS = 1023; /* @@ -1707,9 +1738,8 @@ public static Float16 scalb(Float16 v, int scaleFactor) { * @see Math#copySign(double, double) */ public static Float16 copySign(Float16 magnitude, Float16 sign) { - return shortBitsToFloat16((short) ((float16ToRawShortBits(sign) & SIGN_BIT_MASK) | - (float16ToRawShortBits(magnitude) & - (EXP_BIT_MASK | SIGNIF_BIT_MASK) ))); + return shortBitsToFloat16((short)((float16ToRawShortBits(sign) & SIGN_BIT_MASK) | + (float16ToRawShortBits(magnitude) & MAG_BIT_MASK))); } /** @@ -1731,7 +1761,7 @@ public static Float16 copySign(Float16 magnitude, Float16 sign) { * @see Math#signum(double) */ public static Float16 signum(Float16 f) { - return (f.floatValue() == 0.0f || isNaN(f)) ? f : copySign(valueOf(1), f); + return (f.floatValue() == 0.0f || isNaN(f)) ? f : copySign(ONE, f); } // TODO: Temporary location for this functionality while Float16 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java index 2b6bfa77951..cda4bc9a5be 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java @@ -378,7 +378,8 @@ private void addScripts(HtmlTree head) { mainBodyScript.append("const pathtoroot = ") .appendStringLiteral(ptrPath + "/") .append(";\n") - .append("loadScripts(document, 'script');"); + .append("loadScripts();\n") + .append("initTheme();\n"); } addScriptElement(head, DocPaths.JQUERY_JS); addScriptElement(head, DocPaths.JQUERY_UI_JS); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index b275323b2f5..b91f99b2c42 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -11,12 +11,13 @@ var typeSearchIndex; var memberSearchIndex; var tagSearchIndex; -var oddRowColor = "odd-row-color"; -var evenRowColor = "even-row-color"; -var sortAsc = "sort-asc"; -var sortDesc = "sort-desc"; -var tableTab = "table-tab"; -var activeTableTab = "active-table-tab"; +const oddRowColor = "odd-row-color"; +const evenRowColor = "even-row-color"; +const sortAsc = "sort-asc"; +const sortDesc = "sort-desc"; +const tableTab = "table-tab"; +const activeTableTab = "active-table-tab"; +const THEMES = Object.freeze(["theme-light", "theme-dark", "theme-os"]); const linkIcon = "##REPLACE:doclet.Link_icon##"; const linkToSection = "##REPLACE:doclet.Link_to_section##"; @@ -30,21 +31,20 @@ if (typeof hljs !== "undefined") { } } -function loadScripts(doc, tag) { - createElem(doc, tag, 'script-files/search.js'); - - createElem(doc, tag, 'module-search-index.js'); - createElem(doc, tag, 'package-search-index.js'); - createElem(doc, tag, 'type-search-index.js'); - createElem(doc, tag, 'member-search-index.js'); - createElem(doc, tag, 'tag-search-index.js'); +function loadScripts() { + createScript('script-files/search.js'); + createScript('module-search-index.js'); + createScript('package-search-index.js'); + createScript('type-search-index.js'); + createScript('member-search-index.js'); + createScript('tag-search-index.js'); } -function createElem(doc, tag, path) { - var script = doc.createElement(tag); - var scriptElement = doc.getElementsByTagName(tag)[0]; +function createScript(path) { + var script = document.createElement("script"); script.src = pathtoroot + path; - scriptElement.parentNode.insertBefore(script, scriptElement); + var firstScript = document.getElementsByTagName("script")[0]; + firstScript.parentNode.insertBefore(script, firstScript); } // Helper for making content containing release names comparable lexicographically @@ -312,21 +312,31 @@ function makeFilterWidget(sidebar, updateToc) { return sidebar; } +function getTheme() { + return localStorage.getItem('theme') || THEMES[0]; +} + +function initTheme() { + document.body.classList.add(getTheme()); +} + function setTopMargin() { // Dynamically set scroll margin to accomodate for draft header var headerHeight = Math.ceil(document.querySelector("header").offsetHeight); document.querySelector(":root") .style.setProperty("--nav-height", headerHeight + "px"); } + document.addEventListener("readystatechange", (e) => { if (document.readyState === "interactive") { setTopMargin(); - } - if (sessionStorage.getItem("sidebar") === "hidden") { - const sidebar = document.querySelector(".main-grid nav.toc"); - if (sidebar) sidebar.classList.add("hide-sidebar"); + if (sessionStorage.getItem("sidebar") === "hidden") { + const sidebar = document.querySelector(".main-grid nav.toc"); + if (sidebar) sidebar.classList.add("hide-sidebar"); + } } }); + document.addEventListener("DOMContentLoaded", function(e) { setTopMargin(); const subnav = document.querySelector("ol.sub-nav-list"); @@ -375,13 +385,16 @@ document.addEventListener("DOMContentLoaded", function(e) { themePanelVisible = false; } } + var currentTheme = getTheme(); themePanel.querySelectorAll("input").forEach(input => { input.removeAttribute("disabled"); + if (input.id === currentTheme) { + input.checked = true; + } input.addEventListener("change", e => { setTheme(e.target.value); }) }); - const THEMES = ["theme-light", "theme-dark", "theme-os"]; function setTheme(theme) { THEMES.forEach(t => { if (t !== theme) document.body.classList.remove(t); @@ -390,7 +403,6 @@ document.addEventListener("DOMContentLoaded", function(e) { localStorage.setItem("theme", theme); document.getElementById(theme).checked = true; } - setTheme(localStorage.getItem("theme") || THEMES[0]); makeFilterWidget(sidebar, updateToc); if (tocMenu) { navbar.appendChild(tocMenu); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index d61283dc677..4bb0fad4306 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -73,7 +73,7 @@ body { --selected-link-color: #4a698a; /* Background colors for generated tables */ --table-header-color: #ebeff4; - --even-row-color: #ffffff; + --even-row-color: #fdfdfe; --odd-row-color: #f0f0f2; /* Text color for page title */ --title-color: #2c4557; @@ -109,17 +109,19 @@ body { /* Colors for invalid tag notifications */ --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; + --icon-filter: none; + --caption-link-color: var(--subnav-link-color); } body.theme-dark { --body-text-color: #e8e8e8; --block-text-color: #e8e8e8; - --body-background-color: #222528; + --body-background-color: #1f2124; --section-background-color: var(--body-background-color); --detail-background-color: var(--body-background-color); --code-background-color: #303940; --mark-background-color: #313131; - --detail-block-color: #f4f4f4; + --detail-block-color: #31363c; --navbar-background-color: #395A6F; --navbar-text-color: #ffffff; --subnav-background-color: #3d454d; @@ -133,11 +135,11 @@ body.theme-dark { --odd-row-color: #2d3135; --title-color: #fff; --link-color: #94badb; - --link-color-active: #ffb45b; - --toc-background-color: #31363c; + --link-color-active: #e8a351; + --toc-background-color: #2f3439; --toc-highlight-color: var(--subnav-background-color); --toc-hover-color: #3f4146; - --snippet-background-color: #2d363c; + --snippet-background-color: #2c353b; --snippet-text-color: var(--block-text-color); --snippet-highlight-color: #f7c590; --pre-background-color: var(--snippet-background-color); @@ -155,10 +157,8 @@ body.theme-dark { --button-focus-filter: brightness(104%); --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; - div.main-grid img, - .inherited-list h3 > button { - filter: invert(100%) brightness(160%); - } + --icon-filter: invert(100%) brightness(160%); + --caption-link-color: var(--link-color); } /* @@ -168,12 +168,12 @@ body.theme-dark { body { --body-text-color: #e8e8e8; --block-text-color: #e8e8e8; - --body-background-color: #222528; + --body-background-color: #1f2124; --section-background-color: var(--body-background-color); --detail-background-color: var(--body-background-color); --code-background-color: #303940; --mark-background-color: #313131; - --detail-block-color: #f4f4f4; + --detail-block-color: #31363c; --navbar-background-color: #395A6F; --navbar-text-color: #ffffff; --subnav-background-color: #3d454d; @@ -187,11 +187,11 @@ body.theme-dark { --odd-row-color: #2d3135; --title-color: #fff; --link-color: #94badb; - --link-color-active: #ffb45b; - --toc-background-color: #31363c; + --link-color-active: #e8a351; + --toc-background-color: #2f3439; --toc-highlight-color: var(--subnav-background-color); --toc-hover-color: #3f4146; - --snippet-background-color: #2d363c; + --snippet-background-color: #2c353b; --snippet-text-color: var(--block-text-color); --snippet-highlight-color: #f7c590; --pre-background-color: var(--snippet-background-color); @@ -209,15 +209,13 @@ body.theme-dark { --button-focus-filter: brightness(104%); --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; - div.main-grid img, - .inherited-list h3 > button { - filter: invert(100%) brightness(160%); - } + --icon-filter: invert(100%) brightness(160%); + --caption-link-color: var(--link-color); } body.theme-light { - --body-text-color: #282828; - --block-text-color: #282828; + --body-text-color: #181818; + --block-text-color: #181818; --body-background-color: #ffffff; --section-background-color: var(--body-background-color); --detail-background-color: var(--body-background-color); @@ -233,7 +231,7 @@ body.theme-dark { --selected-text-color: #253441; --selected-link-color: #4a698a; --table-header-color: #ebeff4; - --even-row-color: #ffffff; + --even-row-color: #fdfdfe; --odd-row-color: #f0f0f2; --title-color: #2c4557; --link-color: #437291; @@ -259,10 +257,8 @@ body.theme-dark { --button-focus-filter: brightness(104%); --invalid-tag-background-color: #ffe6e6; --invalid-tag-text-color: #000000; - div.main-grid img, - .inherited-list h3 > button { - filter: none; - } + --icon-filter: none; + --caption-link-color: var(--subnav-link-color); } } /* @@ -288,6 +284,9 @@ div.main-grid { max-width: var(--max-content-width); margin: var(--content-margin); } +div.main-grid img { + filter: var(--icon-filter); +} a:link, a:visited { text-decoration:none; color:var(--link-color); @@ -909,12 +908,12 @@ ul.preview-feature-list input { .caption a:visited, .inherited-list h3 a:link, .inherited-list h3 a:visited { - color:var(--subnav-link-color); + color:var(--caption-link-color); } .caption a:hover, .caption a:active, -.inherited-list.expanded h3 a:hover, -.inherited-list.expanded h3 a:active { +.inherited-list h3 a:hover, +.inherited-list h3 a:active { color: var(--link-color-active); } div.table-tabs { @@ -1539,6 +1538,7 @@ section[class$="-details"] .detail > div { height: 1.6em; vertical-align: middle; top: -2px; + filter: var(--icon-filter); } .inherited-list h3:has(button) { padding-left: 2px; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java index 32bcab0eef5..d16c47dd59f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java @@ -462,6 +462,7 @@ private static String diff(String inline, String external) { %s ----------------- external ----------------- %s + -------------------------------------------- """.formatted(inline, external); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java index e574ab47992..22d55e6e99f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java @@ -291,7 +291,7 @@ private byte[] getBinaryRepresentation() { } } - synchronized boolean isEnabled(String eventName) { + boolean isEnabled(String eventName) { return settingsManager.isEnabled(eventName); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/SettingsManager.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/SettingsManager.java index 84caf7cb460..bd8fa078dc8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/SettingsManager.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/SettingsManager.java @@ -129,7 +129,7 @@ public void finish() { } } - private Map availableSettings = new LinkedHashMap<>(); + private volatile Map availableSettings = new LinkedHashMap<>(); void setSettings(List> activeSettings, boolean writeSettingEvents) { // store settings so they are available if a new event class is loaded diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryPrinter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryPrinter.java index 0d0310dae5b..9d0ce279abd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryPrinter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryPrinter.java @@ -280,12 +280,14 @@ public static String getGrammarText() { MEDIAN: The numeric median MIN: The numeric minimum P90, P95, P99, P999: The numeric percentile, 90%, 95%, 99% or 99.9% + SET: All unique values in a comma-separated list STDEV: The numeric standard deviation SUM: The numeric sum UNIQUE: The unique number of occurrences of a value Null values are included, but ignored for numeric functions. If no aggregator function is specified, the first non-null value is used. - property, any of the following: + none No formatting for the column cell-height: Maximum height of a table cell missing:whitespace Replace missing values (N/A) with blank space normalized Normalize values between 0 and 1.0 for the column 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 1ab9840b28e..91decb1aa20 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 @@ -290,18 +290,16 @@ table = "SELECT finalizableClass, LAST_BATCH(objects) AS O, LAST_BATCH(totalFina [jvm.gc] label = "Garbage Collections" -table = "COLUMN 'Start', 'GC ID', 'Type', 'Heap Before GC', 'Heap After GC', 'Longest Pause' +table = "COLUMN 'Start', 'GC ID', 'GC Name', 'Heap Before GC', 'Heap After GC', 'Longest Pause' FORMAT none, none, missing:Unknown, none, none, none - SELECT G.startTime, gcId, [Y|O].eventType.label, + SELECT G.startTime, gcId, G.name, B.heapUsed, A.heapUsed, longestPause FROM GarbageCollection AS G, GCHeapSummary AS B, - GCHeapSummary AS A, - OldGarbageCollection AS O, - YoungGarbageCollection AS Y + GCHeapSummary AS A WHERE B.when = 'Before GC' AND A.when = 'After GC' - GROUP BY gcId ORDER BY G.startTime" + GROUP BY gcId ORDER BY gcId" [jvm.gc-concurrent-phases] label = "Concurrent GC Phases" diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Query.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Query.java index d350b4215bf..ec0407a6f04 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Query.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Query.java @@ -73,27 +73,26 @@ public void displayOptionUsage(PrintStream p) { p.println(); p.println(" $ jfr query --verbose \"SELECT * FROM ObjectAllocationSample\" recording.jfr"); p.println(); - p.println(" $ jfr query --width 160 \"SELECT pid, path FROM SystemProcess\" recording.jfr"); + p.println(" $ jfr query --width 160 \"SELECT pid, commandLine FROM SystemProcess\" recording.jfr"); p.println(); p.println(" $ jfr query \"SELECT stackTrace.topFrame AS T, SUM(weight)"); p.println(" FROM ObjectAllocationSample GROUP BY T\" recording.jfr"); p.println(); - p.println("$ jfr JFR.query \"COLUMN 'Method', 'Percentage'"); - p.println(" FORMAT default, normalized;width:10"); - p.println(" SELECT stackTrace.topFrame AS T, COUNT(*) AS C"); - p.println(" GROUP BY T"); - p.println(" FROM ExecutionSample ORDER BY C DESC\" recording.jfr"); + p.println(" $ jfr query \"COLUMN 'Method', 'Percentage'"); + p.println(" FORMAT none, normalized"); + p.println(" SELECT stackTrace.topFrame AS T, COUNT(*) AS C"); + p.println(" FROM ExecutionSample GROUP BY T ORDER BY C DESC\" recording.jfr"); p.println(); - p.println("$ jcmd JFR.query \"COLUMN 'Start', 'GC ID', 'Heap Before GC',"); - p.println(" 'Heap After GC', 'Longest Pause'"); - p.println(" SELECT G.startTime, G.gcId, B.heapUsed,"); - p.println(" A.heapUsed, longestPause"); - p.println(" FROM GarbageCollection AS G,"); - p.println(" GCHeapSummary AS B,"); - p.println(" GCHeapSummary AS A"); - p.println(" WHERE B.when = 'Before GC' AND A.when = 'After GC'"); - p.println(" GROUP BY gcId"); - p.println(" ORDER BY G.startTime\" recording.jfr"); + p.println(" $ jfr query \"COLUMN 'Start', 'GC ID', 'Heap Before GC',"); + p.println(" 'Heap After GC', 'Longest Pause'"); + p.println(" SELECT G.startTime, G.gcId, B.heapUsed,"); + p.println(" A.heapUsed, longestPause"); + p.println(" FROM GarbageCollection AS G,"); + p.println(" GCHeapSummary AS B,"); + p.println(" GCHeapSummary AS A"); + p.println(" WHERE B.when = 'Before GC' AND A.when = 'After GC'"); + p.println(" GROUP BY gcId"); + p.println(" ORDER BY gcId\" recording.jfr"); p.println(); p.println("************************************ WARNING ******************************************"); p.println("The query command is only available in debug builds and is targeted towards OpenJDK"); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 2d0c78c2474..790d5d877aa 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -31,6 +31,7 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; @@ -67,7 +68,7 @@ final class DesktopIntegration extends ShellCustomAction { private static final List REPLACEMENT_STRING_IDS = List.of( COMMANDS_INSTALL, COMMANDS_UNINSTALL, SCRIPTS, COMMON_SCRIPTS); - private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launcher) throws IOException { + private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launcher) { associations = launcher.fileAssociations().stream().map( LinuxFileAssociation::create).toList(); @@ -88,10 +89,14 @@ private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launche // This is additional launcher with explicit `no icon` configuration. withDesktopFile = false; } else { - final Path nullPath = null; - if (curIconResource.get().saveToFile(nullPath) != OverridableResource.Source.DefaultResource) { - // This launcher has custom icon configured. - withDesktopFile = true; + try { + if (curIconResource.get().saveToFile((Path)null) != OverridableResource.Source.DefaultResource) { + // This launcher has custom icon configured. + withDesktopFile = true; + } + } catch (IOException ex) { + // Should never happen as `saveToFile((Path)null)` should not perform any actual I/O operations. + throw new UncheckedIOException(ex); } } @@ -135,13 +140,13 @@ private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launche return (LinuxLauncher)v; }).filter(l -> { return toRequest(l.shortcut()).orElse(true); - }).map(toFunction(l -> { + }).map(l -> { return new DesktopIntegration(env, pkg, l); - })).toList(); + }).toList(); } } - static ShellCustomAction create(BuildEnv env, Package pkg) throws IOException { + static ShellCustomAction create(BuildEnv env, Package pkg) { if (pkg.isRuntimeInstaller()) { return ShellCustomAction.nop(REPLACEMENT_STRING_IDS); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index d5b369ba23a..9e2ea63cc32 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -25,362 +25,19 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.LinuxPackage; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LinuxDebPackage; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; - -import java.nio.file.attribute.PosixFilePermission; -import java.nio.file.attribute.PosixFilePermissions; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.model.AppImageLayout; -import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import jdk.jpackage.internal.model.LinuxDebPackage; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.StandardPackageType; +import jdk.jpackage.internal.util.Result; public class LinuxDebBundler extends LinuxPackageBundler { - private static final String TOOL_DPKG_DEB = "dpkg-deb"; - private static final String TOOL_DPKG = "dpkg"; - private static final String TOOL_FAKEROOT = "fakeroot"; - public LinuxDebBundler() { super(LinuxFromParams.DEB_PACKAGE); } - @Override - protected void doValidate(BuildEnv env, LinuxPackage pkg) throws ConfigException { - - // Show warning if license file is missing - if (pkg.licenseFile().isEmpty()) { - Log.verbose(I18N.getString("message.debs-like-licenses")); - } - } - - @Override - protected List getToolValidators() { - return Stream.of(TOOL_DPKG_DEB, TOOL_DPKG, TOOL_FAKEROOT).map( - ToolValidator::new).toList(); - } - - @Override - protected void createConfigFiles(Map replacementData, - BuildEnv env, LinuxPackage pkg) throws IOException { - prepareProjectConfig(replacementData, env, pkg); - adjustPermissionsRecursive(env.appImageDir()); - } - - @Override - protected Path buildPackageBundle(BuildEnv env, LinuxPackage pkg, - Path outputParentDir) throws PackagerException, IOException { - return buildDeb(env, pkg, outputParentDir); - } - - private static final Pattern PACKAGE_NAME_REGEX = Pattern.compile("^(^\\S+):"); - - @Override - protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) { - - libProvidersLookup.setPackageLookup(file -> { - Path realPath = file.toRealPath(); - - try { - // Try the real path first as it works better on newer Ubuntu versions - return findProvidingPackages(realPath); - } catch (IOException ex) { - // Try the default path if differ - if (!realPath.toString().equals(file.toString())) { - return findProvidingPackages(file); - } else { - throw ex; - } - } - }); - } - - private static Stream findProvidingPackages(Path file) throws IOException { - // - // `dpkg -S` command does glob pattern lookup. If not the absolute path - // to the file is specified it might return mltiple package names. - // Even for full paths multiple package names can be returned as - // it is OK for multiple packages to provide the same file. `/opt` - // directory is such an example. So we have to deal with multiple - // packages per file situation. - // - // E.g.: `dpkg -S libc.so.6` command reports three packages: - // libc6-x32: /libx32/libc.so.6 - // libc6:amd64: /lib/x86_64-linux-gnu/libc.so.6 - // libc6-i386: /lib32/libc.so.6 - // `:amd64` is architecture suffix and can (should) be dropped. - // Still need to decide what package to choose from three. - // libc6-x32 and libc6-i386 both depend on libc6: - // $ dpkg -s libc6-x32 - // Package: libc6-x32 - // Status: install ok installed - // Priority: optional - // Section: libs - // Installed-Size: 10840 - // Maintainer: Ubuntu Developers - // Architecture: amd64 - // Source: glibc - // Version: 2.23-0ubuntu10 - // Depends: libc6 (= 2.23-0ubuntu10) - // - // We can dive into tracking dependencies, but this would be overly - // complicated. - // - // For simplicity lets consider the following rules: - // 1. If there is one item in `dpkg -S` output, accept it. - // 2. If there are multiple items in `dpkg -S` output and there is at - // least one item with the default arch suffix (DEB_ARCH), - // accept only these items. - // 3. If there are multiple items in `dpkg -S` output and there are - // no with the default arch suffix (DEB_ARCH), accept all items. - // So lets use this heuristics: don't accept packages for whom - // `dpkg -p` command fails. - // 4. Arch suffix should be stripped from accepted package names. - // - - Set archPackages = new HashSet<>(); - Set otherPackages = new HashSet<>(); - - var debArch = LinuxPackageArch.getValue(LINUX_DEB); - - Executor.of(TOOL_DPKG, "-S", file.toString()) - .saveOutput(true).executeExpectSuccess() - .getOutput().forEach(line -> { - Matcher matcher = PACKAGE_NAME_REGEX.matcher(line); - if (matcher.find()) { - String name = matcher.group(1); - if (name.endsWith(":" + debArch)) { - // Strip arch suffix - name = name.substring(0, - name.length() - (debArch.length() + 1)); - archPackages.add(name); - } else { - otherPackages.add(name); - } - } - }); - - if (!archPackages.isEmpty()) { - return archPackages.stream(); - } - return otherPackages.stream(); - } - - @Override - protected List verifyOutputBundle(BuildEnv env, LinuxPackage pkg, - Path packageBundle) { - List errors = new ArrayList<>(); - - String controlFileName = "control"; - - List properties = List.of( - new PackageProperty("Package", pkg.packageName(), - "APPLICATION_PACKAGE", controlFileName), - new PackageProperty("Version", ((LinuxDebPackage)pkg).versionWithRelease(), - "APPLICATION_VERSION_WITH_RELEASE", - controlFileName), - new PackageProperty("Architecture", pkg.arch(), "APPLICATION_ARCH", controlFileName)); - - List cmdline = new ArrayList<>(List.of(TOOL_DPKG_DEB, "-f", - packageBundle.toString())); - properties.forEach(property -> cmdline.add(property.name)); - try { - Map actualValues = Executor.of(cmdline.toArray(String[]::new)) - .saveOutput(true) - .executeExpectSuccess() - .getOutput().stream() - .map(line -> line.split(":\\s+", 2)) - .collect(Collectors.toMap( - components -> components[0], - components -> components[1])); - properties.forEach(property -> errors.add(property.verifyValue( - actualValues.get(property.name)))); - } catch (IOException ex) { - // Ignore error as it is not critical. Just report it. - Log.verbose(ex); - } - - return errors; - } - - /* - * set permissions with a string like "rwxr-xr-x" - * - * This cannot be directly backport to 22u which is built with 1.6 - */ - private void setPermissions(Path file, String permissions) { - Set filePermissions = - PosixFilePermissions.fromString(permissions); - try { - if (Files.exists(file)) { - Files.setPosixFilePermissions(file, filePermissions); - } - } catch (IOException ex) { - Log.error(ex.getMessage()); - Log.verbose(ex); - } - - } - - public static boolean isDebian() { - // we are just going to run "dpkg -s coreutils" and assume Debian - // or deritive if no error is returned. - try { - Executor.of(TOOL_DPKG, "-s", "coreutils").executeExpectSuccess(); - return true; - } catch (IOException e) { - // just fall thru - } - return false; - } - - private void adjustPermissionsRecursive(Path dir) throws IOException { - Files.walkFileTree(dir, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attrs) - throws IOException { - if (file.endsWith(".so") || !Files.isExecutable(file)) { - setPermissions(file, "rw-r--r--"); - } else if (Files.isExecutable(file)) { - setPermissions(file, "rwxr-xr-x"); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException e) - throws IOException { - if (e == null) { - setPermissions(dir, "rwxr-xr-x"); - return FileVisitResult.CONTINUE; - } else { - // directory iteration failed - throw e; - } - } - }); - } - - private class DebianFile { - - DebianFile(Path dstFilePath, String comment) { - this.dstFilePath = dstFilePath; - this.comment = comment; - } - - DebianFile setExecutable() { - permissions = "rwxr-xr-x"; - return this; - } - - void create(Map data, Function resourceFactory) - throws IOException { - resourceFactory.apply("template." + dstFilePath.getFileName().toString()) - .setCategory(I18N.getString(comment)) - .setSubstitutionData(data) - .saveToFile(dstFilePath); - if (permissions != null) { - setPermissions(dstFilePath, permissions); - } - } - - private final Path dstFilePath; - private final String comment; - private String permissions; - } - - private void prepareProjectConfig(Map data, BuildEnv env, LinuxPackage pkg) throws IOException { - - Path configDir = env.appImageDir().resolve("DEBIAN"); - List debianFiles = new ArrayList<>(); - debianFiles.add(new DebianFile( - configDir.resolve("control"), - "resource.deb-control-file")); - debianFiles.add(new DebianFile( - configDir.resolve("preinst"), - "resource.deb-preinstall-script").setExecutable()); - debianFiles.add(new DebianFile( - configDir.resolve("prerm"), - "resource.deb-prerm-script").setExecutable()); - debianFiles.add(new DebianFile( - configDir.resolve("postinst"), - "resource.deb-postinstall-script").setExecutable()); - debianFiles.add(new DebianFile( - configDir.resolve("postrm"), - "resource.deb-postrm-script").setExecutable()); - - ((LinuxDebPackage)pkg).relativeCopyrightFilePath().ifPresent(copyrightFile -> { - debianFiles.add(new DebianFile(env.appImageDir().resolve(copyrightFile), - "resource.copyright-file")); - }); - - for (DebianFile debianFile : debianFiles) { - debianFile.create(data, env::createResource); - } - } - - @Override - protected Map createReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException { - Map data = new HashMap<>(); - - String licenseText = pkg.licenseFile().map(toFunction(Files::readString)).orElse("Unknown"); - - data.put("APPLICATION_MAINTAINER", ((LinuxDebPackage) pkg).maintainer()); - data.put("APPLICATION_SECTION", pkg.category().orElseThrow()); - data.put("APPLICATION_COPYRIGHT", pkg.app().copyright()); - data.put("APPLICATION_LICENSE_TEXT", licenseText); - data.put("APPLICATION_ARCH", pkg.arch()); - data.put("APPLICATION_INSTALLED_SIZE", Long.toString( - AppImageLayout.toPathGroup(env.appImageLayout()).sizeInBytes() >> 10)); - data.put("APPLICATION_HOMEPAGE", pkg.aboutURL().map( - value -> "Homepage: " + value).orElse("")); - data.put("APPLICATION_VERSION_WITH_RELEASE", ((LinuxDebPackage) pkg).versionWithRelease()); - - return data; - } - - private Path buildDeb(BuildEnv env, LinuxPackage pkg, Path outdir) throws IOException { - Path outFile = outdir.resolve(pkg.packageFileNameWithSuffix()); - Log.verbose(I18N.format("message.outputting-to-location", outFile.toAbsolutePath())); - - List cmdline = new ArrayList<>(); - cmdline.addAll(List.of(TOOL_FAKEROOT, TOOL_DPKG_DEB)); - if (Log.isVerbose()) { - cmdline.add("--verbose"); - } - cmdline.addAll(List.of("-b", env.appImageDir().toString(), - outFile.toAbsolutePath().toString())); - - // run dpkg - RetryExecutor.retryOnKnownErrorMessage( - "semop(1): encountered an error: Invalid argument").execute( - cmdline.toArray(String[]::new)); - - Log.verbose(I18N.format("message.output-to-location", outFile.toAbsolutePath())); - - return outFile; - } - @Override public String getName() { return I18N.getString("deb.bundler.name"); @@ -392,12 +49,28 @@ public String getID() { } @Override - public boolean supported(boolean runtimeInstaller) { - return OperatingSystem.isLinux() && (new ToolValidator(TOOL_DPKG_DEB).validate() == null); + public Path execute(Map params, Path outputParentDir) throws PackagerException { + + return Packager.build().outputDir(outputParentDir) + .pkg(LinuxFromParams.DEB_PACKAGE.fetchFrom(params)) + .env(BuildEnvFromParams.BUILD_ENV.fetchFrom(params)) + .pipelineBuilderMutatorFactory((env, pkg, outputDir) -> { + return new LinuxDebPackager(env, pkg, outputDir, sysEnv.orElseThrow()); + }).execute(LinuxPackagingPipeline.build()); + } + + @Override + protected Result sysEnv() { + return sysEnv; } @Override public boolean isDefault() { - return isDebian(); + return sysEnv.value() + .map(LinuxSystemEnvironment::nativePackageType) + .map(StandardPackageType.LINUX_DEB::equals) + .orElse(false); } + + private final Result sysEnv = LinuxDebSystemEnvironment.create(SYS_ENV); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java new file mode 100644 index 00000000000..64a0368e9a0 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2012, 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.jpackage.internal; + +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; +import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxDebPackage; + +final class LinuxDebPackager extends LinuxPackager { + + LinuxDebPackager(BuildEnv env, LinuxDebPackage pkg, Path outputDir, LinuxDebSystemEnvironment sysEnv) { + super(env, pkg, outputDir, sysEnv); + this.sysEnv = Objects.requireNonNull(sysEnv); + } + + @Override + protected void createConfigFiles(Map replacementData) throws IOException { + prepareProjectConfig(replacementData); + adjustPermissionsRecursive(); + } + + @Override + protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) { + + libProvidersLookup.setPackageLookup(file -> { + Path realPath = file.toRealPath(); + + try { + // Try the real path first as it works better on newer Ubuntu versions + return findProvidingPackages(realPath, sysEnv.dpkg()); + } catch (IOException ex) { + // Try the default path if differ + if (!realPath.equals(file)) { + return findProvidingPackages(file, sysEnv.dpkg()); + } else { + throw ex; + } + } + }); + } + + @Override + protected List findErrorsInOutputPackage() throws IOException { + List errors = new ArrayList<>(); + + var controlFileName = "control"; + + List properties = List.of( + new PackageProperty("Package", pkg.packageName(), + "APPLICATION_PACKAGE", controlFileName), + new PackageProperty("Version", pkg.versionWithRelease(), + "APPLICATION_VERSION_WITH_RELEASE", + controlFileName), + new PackageProperty("Architecture", pkg.arch(), "APPLICATION_ARCH", controlFileName)); + + List cmdline = new ArrayList<>(List.of( + sysEnv.dpkgdeb().toString(), "-f", outputPackageFile().toString())); + + properties.forEach(property -> cmdline.add(property.name)); + + Map actualValues = Executor.of(cmdline.toArray(String[]::new)) + .saveOutput(true) + .executeExpectSuccess() + .getOutput().stream() + .map(line -> line.split(":\\s+", 2)) + .collect(Collectors.toMap( + components -> components[0], + components -> components[1])); + + for (var property : properties) { + Optional.ofNullable(property.verifyValue(actualValues.get(property.name))).ifPresent(errors::add); + } + + return errors; + } + + @Override + protected Map createReplacementData() throws IOException { + Map data = new HashMap<>(); + + String licenseText = pkg.licenseFile().map(toFunction(Files::readString)).orElse("Unknown"); + + data.put("APPLICATION_MAINTAINER", pkg.maintainer()); + data.put("APPLICATION_SECTION", pkg.category().orElseThrow()); + data.put("APPLICATION_COPYRIGHT", pkg.app().copyright()); + data.put("APPLICATION_LICENSE_TEXT", licenseText); + data.put("APPLICATION_ARCH", pkg.arch()); + data.put("APPLICATION_INSTALLED_SIZE", Long.toString( + AppImageLayout.toPathGroup(env.appImageLayout()).sizeInBytes() >> 10)); + data.put("APPLICATION_HOMEPAGE", pkg.aboutURL().map( + value -> "Homepage: " + value).orElse("")); + data.put("APPLICATION_VERSION_WITH_RELEASE", pkg.versionWithRelease()); + + return data; + } + + @Override + protected void buildPackage() throws IOException { + + Path debFile = outputPackageFile(); + + Log.verbose(I18N.format("message.outputting-to-location", debFile.toAbsolutePath())); + + List cmdline = new ArrayList<>(); + Stream.of(sysEnv.fakeroot(), sysEnv.dpkgdeb()).map(Path::toString).forEach(cmdline::add); + if (Log.isVerbose()) { + cmdline.add("--verbose"); + } + cmdline.addAll(List.of("-b", env.appImageDir().toString(), debFile.toAbsolutePath().toString())); + + // run dpkg + RetryExecutor.retryOnKnownErrorMessage( + "semop(1): encountered an error: Invalid argument").execute( + cmdline.toArray(String[]::new)); + + Log.verbose(I18N.format("message.output-to-location", debFile.toAbsolutePath())); + } + + @Override + public void accept(PackagingPipeline.Builder pipelineBuilder) { + super.accept(pipelineBuilder); + + // Build deb config files after app image contents are ready because + // it calculates the size of the image and saves the value in one of the config files. + pipelineBuilder.configuredTasks().filter(task -> { + return PackageTaskID.CREATE_CONFIG_FILES.equals(task.task()); + }).findFirst().orElseThrow() + .addDependencies(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE) + .add(); + } + + private void adjustPermissionsRecursive() throws IOException { + Files.walkFileTree(env.appImageDir(), new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (file.endsWith(".so") || !Files.isExecutable(file)) { + Files.setPosixFilePermissions(file, SO_PERMISSIONS); + } else if (Files.isExecutable(file)) { + Files.setPosixFilePermissions(file, EXECUTABLE_PERMISSIONS); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException { + if (e == null) { + Files.setPosixFilePermissions(dir, FOLDER_PERMISSIONS); + return FileVisitResult.CONTINUE; + } else { + // directory iteration failed + throw e; + } + } + }); + } + + private void prepareProjectConfig(Map data) throws IOException { + + Path configDir = env.appImageDir().resolve("DEBIAN"); + List debianFiles = new ArrayList<>(); + debianFiles.add(new DebianFile( + configDir.resolve("control"), + "resource.deb-control-file")); + debianFiles.add(new DebianFile( + configDir.resolve("preinst"), + "resource.deb-preinstall-script").setExecutable()); + debianFiles.add(new DebianFile( + configDir.resolve("prerm"), + "resource.deb-prerm-script").setExecutable()); + debianFiles.add(new DebianFile( + configDir.resolve("postinst"), + "resource.deb-postinstall-script").setExecutable()); + debianFiles.add(new DebianFile( + configDir.resolve("postrm"), + "resource.deb-postrm-script").setExecutable()); + + pkg.relativeCopyrightFilePath().ifPresent(copyrightFile -> { + debianFiles.add(new DebianFile(env.appImageDir().resolve(copyrightFile), + "resource.copyright-file")); + }); + + for (DebianFile debianFile : debianFiles) { + debianFile.create(data, env::createResource); + } + } + + private static Stream findProvidingPackages(Path file, Path dpkg) throws IOException { + // + // `dpkg -S` command does glob pattern lookup. If not the absolute path + // to the file is specified it might return mltiple package names. + // Even for full paths multiple package names can be returned as + // it is OK for multiple packages to provide the same file. `/opt` + // directory is such an example. So we have to deal with multiple + // packages per file situation. + // + // E.g.: `dpkg -S libc.so.6` command reports three packages: + // libc6-x32: /libx32/libc.so.6 + // libc6:amd64: /lib/x86_64-linux-gnu/libc.so.6 + // libc6-i386: /lib32/libc.so.6 + // `:amd64` is architecture suffix and can (should) be dropped. + // Still need to decide what package to choose from three. + // libc6-x32 and libc6-i386 both depend on libc6: + // $ dpkg -s libc6-x32 + // Package: libc6-x32 + // Status: install ok installed + // Priority: optional + // Section: libs + // Installed-Size: 10840 + // Maintainer: Ubuntu Developers + // Architecture: amd64 + // Source: glibc + // Version: 2.23-0ubuntu10 + // Depends: libc6 (= 2.23-0ubuntu10) + // + // We can dive into tracking dependencies, but this would be overly + // complicated. + // + // For simplicity lets consider the following rules: + // 1. If there is one item in `dpkg -S` output, accept it. + // 2. If there are multiple items in `dpkg -S` output and there is at + // least one item with the default arch suffix (DEB_ARCH), + // accept only these items. + // 3. If there are multiple items in `dpkg -S` output and there are + // no with the default arch suffix (DEB_ARCH), accept all items. + // So lets use this heuristics: don't accept packages for whom + // `dpkg -p` command fails. + // 4. Arch suffix should be stripped from accepted package names. + // + + Set archPackages = new HashSet<>(); + Set otherPackages = new HashSet<>(); + + var debArch = LinuxPackageArch.getValue(LINUX_DEB); + + Executor.of(dpkg.toString(), "-S", file.toString()) + .saveOutput(true).executeExpectSuccess() + .getOutput().forEach(line -> { + Matcher matcher = PACKAGE_NAME_REGEX.matcher(line); + if (matcher.find()) { + String name = matcher.group(1); + if (name.endsWith(":" + debArch)) { + // Strip arch suffix + name = name.substring(0, + name.length() - (debArch.length() + 1)); + archPackages.add(name); + } else { + otherPackages.add(name); + } + } + }); + + if (!archPackages.isEmpty()) { + return archPackages.stream(); + } + return otherPackages.stream(); + } + + + private static final class DebianFile { + + DebianFile(Path dstFilePath, String comment) { + this.dstFilePath = Objects.requireNonNull(dstFilePath); + this.comment = Objects.requireNonNull(comment); + } + + DebianFile setExecutable() { + permissions = EXECUTABLE_PERMISSIONS; + return this; + } + + void create(Map data, Function resourceFactory) + throws IOException { + resourceFactory.apply("template." + dstFilePath.getFileName().toString()) + .setCategory(I18N.getString(comment)) + .setSubstitutionData(data) + .saveToFile(dstFilePath); + if (permissions != null) { + Files.setPosixFilePermissions(dstFilePath, permissions); + } + } + + private final Path dstFilePath; + private final String comment; + private Set permissions; + } + + + private final LinuxDebSystemEnvironment sysEnv; + + private static final Pattern PACKAGE_NAME_REGEX = Pattern.compile("^(^\\S+):"); + + private static final Set EXECUTABLE_PERMISSIONS = PosixFilePermissions.fromString("rwxr-xr-x"); + private static final Set FOLDER_PERMISSIONS = PosixFilePermissions.fromString("rwxr-xr-x"); + private static final Set SO_PERMISSIONS = PosixFilePermissions.fromString("rw-r--r--"); +} diff --git a/src/jdk.hotspot.agent/test/libproc/LibprocTest.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironment.java similarity index 56% rename from src/jdk.hotspot.agent/test/libproc/LibprocTest.java rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironment.java index a3e27a94ec0..5b5decb7a67 100644 --- a/src/jdk.hotspot.agent/test/libproc/LibprocTest.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironment.java @@ -1,10 +1,12 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * 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 @@ -19,23 +21,16 @@ * 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.jpackage.internal; + +import static jdk.jpackage.internal.LinuxSystemEnvironment.mixin; + +import jdk.jpackage.internal.util.Result; -/** - This is test case run by debuggee for running LibprocClient.java. -*/ +public interface LinuxDebSystemEnvironment extends LinuxSystemEnvironment, LinuxDebSystemEnvironmentMixin { -public class LibprocTest { - public static void main(String[] args) throws Exception { - String myStr = ""; - System.out.println("main start"); - synchronized(myStr) { - try { - myStr.wait(); - } catch (InterruptedException ee) { - } - } - System.out.println("main end"); - } + static Result create(Result base) { + return mixin(LinuxDebSystemEnvironment.class, base, LinuxDebSystemEnvironmentMixin::create); + } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironmentMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironmentMixin.java new file mode 100644 index 00000000000..8688327b353 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironmentMixin.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. 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.jpackage.internal; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.Result; + +public interface LinuxDebSystemEnvironmentMixin { + Path dpkg(); + Path dpkgdeb(); + Path fakeroot(); + + record Stub(Path dpkg, Path dpkgdeb, Path fakeroot) implements LinuxDebSystemEnvironmentMixin { + } + + static Result create() { + final var errors = Stream.of(Internal.TOOL_DPKG_DEB, Internal.TOOL_DPKG, Internal.TOOL_FAKEROOT) + .map(ToolValidator::new) + .map(ToolValidator::validate) + .filter(Objects::nonNull) + .toList(); + if (errors.isEmpty()) { + return Result.ofValue(new Stub(Internal.TOOL_DPKG, Internal.TOOL_DPKG_DEB, Internal.TOOL_FAKEROOT)); + } else { + return Result.ofErrors(errors); + } + } + + static final class Internal { + + private static final Path TOOL_DPKG_DEB = Path.of("dpkg-deb"); + private static final Path TOOL_DPKG = Path.of("dpkg"); + private static final Path TOOL_FAKEROOT = Path.of("fakeroot"); + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index ced77b1aa68..a8d109220dc 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -39,9 +39,10 @@ import java.util.Map; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxApplication; +import jdk.jpackage.internal.model.LinuxDebPackage; import jdk.jpackage.internal.model.LinuxLauncher; import jdk.jpackage.internal.model.LinuxLauncherMixin; -import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.LinuxRpmPackage; import jdk.jpackage.internal.model.StandardPackageType; final class LinuxFromParams { @@ -76,7 +77,7 @@ private static LinuxPackageBuilder createLinuxPackageBuilder( return pkgBuilder; } - private static LinuxPackage createLinuxRpmPackage( + private static LinuxRpmPackage createLinuxRpmPackage( Map params) throws ConfigException, IOException { final var superPkgBuilder = createLinuxPackageBuilder(params, LINUX_RPM); @@ -88,7 +89,7 @@ private static LinuxPackage createLinuxRpmPackage( return pkgBuilder.create(); } - private static LinuxPackage createLinuxDebPackage( + private static LinuxDebPackage createLinuxDebPackage( Map params) throws ConfigException, IOException { final var superPkgBuilder = createLinuxPackageBuilder(params, LINUX_DEB); @@ -97,16 +98,23 @@ private static LinuxPackage createLinuxDebPackage( MAINTAINER_EMAIL.copyInto(params, pkgBuilder::maintainerEmail); - return pkgBuilder.create(); + final var pkg = pkgBuilder.create(); + + // Show warning if license file is missing + if (pkg.licenseFile().isEmpty()) { + Log.verbose(I18N.getString("message.debs-like-licenses")); + } + + return pkg; } static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( LinuxFromParams::createLinuxApplication); - static final BundlerParamInfo RPM_PACKAGE = createPackageBundlerParam( + static final BundlerParamInfo RPM_PACKAGE = createPackageBundlerParam( LinuxFromParams::createLinuxRpmPackage); - static final BundlerParamInfo DEB_PACKAGE = createPackageBundlerParam( + static final BundlerParamInfo DEB_PACKAGE = createPackageBundlerParam( LinuxFromParams::createLinuxDebPackage); private static final BundlerParamInfo LINUX_SHORTCUT_HINT = createStringBundlerParam( diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java index 742f87b3a9f..b14404d67b1 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java @@ -38,7 +38,7 @@ */ public final class LinuxLaunchersAsServices extends UnixLaunchersAsServices { - private LinuxLaunchersAsServices(BuildEnv env, Package pkg) throws IOException { + private LinuxLaunchersAsServices(BuildEnv env, Package pkg) { super(env.appImageDir(), pkg.app(), REQUIRED_PACKAGES, launcher -> { return new LauncherImpl(env, pkg, launcher); }); @@ -58,7 +58,7 @@ protected Map createImpl() throws IOException { return data; } - static ShellCustomAction create(BuildEnv env, Package pkg) throws IOException { + static ShellCustomAction create(BuildEnv env, Package pkg) { if (pkg.isRuntimeInstaller()) { return ShellCustomAction.nop(LINUX_REPLACEMENT_STRING_IDS); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 2f3e6da1e69..1f674c0be11 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -24,33 +24,16 @@ */ package jdk.jpackage.internal; -import java.io.IOException; -import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.function.Predicate; -import java.util.stream.Stream; -import jdk.jpackage.internal.PackagingPipeline.PackageBuildEnv; -import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; -import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; -import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LinuxDebPackage; import jdk.jpackage.internal.model.LinuxPackage; -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.util.Result; abstract class LinuxPackageBundler extends AbstractBundler { LinuxPackageBundler(BundlerParamInfo pkgParam) { - this.pkgParam = pkgParam; - customActions = List.of(new CustomActionInstance( - DesktopIntegration::create), new CustomActionInstance( - LinuxLaunchersAsServices::create)); + this.pkgParam = Objects.requireNonNull(pkgParam); } @Override @@ -58,39 +41,32 @@ public final boolean validate(Map params) throws ConfigException { // Order is important! - LinuxPackage pkg = pkgParam.fetchFrom(params); - var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - - for (var validator: getToolValidators()) { - ConfigException ex = validator.validate(); - if (ex != null) { - throw ex; - } + pkgParam.fetchFrom(params); + BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + + LinuxSystemEnvironment sysEnv; + try { + sysEnv = sysEnv().orElseThrow(); + } catch (RuntimeException ex) { + throw ConfigException.rethrowConfigException(ex); } if (!isDefault()) { - withFindNeededPackages = false; - Log.verbose(MessageFormat.format(I18N.getString( - "message.not-default-bundler-no-dependencies-lookup"), + Log.verbose(I18N.format( + "message.not-default-bundler-no-dependencies-lookup", getName())); - } else { - withFindNeededPackages = LibProvidersLookup.supported(); - if (!withFindNeededPackages) { - final String advice; - if ("deb".equals(getID())) { - advice = "message.deb-ldd-not-available.advice"; - } else { - advice = "message.rpm-ldd-not-available.advice"; - } - // Let user know package dependencies will not be generated. - Log.error(String.format("%s\n%s", I18N.getString( - "message.ldd-not-available"), I18N.getString(advice))); + } else if (!sysEnv.soLookupAvailable()) { + final String advice; + if ("deb".equals(getID())) { + advice = "message.deb-ldd-not-available.advice"; + } else { + advice = "message.rpm-ldd-not-available.advice"; } + // Let user know package dependencies will not be generated. + Log.error(String.format("%s\n%s", I18N.getString( + "message.ldd-not-available"), I18N.getString(advice))); } - // Packaging specific validation - doValidate(env, pkg); - return true; } @@ -100,148 +76,13 @@ public final String getBundleType() { } @Override - public final Path execute(Map params, - Path outputParentDir) throws PackagerException { - IOUtils.writableOutputDir(outputParentDir); - - // Order is important! - final LinuxPackage pkg = pkgParam.fetchFrom(params); - final var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - - final var pipelineBuilder = LinuxPackagingPipeline.build() - .excludeDirFromCopying(outputParentDir) - .task(PackageTaskID.CREATE_PACKAGE_FILE) - .packageAction(this::buildPackage) - .add(); - - final var createConfigFilesTaskBuilder = pipelineBuilder - .task(PackageTaskID.CREATE_CONFIG_FILES) - .packageAction(this::buildConfigFiles); - - if (pkg instanceof LinuxDebPackage) { - // Build deb config files after app image contents are ready because - // it calculates the size of the image and saves the value in one of the config files. - createConfigFilesTaskBuilder.addDependencies(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE); - } - - createConfigFilesTaskBuilder.add(); - - pipelineBuilder.create().execute(env, pkg, outputParentDir); - - return outputParentDir.resolve(pkg.packageFileNameWithSuffix()).toAbsolutePath(); - } - - private void buildConfigFiles(PackageBuildEnv env) throws PackagerException, IOException { - for (var ca : customActions) { - ca.init(env.env(), env.pkg()); - } - - Map data = createDefaultReplacementData(env.env(), env.pkg()); - - for (var ca : customActions) { - ShellCustomAction.mergeReplacementData(data, ca.instance.create()); - } - - data.putAll(createReplacementData(env.env(), env.pkg())); - - createConfigFiles(Collections.unmodifiableMap(data), env.env(), env.pkg()); - } - - private void buildPackage(PackageBuildEnv env) throws PackagerException, IOException { - Path packageBundle = buildPackageBundle(env.env(), env.pkg(), env.outputDir()); - - verifyOutputBundle(env.env(), env.pkg(), packageBundle).stream() - .filter(Objects::nonNull) - .forEachOrdered(ex -> { - Log.verbose(ex.getLocalizedMessage()); - Log.verbose(ex.getAdvice()); - }); - } - - private List getListOfNeededPackages(BuildEnv env) throws IOException { - - final List caPackages = customActions.stream() - .map(ca -> ca.instance) - .map(ShellCustomAction::requiredPackages) - .flatMap(List::stream).toList(); - - final List neededLibPackages; - if (withFindNeededPackages) { - LibProvidersLookup lookup = new LibProvidersLookup(); - initLibProvidersLookup(lookup); - - neededLibPackages = lookup.execute(env.appImageDir()); - } else { - neededLibPackages = Collections.emptyList(); - Log.info(I18N.getString("warning.foreign-app-image")); - } - - // Merge all package lists together. - // Filter out empty names, sort and remove duplicates. - List result = Stream.of(caPackages, neededLibPackages).flatMap( - List::stream).filter(Predicate.not(String::isEmpty)).sorted().distinct().toList(); - - Log.verbose(String.format("Required packages: %s", result)); - - return result; - } - - private Map createDefaultReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException { - Map data = new HashMap<>(); - - data.put("APPLICATION_PACKAGE", pkg.packageName()); - data.put("APPLICATION_VENDOR", pkg.app().vendor()); - data.put("APPLICATION_VERSION", pkg.version()); - data.put("APPLICATION_DESCRIPTION", pkg.description()); - - String defaultDeps = String.join(", ", getListOfNeededPackages(env)); - String customDeps = pkg.additionalDependencies().orElse(""); - if (!customDeps.isEmpty() && !defaultDeps.isEmpty()) { - customDeps = ", " + customDeps; - } - data.put("PACKAGE_DEFAULT_DEPENDENCIES", defaultDeps); - data.put("PACKAGE_CUSTOM_DEPENDENCIES", customDeps); - - return data; + public boolean supported(boolean runtimeInstaller) { + return sysEnv().hasValue(); } - protected abstract List verifyOutputBundle( - BuildEnv env, LinuxPackage pkg, Path packageBundle); - - protected abstract void initLibProvidersLookup(LibProvidersLookup libProvidersLookup); - - protected abstract List getToolValidators(); - - protected abstract void doValidate(BuildEnv env, LinuxPackage pkg) - throws ConfigException; - - protected abstract Map createReplacementData( - BuildEnv env, LinuxPackage pkg) throws IOException; - - protected abstract void createConfigFiles( - Map replacementData, - BuildEnv env, LinuxPackage pkg) throws IOException; - - protected abstract Path buildPackageBundle( - BuildEnv env, LinuxPackage pkg, Path outputParentDir) throws - PackagerException, IOException; + protected abstract Result sysEnv(); private final BundlerParamInfo pkgParam; - private boolean withFindNeededPackages; - private final List customActions; - private static final class CustomActionInstance { - - CustomActionInstance(ShellCustomActionFactory factory) { - this.factory = factory; - } - - void init(BuildEnv env, Package pkg) throws IOException { - instance = factory.create(env, pkg); - Objects.requireNonNull(instance); - } - - private final ShellCustomActionFactory factory; - ShellCustomAction instance; - } + static final Result SYS_ENV = LinuxSystemEnvironment.create(); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java new file mode 100644 index 00000000000..806592904d1 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java @@ -0,0 +1,184 @@ +/* + * 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.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; +import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; +import jdk.jpackage.internal.PackagingPipeline.TaskID; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.PackagerException; + +abstract class LinuxPackager implements Consumer { + + LinuxPackager(BuildEnv env, T pkg, Path outputDir, LinuxSystemEnvironment sysEnv) { + this.env = Objects.requireNonNull(env); + this.pkg = Objects.requireNonNull(pkg); + this.outputDir = Objects.requireNonNull(outputDir); + this.withRequiredPackagesLookup = sysEnv.soLookupAvailable() && sysEnv.nativePackageType().equals(pkg.type()); + + customActions = List.of( + DesktopIntegration.create(env, pkg), + LinuxLaunchersAsServices.create(env, pkg)); + } + + enum LinuxPackageTaskID implements TaskID { + INIT_REQUIRED_PACKAGES, + VERIFY_PACKAGE + } + + @Override + public void accept(PackagingPipeline.Builder pipelineBuilder) { + pipelineBuilder.excludeDirFromCopying(outputDir) + .task(PackageTaskID.CREATE_CONFIG_FILES) + .action(this::buildConfigFiles) + .add() + .task(LinuxPackageTaskID.INIT_REQUIRED_PACKAGES) + .addDependencies(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE) + .addDependent(PackageTaskID.CREATE_CONFIG_FILES) + .action(this::initRequiredPackages) + .add() + .task(LinuxPackageTaskID.VERIFY_PACKAGE) + .addDependencies(PackageTaskID.CREATE_PACKAGE_FILE) + .addDependent(PrimaryTaskID.PACKAGE) + .action(this::verifyOutputPackage) + .add() + .task(PackageTaskID.CREATE_PACKAGE_FILE) + .action(this::buildPackage) + .add(); + } + + protected final Path outputPackageFile() { + return outputDir.resolve(pkg.packageFileNameWithSuffix()); + } + + protected abstract void buildPackage() throws IOException; + + protected abstract List findErrorsInOutputPackage() throws IOException; + + protected abstract void createConfigFiles(Map replacementData) throws IOException; + + protected abstract Map createReplacementData() throws IOException; + + protected abstract void initLibProvidersLookup(LibProvidersLookup libProvidersLookup); + + private void buildConfigFiles() throws PackagerException, IOException { + + final var data = createDefaultReplacementData(); + + for (var ca : customActions) { + ShellCustomAction.mergeReplacementData(data, ca.create()); + } + + data.putAll(createReplacementData()); + + createConfigFiles(Collections.unmodifiableMap(data)); + } + + private Map createDefaultReplacementData() { + Map data = new HashMap<>(); + + data.put("APPLICATION_PACKAGE", pkg.packageName()); + data.put("APPLICATION_VENDOR", pkg.app().vendor()); + data.put("APPLICATION_VERSION", pkg.version()); + data.put("APPLICATION_DESCRIPTION", pkg.description()); + + String defaultDeps = String.join(", ", requiredPackages); + String customDeps = pkg.additionalDependencies().orElse(""); + if (!customDeps.isEmpty() && !defaultDeps.isEmpty()) { + customDeps = ", " + customDeps; + } + data.put("PACKAGE_DEFAULT_DEPENDENCIES", defaultDeps); + data.put("PACKAGE_CUSTOM_DEPENDENCIES", customDeps); + + return data; + } + + private void initRequiredPackages() throws IOException { + + final List caPackages = customActions.stream() + .map(ShellCustomAction::requiredPackages) + .flatMap(List::stream).toList(); + + final List neededLibPackages; + if (withRequiredPackagesLookup) { + neededLibPackages = findRequiredPackages(); + } else { + neededLibPackages = Collections.emptyList(); + Log.info(I18N.getString("warning.foreign-app-image")); + } + + // Merge all package lists together. + // Filter out empty names, sort and remove duplicates. + Stream.of(caPackages, neededLibPackages) + .flatMap(List::stream) + .filter(Predicate.not(String::isEmpty)) + .sorted().distinct().forEach(requiredPackages::add); + + Log.verbose(String.format("Required packages: %s", requiredPackages)); + } + + private List findRequiredPackages() throws IOException { + var lookup = new LibProvidersLookup(); + initLibProvidersLookup(lookup); + return lookup.execute(env.appImageDir()); + } + + private void verifyOutputPackage() { + final List errors; + try { + errors = findErrorsInOutputPackage(); + } catch (Exception ex) { + // Ignore error as it is not critical. Just report it. + Log.verbose(ex); + return; + } + + for (var ex : errors) { + Log.verbose(ex.getLocalizedMessage()); + if (ex instanceof ConfigException cfgEx) { + Log.verbose(cfgEx.getAdvice()); + } + } + } + + protected final BuildEnv env; + protected final T pkg; + protected final Path outputDir; + private final boolean withRequiredPackagesLookup; + private final List requiredPackages = new ArrayList<>(); + private final List customActions; +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index 350f70f11bc..2337a286011 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -25,189 +25,20 @@ package jdk.jpackage.internal; -import java.io.IOException; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.DottedVersion; -import jdk.jpackage.internal.model.LinuxPackage; import jdk.jpackage.internal.model.LinuxRpmPackage; -import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.StandardPackageType; +import jdk.jpackage.internal.util.Result; -/** - * There are two command line options to configure license information for RPM - * packaging: --linux-rpm-license-type and --license-file. Value of - * --linux-rpm-license-type command line option configures "License:" section - * of RPM spec. Value of --license-file command line option specifies a license - * file to be added to the package. License file is a sort of documentation file - * but it will be installed even if user selects an option to install the - * package without documentation. --linux-rpm-license-type is the primary option - * to set license information. --license-file makes little sense in case of RPM - * packaging. - */ public class LinuxRpmBundler extends LinuxPackageBundler { - private static final String DEFAULT_SPEC_TEMPLATE = "template.spec"; - - public static final String TOOL_RPM = "rpm"; - public static final String TOOL_RPMBUILD = "rpmbuild"; - public static final DottedVersion TOOL_RPMBUILD_MIN_VERSION = DottedVersion.lazy( - "4.10"); - public LinuxRpmBundler() { super(LinuxFromParams.RPM_PACKAGE); } - @Override - protected void doValidate(BuildEnv env, LinuxPackage pkg) throws ConfigException { - } - - private static ToolValidator createRpmbuildToolValidator() { - Pattern pattern = Pattern.compile(" (\\d+\\.\\d+)"); - return new ToolValidator(TOOL_RPMBUILD).setMinimalVersion( - TOOL_RPMBUILD_MIN_VERSION).setVersionParser(lines -> { - String versionString = lines.limit(1).collect( - Collectors.toList()).get(0); - Matcher matcher = pattern.matcher(versionString); - if (matcher.find()) { - return matcher.group(1); - } - return null; - }); - } - - @Override - protected List getToolValidators() { - return List.of(createRpmbuildToolValidator()); - } - - protected void createConfigFiles(Map replacementData, - BuildEnv env, LinuxPackage pkg) throws IOException { - Path specFile = specFile(env, pkg); - - // prepare spec file - env.createResource(DEFAULT_SPEC_TEMPLATE) - .setCategory(I18N.getString("resource.rpm-spec-file")) - .setSubstitutionData(replacementData) - .saveToFile(specFile); - } - - @Override - protected Path buildPackageBundle(BuildEnv env, LinuxPackage pkg, - Path outputParentDir) throws PackagerException, IOException { - return buildRPM(env, pkg, outputParentDir); - } - - private static Path installPrefix(LinuxPackage pkg) { - Path path = pkg.relativeInstallDir(); - if (!pkg.isInstallDirInUsrTree()) { - path = path.getParent(); - } - return Path.of("/").resolve(path); - } - - @Override - protected Map createReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException { - Map data = new HashMap<>(); - - data.put("APPLICATION_RELEASE", pkg.release().orElseThrow()); - data.put("APPLICATION_PREFIX", installPrefix(pkg).toString()); - data.put("APPLICATION_DIRECTORY", Path.of("/").resolve(pkg.relativeInstallDir()).toString()); - data.put("APPLICATION_SUMMARY", pkg.app().name()); - data.put("APPLICATION_LICENSE_TYPE", ((LinuxRpmPackage)pkg).licenseType()); - - String licenseFile = pkg.licenseFile().map(v -> { - return v.toAbsolutePath().normalize().toString(); - }).orElse(null); - data.put("APPLICATION_LICENSE_FILE", licenseFile); - data.put("APPLICATION_GROUP", pkg.category().orElse("")); - - data.put("APPLICATION_URL", pkg.aboutURL().orElse("")); - - return data; - } - - @Override - protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) { - libProvidersLookup.setPackageLookup(file -> { - return Executor.of(TOOL_RPM, - "-q", "--queryformat", "%{name}\\n", - "-q", "--whatprovides", file.toString()) - .saveOutput(true).executeExpectSuccess().getOutput().stream(); - }); - } - - @Override - protected List verifyOutputBundle(BuildEnv env, LinuxPackage pkg, - Path packageBundle) { - List errors = new ArrayList<>(); - - String specFileName = specFile(env, pkg).getFileName().toString(); - - try { - List properties = List.of( - new PackageProperty("Name", pkg.packageName(), - "APPLICATION_PACKAGE", specFileName), - new PackageProperty("Version", pkg.version(), - "APPLICATION_VERSION", specFileName), - new PackageProperty("Release", pkg.release().orElseThrow(), - "APPLICATION_RELEASE", specFileName), - new PackageProperty("Arch", pkg.arch(), null, specFileName)); - - List actualValues = Executor.of(TOOL_RPM, "-qp", "--queryformat", - properties.stream().map(entry -> String.format("%%{%s}", - entry.name)).collect(Collectors.joining("\\n")), - packageBundle.toString()).saveOutput(true).executeExpectSuccess().getOutput(); - - Iterator actualValuesIt = actualValues.iterator(); - properties.forEach(property -> errors.add(property.verifyValue( - actualValuesIt.next()))); - } catch (IOException ex) { - // Ignore error as it is not critical. Just report it. - Log.verbose(ex); - } - - return errors; - } - - private Path specFile(BuildEnv env, Package pkg) { - return env.buildRoot().resolve(Path.of("SPECS", pkg.packageName() + ".spec")); - } - - private Path buildRPM(BuildEnv env, Package pkg, Path outdir) throws IOException { - - Path rpmFile = outdir.toAbsolutePath().resolve(pkg.packageFileNameWithSuffix()); - - Log.verbose(I18N.format("message.outputting-bundle-location", rpmFile.getParent())); - - //run rpmbuild - Executor.of(TOOL_RPMBUILD, - "-bb", specFile(env, pkg).toAbsolutePath().toString(), - "--define", String.format("%%_sourcedir %s", - env.appImageDir().toAbsolutePath()), - // save result to output dir - "--define", String.format("%%_rpmdir %s", rpmFile.getParent()), - // do not use other system directories to build as current user - "--define", String.format("%%_topdir %s", - env.buildRoot().toAbsolutePath()), - "--define", String.format("%%_rpmfilename %s", rpmFile.getFileName()) - ).executeExpectSuccess(); - - Log.verbose(I18N.format("message.output-bundle-location", rpmFile.getParent())); - - return rpmFile; - } - @Override public String getName() { return I18N.getString("rpm.bundler.name"); @@ -219,12 +50,28 @@ public String getID() { } @Override - public boolean supported(boolean runtimeInstaller) { - return OperatingSystem.isLinux() && (createRpmbuildToolValidator().validate() == null); + public Path execute(Map params, Path outputParentDir) throws PackagerException { + + return Packager.build().outputDir(outputParentDir) + .pkg(LinuxFromParams.RPM_PACKAGE.fetchFrom(params)) + .env(BuildEnvFromParams.BUILD_ENV.fetchFrom(params)) + .pipelineBuilderMutatorFactory((env, pkg, outputDir) -> { + return new LinuxRpmPackager(env, pkg, outputDir, sysEnv.orElseThrow()); + }).execute(LinuxPackagingPipeline.build()); + } + + @Override + protected Result sysEnv() { + return sysEnv; } @Override public boolean isDefault() { - return !LinuxDebBundler.isDebian(); + return sysEnv.value() + .map(LinuxSystemEnvironment::nativePackageType) + .map(StandardPackageType.LINUX_RPM::equals) + .orElse(false); } + + private final Result sysEnv = LinuxRpmSystemEnvironment.create(SYS_ENV); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackager.java new file mode 100644 index 00000000000..60355d0d1a2 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackager.java @@ -0,0 +1,167 @@ +/* + * 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.jpackage.internal; + +import static java.util.stream.Collectors.joining; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxRpmPackage; + + +/** + * There are two command line options to configure license information for RPM + * packaging: --linux-rpm-license-type and --license-file. Value of + * --linux-rpm-license-type command line option configures "License:" section + * of RPM spec. Value of --license-file command line option specifies a license + * file to be added to the package. License file is a sort of documentation file + * but it will be installed even if user selects an option to install the + * package without documentation. --linux-rpm-license-type is the primary option + * to set license information. --license-file makes little sense in case of RPM + * packaging. + */ +final class LinuxRpmPackager extends LinuxPackager { + + LinuxRpmPackager(BuildEnv env, LinuxRpmPackage pkg, Path outputDir, LinuxRpmSystemEnvironment sysEnv) { + super(env, pkg, outputDir, sysEnv); + this.sysEnv = Objects.requireNonNull(sysEnv); + } + + @Override + protected void createConfigFiles(Map replacementData) throws IOException { + Path specFile = specFile(); + + // prepare spec file + env.createResource("template.spec") + .setCategory(I18N.getString("resource.rpm-spec-file")) + .setSubstitutionData(replacementData) + .saveToFile(specFile); + } + + @Override + protected Map createReplacementData() { + Map data = new HashMap<>(); + + data.put("APPLICATION_RELEASE", pkg.release().orElseThrow()); + data.put("APPLICATION_PREFIX", installPrefix().toString()); + data.put("APPLICATION_DIRECTORY", Path.of("/").resolve(pkg.relativeInstallDir()).toString()); + data.put("APPLICATION_SUMMARY", pkg.app().name()); + data.put("APPLICATION_LICENSE_TYPE", pkg.licenseType()); + + String licenseFile = pkg.licenseFile().map(v -> { + return v.toAbsolutePath().normalize().toString(); + }).orElse(null); + data.put("APPLICATION_LICENSE_FILE", licenseFile); + data.put("APPLICATION_GROUP", pkg.category().orElse("")); + + data.put("APPLICATION_URL", pkg.aboutURL().orElse("")); + + return data; + } + + @Override + protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) { + libProvidersLookup.setPackageLookup(file -> { + return Executor.of(sysEnv.rpm().toString(), + "-q", "--queryformat", "%{name}\\n", + "-q", "--whatprovides", file.toString() + ).saveOutput(true).executeExpectSuccess().getOutput().stream(); + }); + } + + @Override + protected List findErrorsInOutputPackage() throws IOException { + List errors = new ArrayList<>(); + + var specFileName = specFile().getFileName().toString(); + + var properties = List.of( + new PackageProperty("Name", pkg.packageName(), + "APPLICATION_PACKAGE", specFileName), + new PackageProperty("Version", pkg.version(), + "APPLICATION_VERSION", specFileName), + new PackageProperty("Release", pkg.release().orElseThrow(), + "APPLICATION_RELEASE", specFileName), + new PackageProperty("Arch", pkg.arch(), null, specFileName)); + + var actualValues = Executor.of( + sysEnv.rpm().toString(), + "-qp", + "--queryformat", properties.stream().map(e -> String.format("%%{%s}", e.name)).collect(joining("\\n")), + outputPackageFile().toString() + ).saveOutput(true).executeExpectSuccess().getOutput(); + + for (int i = 0; i != properties.size(); i++) { + Optional.ofNullable(properties.get(i).verifyValue(actualValues.get(i))).ifPresent(errors::add); + } + + return errors; + } + + @Override + protected void buildPackage() throws IOException { + + Path rpmFile = outputPackageFile(); + + Log.verbose(I18N.format("message.outputting-bundle-location", rpmFile.getParent())); + + //run rpmbuild + Executor.of(sysEnv.rpmbuild().toString(), + "-bb", specFile().toAbsolutePath().toString(), + "--define", String.format("%%_sourcedir %s", + env.appImageDir().toAbsolutePath()), + // save result to output dir + "--define", String.format("%%_rpmdir %s", rpmFile.getParent()), + // do not use other system directories to build as current user + "--define", String.format("%%_topdir %s", + env.buildRoot().toAbsolutePath()), + "--define", String.format("%%_rpmfilename %s", rpmFile.getFileName()) + ).executeExpectSuccess(); + + Log.verbose(I18N.format("message.output-bundle-location", rpmFile.getParent())); + } + + private Path installPrefix() { + Path path = pkg.relativeInstallDir(); + if (!pkg.isInstallDirInUsrTree()) { + path = path.getParent(); + } + return Path.of("/").resolve(path); + } + + private Path specFile() { + return env.buildRoot().resolve(Path.of("SPECS", pkg.packageName() + ".spec")); + } + + private final LinuxRpmSystemEnvironment sysEnv; +} diff --git a/src/hotspot/cpu/aarch64/bytecodes_aarch64.hpp b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironment.java similarity index 56% rename from src/hotspot/cpu/aarch64/bytecodes_aarch64.hpp rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironment.java index 1daf71388e3..58c10668227 100644 --- a/src/hotspot/cpu/aarch64/bytecodes_aarch64.hpp +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironment.java @@ -1,11 +1,12 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. 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 * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * 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 @@ -20,12 +21,16 @@ * 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.jpackage.internal; + +import static jdk.jpackage.internal.LinuxSystemEnvironment.mixin; -#ifndef CPU_AARCH64_BYTECODES_AARCH64_HPP -#define CPU_AARCH64_BYTECODES_AARCH64_HPP +import jdk.jpackage.internal.util.Result; -// No aarch64 specific bytecodes +public interface LinuxRpmSystemEnvironment extends LinuxSystemEnvironment, LinuxRpmSystemEnvironmentMixin { -#endif // CPU_AARCH64_BYTECODES_AARCH64_HPP + static Result create(Result base) { + return mixin(LinuxRpmSystemEnvironment.class, base, LinuxRpmSystemEnvironmentMixin::create); + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironmentMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironmentMixin.java new file mode 100644 index 00000000000..b741495f5ed --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironmentMixin.java @@ -0,0 +1,74 @@ +/* + * 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.jpackage.internal; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.util.Result; + +public interface LinuxRpmSystemEnvironmentMixin { + Path rpm(); + Path rpmbuild(); + + record Stub(Path rpm, Path rpmbuild) implements LinuxRpmSystemEnvironmentMixin { + } + + static Result create() { + + final var errors = Stream.of( + Internal.createRpmbuildToolValidator(), + new ToolValidator(Internal.TOOL_RPM) + ).map(ToolValidator::validate).filter(Objects::nonNull).toList(); + + if (errors.isEmpty()) { + return Result.ofValue(new Stub(Internal.TOOL_RPM, Internal.TOOL_RPMBUILD)); + } else { + return Result.ofErrors(errors); + } + } + + static final class Internal { + private static ToolValidator createRpmbuildToolValidator() { + Pattern pattern = Pattern.compile(" (\\d+\\.\\d+)"); + return new ToolValidator(TOOL_RPMBUILD).setMinimalVersion( + TOOL_RPMBUILD_MIN_VERSION).setVersionParser(lines -> { + String versionString = lines.limit(1).findFirst().orElseThrow(); + Matcher matcher = pattern.matcher(versionString); + if (matcher.find()) { + return matcher.group(1); + } + return null; + }); + } + + private static final Path TOOL_RPM = Path.of("rpm"); + private static final Path TOOL_RPMBUILD = Path.of("rpmbuild"); + private static final DottedVersion TOOL_RPMBUILD_MIN_VERSION = DottedVersion.lazy("4.10"); + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxSystemEnvironment.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxSystemEnvironment.java new file mode 100644 index 00000000000..1a70cc938b8 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxSystemEnvironment.java @@ -0,0 +1,111 @@ +/* + * 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.jpackage.internal; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.StandardPackageType; +import jdk.jpackage.internal.util.CompositeProxy; +import jdk.jpackage.internal.util.Result; + +public interface LinuxSystemEnvironment extends SystemEnvironment { + boolean soLookupAvailable(); + PackageType nativePackageType(); + + static Result create() { + return detectNativePackageType().map(LinuxSystemEnvironment::create).orElseGet(() -> { + return Result.ofError(new RuntimeException("Unknown native package type")); + }); + } + + static Optional detectNativePackageType() { + if (Internal.isDebian()) { + return Optional.of(StandardPackageType.LINUX_DEB); + } else if (Internal.isRpm()) { + return Optional.of(StandardPackageType.LINUX_RPM); + } else { + return Optional.empty(); + } + } + + static Result create(PackageType nativePackageType) { + return Result.ofValue(new Stub(LibProvidersLookup.supported(), + Objects.requireNonNull(nativePackageType))); + } + + static U createWithMixin(Class type, LinuxSystemEnvironment base, T mixin) { + return CompositeProxy.create(type, base, mixin); + } + + static Result mixin(Class type, + Result base, Supplier> mixinResultSupplier) { + final var mixin = mixinResultSupplier.get(); + + final List errors = new ArrayList<>(); + errors.addAll(base.errors()); + errors.addAll(mixin.errors()); + + if (errors.isEmpty()) { + return Result.ofValue(createWithMixin(type, base.orElseThrow(), mixin.orElseThrow())); + } else { + return Result.ofErrors(errors); + } + } + + record Stub(boolean soLookupAvailable, PackageType nativePackageType) implements LinuxSystemEnvironment { + } + + static final class Internal { + + private static boolean isDebian() { + // we are just going to run "dpkg -s coreutils" and assume Debian + // or derivative if no error is returned. + try { + Executor.of("dpkg", "-s", "coreutils").executeExpectSuccess(); + return true; + } catch (IOException e) { + // just fall thru + return false; + } + } + + private static boolean isRpm() { + // we are just going to run "rpm -q rpm" and assume RPM + // or derivative if no error is returned. + try { + Executor.of("rpm", "-q", "rpm").executeExpectSuccess(); + return true; + } catch (IOException e) { + // just fall thru + return false; + } + } + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java index 7563dfa0ed3..571f163f682 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java @@ -237,7 +237,7 @@ static Codesigners create(CodesignConfig signingCfg) { final var codesignExecutableFile = Codesign.build(signingCfg::toCodesignArgs).quiet(true).create().asConsumer(); final var codesignFile = Codesign.build(signingCfgWithoutEntitlements::toCodesignArgs).quiet(true).create().asConsumer(); - final var codesignDir = Codesign.build(signingCfgWithoutEntitlements::toCodesignArgs).force(true).create().asConsumer(); + final var codesignDir = Codesign.build(signingCfg::toCodesignArgs).force(true).create().asConsumer(); return new Codesigners(codesignFile, codesignExecutableFile, codesignDir); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index d2c72765d7a..0ddb987dbee 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -25,12 +25,14 @@ package jdk.jpackage.internal; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; import java.util.Objects; +import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.util.Result; public class MacDmgBundler extends MacBaseInstallerBundler { @@ -70,39 +72,27 @@ public boolean validate(Map params) public Path execute(Map params, Path outputParentDir) throws PackagerException { - final var pkg = MacFromParams.DMG_PACKAGE.fetchFrom(params); - var env = MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params); + var pkg = MacFromParams.DMG_PACKAGE.fetchFrom(params); - final var packager = MacDmgPackager.build().outputDir(outputParentDir).pkg(pkg).env(env); + Log.verbose(I18N.format("message.building-dmg", pkg.app().name())); - MacDmgPackager.findSetFileUtility().ifPresent(packager::setFileUtility); - - return packager.execute(); + return Packager.build().outputDir(outputParentDir) + .pkg(pkg) + .env(MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params)) + .pipelineBuilderMutatorFactory((env, _, outputDir) -> { + return new MacDmgPackager(env, pkg, outputDir, sysEnv.orElseThrow()); + }).execute(MacPackagingPipeline.build(Optional.of(pkg))); } @Override public boolean supported(boolean runtimeInstaller) { - return isSupported(); - } - - public static final String[] required = - {"/usr/bin/hdiutil", "/usr/bin/osascript"}; - public static boolean isSupported() { - try { - for (String s : required) { - Path f = Path.of(s); - if (!Files.exists(f) || !Files.isExecutable(f)) { - return false; - } - } - return true; - } catch (Exception e) { - return false; - } + return sysEnv.hasValue(); } @Override public boolean isDefault() { return true; } + + private final Result sysEnv = MacDmgSystemEnvironment.create(); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java index eb3ad3a76c8..6e13a2ff0c1 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -36,106 +36,25 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.Optional; -import java.util.stream.Stream; +import java.util.function.Consumer; import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; -import jdk.jpackage.internal.PackagingPipeline.StartupParameters; import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.MacDmgPackage; -import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.PathGroup; -record MacDmgPackager(MacDmgPackage pkg, BuildEnv env, Path hdiutil, Path outputDir, Optional setFileUtility) { +record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, + MacDmgSystemEnvironment sysEnv) implements Consumer { MacDmgPackager { - Objects.requireNonNull(pkg); Objects.requireNonNull(env); - Objects.requireNonNull(hdiutil); + Objects.requireNonNull(pkg); Objects.requireNonNull(outputDir); - Objects.requireNonNull(setFileUtility); - } - - static Builder build() { - return new Builder(); + Objects.requireNonNull(sysEnv); } - static final class Builder extends PackagerBuilder { - - Builder hdiutil(Path v) { - hdiutil = v; - return this; - } - - Builder setFileUtility(Path v) { - setFileUtility = v; - return this; - } - - Path execute() throws PackagerException { - Log.verbose(MessageFormat.format(I18N.getString("message.building-dmg"), - pkg.app().name())); - - IOUtils.writableOutputDir(outputDir); - - return execute(MacPackagingPipeline.build(Optional.of(pkg))); - } - - @Override - protected void configurePackagingPipeline(PackagingPipeline.Builder pipelineBuilder, - StartupParameters startupParameters) { - final var packager = new MacDmgPackager(pkg, startupParameters.packagingEnv(), - validatedHdiutil(), outputDir, Optional.ofNullable(setFileUtility)); - packager.applyToPipeline(pipelineBuilder); - } - - private Path validatedHdiutil() { - return Optional.ofNullable(hdiutil).orElse(HDIUTIL); - } - - private Path hdiutil; - private Path setFileUtility; - } - - // Location of SetFile utility may be different depending on MacOS version - // We look for several known places and if none of them work will - // try to find it - static Optional findSetFileUtility() { - String typicalPaths[] = {"/Developer/Tools/SetFile", - "/usr/bin/SetFile", "/Developer/usr/bin/SetFile"}; - - final var setFilePath = Stream.of(typicalPaths).map(Path::of).filter(Files::isExecutable).findFirst(); - if (setFilePath.isPresent()) { - // Validate SetFile, if Xcode is not installed it will run, but exit with error - // code - try { - if (Executor.of(setFilePath.orElseThrow().toString(), "-h").setQuiet(true).execute() == 0) { - return setFilePath; - } - } catch (Exception ignored) { - // No need for generic find attempt. We found it, but it does not work. - // Probably due to missing xcode. - return Optional.empty(); - } - } - - // generic find attempt - try { - final var executor = Executor.of("/usr/bin/xcrun", "-find", "SetFile"); - final var code = executor.setQuiet(true).saveOutput(true).execute(); - if (code == 0 && executor.getOutput().isEmpty()) { - final var firstLine = executor.getOutput().getFirst(); - Path f = Path.of(firstLine); - if (Files.exists(f) && Files.isExecutable(f)) { - return Optional.of(f.toAbsolutePath()); - } - } - } catch (IOException ignored) {} - - return Optional.empty(); - } - - private void applyToPipeline(PackagingPipeline.Builder pipelineBuilder) { + @Override + public void accept(PackagingPipeline.Builder pipelineBuilder) { pipelineBuilder .excludeDirFromCopying(outputDir) .task(DmgPackageTaskID.COPY_DMG_CONTENT) @@ -318,7 +237,7 @@ private void buildDMG() throws IOException { // create temp image ProcessBuilder pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "create", hdiUtilVerbosityFlag, "-srcfolder", normalizedAbsolutePathString(srcFolder), @@ -341,7 +260,7 @@ private void buildDMG() throws IOException { // We need extra room for icons and background image. When we providing // actual files to hdiutil, it will create DMG with ~50 megabytes extra room. pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "create", hdiUtilVerbosityFlag, "-size", String.valueOf(size), @@ -357,7 +276,7 @@ private void buildDMG() throws IOException { // mount temp image pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "attach", normalizedAbsolutePathString(protoDMG), hdiUtilVerbosityFlag, @@ -382,7 +301,7 @@ private void buildDMG() throws IOException { // to install-dir in DMG as critical error, since it can fail in // headless environment. try { - pb = new ProcessBuilder("/usr/bin/osascript", + pb = new ProcessBuilder(sysEnv.osascript().toString(), normalizedAbsolutePathString(volumeScript())); IOUtils.exec(pb, 180); // Wait 3 minutes. See JDK-8248248. } catch (IOException ex) { @@ -397,7 +316,7 @@ private void buildDMG() throws IOException { // NB: attributes of the root directory are ignored // when creating the volume // Therefore we have to do this after we mount image - if (setFileUtility.isPresent()) { + if (sysEnv.setFileUtility().isPresent()) { //can not find utility => keep going without icon try { volumeIconFile.toFile().setWritable(true); @@ -406,14 +325,14 @@ private void buildDMG() throws IOException { // "icnC" for the volume icon // (might not work on Mac 10.13 with old XCode) pb = new ProcessBuilder( - setFileUtility.orElseThrow().toString(), + sysEnv.setFileUtility().orElseThrow().toString(), "-c", "icnC", normalizedAbsolutePathString(volumeIconFile)); IOUtils.exec(pb); volumeIconFile.toFile().setReadOnly(); pb = new ProcessBuilder( - setFileUtility.orElseThrow().toString(), + sysEnv.setFileUtility().orElseThrow().toString(), "-a", "C", normalizedAbsolutePathString(mountedVolume)); IOUtils.exec(pb); @@ -428,7 +347,7 @@ private void buildDMG() throws IOException { } finally { // Detach the temporary image pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "detach", hdiUtilVerbosityFlag, normalizedAbsolutePathString(mountedVolume)); @@ -451,7 +370,7 @@ private void buildDMG() throws IOException { // Now force to detach if it still attached if (Files.exists(mountedVolume)) { pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "detach", "-force", hdiUtilVerbosityFlag, @@ -464,7 +383,7 @@ private void buildDMG() throws IOException { // Compress it to a new image pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "convert", normalizedAbsolutePathString(protoDMG), hdiUtilVerbosityFlag, @@ -481,7 +400,7 @@ private void buildDMG() throws IOException { Files.copy(protoDMG, protoCopyDMG); try { pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "convert", normalizedAbsolutePathString(protoCopyDMG), hdiUtilVerbosityFlag, @@ -496,7 +415,7 @@ private void buildDMG() throws IOException { //add license if needed if (pkg.licenseFile().isPresent()) { pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "udifrez", normalizedAbsolutePathString(finalDMG), "-xml", @@ -527,6 +446,4 @@ private void buildDMG() throws IOException { private static final String TEMPLATE_BUNDLE_ICON = "JavaApp.icns"; private static final String DEFAULT_LICENSE_PLIST="lic_template.plist"; - - private static final Path HDIUTIL = Path.of("/usr/bin/hdiutil"); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgSystemEnvironment.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgSystemEnvironment.java new file mode 100644 index 00000000000..54eb0c6f4fe --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgSystemEnvironment.java @@ -0,0 +1,94 @@ +/* + * 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.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.Result; + +record MacDmgSystemEnvironment(Path hdiutil, Path osascript, Optional setFileUtility) implements SystemEnvironment { + + MacDmgSystemEnvironment { + } + + static Result create() { + final var errors = Stream.of(HDIUTIL, OSASCRIPT) + .map(ToolValidator::new) + .map(ToolValidator::checkExistsOnly) + .map(ToolValidator::validate) + .filter(Objects::nonNull) + .toList(); + if (errors.isEmpty()) { + return Result.ofValue(new MacDmgSystemEnvironment(HDIUTIL, OSASCRIPT, findSetFileUtility())); + } else { + return Result.ofErrors(errors); + } + } + + // Location of SetFile utility may be different depending on MacOS version + // We look for several known places and if none of them work will + // try to find it + private static Optional findSetFileUtility() { + String typicalPaths[] = {"/Developer/Tools/SetFile", + "/usr/bin/SetFile", "/Developer/usr/bin/SetFile"}; + + final var setFilePath = Stream.of(typicalPaths).map(Path::of).filter(Files::isExecutable).findFirst(); + if (setFilePath.isPresent()) { + // Validate SetFile, if Xcode is not installed it will run, but exit with error + // code + try { + if (Executor.of(setFilePath.orElseThrow().toString(), "-h").setQuiet(true).execute() == 0) { + return setFilePath; + } + } catch (Exception ignored) { + // No need for generic find attempt. We found it, but it does not work. + // Probably due to missing xcode. + return Optional.empty(); + } + } + + // generic find attempt + try { + final var executor = Executor.of("/usr/bin/xcrun", "-find", "SetFile"); + final var code = executor.setQuiet(true).saveOutput(true).execute(); + if (code == 0 && !executor.getOutput().isEmpty()) { + final var firstLine = executor.getOutput().getFirst(); + Path f = Path.of(firstLine); + if (new ToolValidator(f).checkExistsOnly().validate() == null) { + return Optional.of(f.toAbsolutePath()); + } + } + } catch (IOException ignored) {} + + return Optional.empty(); + } + + private static final Path HDIUTIL = Path.of("/usr/bin/hdiutil"); + private static final Path OSASCRIPT = Path.of("/usr/bin/osascript"); +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index bc19e7c4a1a..e827f238db3 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -28,7 +28,9 @@ import java.nio.file.Path; import java.util.Map; import java.util.Objects; +import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.PackagerException; public class MacPkgBundler extends MacBaseInstallerBundler { @@ -49,7 +51,7 @@ public boolean validate(Map params) try { Objects.requireNonNull(params); - final var pkgPkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); + final var pkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); // run basic validation to ensure requirements are met // we are not interested in return code, only possible exception @@ -72,12 +74,16 @@ public boolean validate(Map params) public Path execute(Map params, Path outputParentDir) throws PackagerException { - final var pkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); - var env = MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params); + var pkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); - final var packager = MacPkgPackager.build().outputDir(outputParentDir).pkg(pkg).env(env); + Log.verbose(I18N.format("message.building-pkg", pkg.app().name())); - return packager.execute(); + return Packager.build().outputDir(outputParentDir) + .pkg(pkg) + .env(MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params)) + .pipelineBuilderMutatorFactory((env, _, outputDir) -> { + return new MacPkgPackager(env, pkg, outputDir); + }).execute(MacPackagingPipeline.build(Optional.of(pkg))); } @Override diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java index 1fb0b9bc160..891c5b120f5 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java @@ -41,6 +41,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.function.Consumer; import java.util.stream.Stream; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; @@ -52,15 +53,25 @@ import jdk.internal.util.Architecture; import jdk.internal.util.OSVersion; import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; -import jdk.jpackage.internal.PackagingPipeline.StartupParameters; import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.MacPkgPackage; -import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.resources.ResourceLocator; import jdk.jpackage.internal.util.XmlUtils; import org.xml.sax.SAXException; -record MacPkgPackager(MacPkgPackage pkg, BuildEnv env, Optional services, Path outputDir) { +record MacPkgPackager(BuildEnv env, MacPkgPackage pkg, Optional services, + Path outputDir) implements Consumer { + + MacPkgPackager { + Objects.requireNonNull(env); + Objects.requireNonNull(pkg); + Objects.requireNonNull(services); + Objects.requireNonNull(outputDir); + } + + MacPkgPackager(BuildEnv env, MacPkgPackage pkg, Path outputDir) { + this(env, pkg, createServices(env, pkg), outputDir); + } enum PkgPackageTaskID implements TaskID { PREPARE_MAIN_SCRIPTS, @@ -69,37 +80,6 @@ enum PkgPackageTaskID implements TaskID { PREPARE_SERVICES } - static Builder build() { - return new Builder(); - } - - static final class Builder extends PackagerBuilder { - - Path execute() throws PackagerException { - Log.verbose(MessageFormat.format(I18N.getString("message.building-pkg"), - pkg.app().name())); - - IOUtils.writableOutputDir(outputDir); - - return execute(MacPackagingPipeline.build(Optional.of(pkg))); - } - - @Override - protected void configurePackagingPipeline(PackagingPipeline.Builder pipelineBuilder, - StartupParameters startupParameters) { - final var packager = new MacPkgPackager(pkg, startupParameters.packagingEnv(), createServices(), outputDir); - packager.applyToPipeline(pipelineBuilder); - } - - private Optional createServices() { - if (pkg.app().isService()) { - return Optional.of(Services.create(pkg, env)); - } else { - return Optional.empty(); - } - } - } - record InternalPackage(Path srcRoot, String identifier, Path path, List otherPkgbuildArgs) { InternalPackage { @@ -230,7 +210,8 @@ private String filename(MacPkgPackage pkg) { private final Optional nameSuffix; } - private void applyToPipeline(PackagingPipeline.Builder pipelineBuilder) { + @Override + public void accept(PackagingPipeline.Builder pipelineBuilder) { pipelineBuilder .excludeDirFromCopying(outputDir) .task(PkgPackageTaskID.PREPARE_MAIN_SCRIPTS) @@ -559,6 +540,14 @@ private void productbuild() throws IOException { IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); } + private static Optional createServices(BuildEnv env, MacPkgPackage pkg) { + if (pkg.app().isService()) { + return Optional.of(Services.create(pkg, env)); + } else { + return Optional.empty(); + } + } + private static final String DEFAULT_BACKGROUND_IMAGE = "background_pkg.png"; private static final String DEFAULT_PDF = "product-def.plist"; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Packager.java similarity index 57% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/Packager.java index 4ba2f0fbda6..501fd64bdca 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Packager.java @@ -26,50 +26,80 @@ import java.nio.file.Path; import java.util.Objects; -import jdk.jpackage.internal.PackagingPipeline.StartupParameters; +import java.util.Optional; +import java.util.function.Consumer; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; -abstract class PackagerBuilder> { +final class Packager { - U pkg(T v) { + static Packager build() { + return new Packager<>(); + } + + Packager pkg(T v) { pkg = v; - return thiz(); + return this; } - U env(BuildEnv v) { + Packager env(BuildEnv v) { env = v; - return thiz(); + return this; } - U outputDir(Path v) { + Packager outputDir(Path v) { outputDir = v; - return thiz(); + return this; + } + + Packager pipelineBuilderMutatorFactory(PipelineBuilderMutatorFactory v) { + pipelineBuilderMutatorFactory = v; + return this; } - @SuppressWarnings("unchecked") - private U thiz() { - return (U)this; + T pkg() { + return Objects.requireNonNull(pkg); } - protected abstract void configurePackagingPipeline(PackagingPipeline.Builder pipelineBuilder, - StartupParameters startupParameters); + Path outputDir() { + return Objects.requireNonNull(outputDir); + } + + BuildEnv env() { + return Objects.requireNonNull(env); + } Path execute(PackagingPipeline.Builder pipelineBuilder) throws PackagerException { Objects.requireNonNull(pkg); Objects.requireNonNull(env); Objects.requireNonNull(outputDir); + IOUtils.writableOutputDir(outputDir); + final var startupParameters = pipelineBuilder.createStartupParameters(env, pkg, outputDir); - configurePackagingPipeline(pipelineBuilder, startupParameters); + pipelineBuilderMutatorFactory().ifPresent(factory -> { + factory.create(startupParameters.packagingEnv(), pkg, outputDir).accept(pipelineBuilder); + }); pipelineBuilder.create().execute(startupParameters); return outputDir.resolve(pkg.packageFileNameWithSuffix()); } - protected T pkg; - protected BuildEnv env; - protected Path outputDir; + + @FunctionalInterface + interface PipelineBuilderMutatorFactory { + Consumer create(BuildEnv env, T pkg, Path outputDir); + } + + + private Optional> pipelineBuilderMutatorFactory() { + return Optional.ofNullable(pipelineBuilderMutatorFactory); + } + + private T pkg; + private BuildEnv env; + private Path outputDir; + private PipelineBuilderMutatorFactory pipelineBuilderMutatorFactory; } diff --git a/src/hotspot/cpu/aarch64/bytecodes_aarch64.cpp b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/SystemEnvironment.java similarity index 72% rename from src/hotspot/cpu/aarch64/bytecodes_aarch64.cpp rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/SystemEnvironment.java index 119ad8baec3..de98e97c922 100644 --- a/src/hotspot/cpu/aarch64/bytecodes_aarch64.cpp +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/SystemEnvironment.java @@ -1,11 +1,12 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. 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 * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * 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 @@ -20,9 +21,8 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. - * */ +package jdk.jpackage.internal; -#include "interpreter/bytecodes.hpp" - - +public interface SystemEnvironment { +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java index f673ac7e33e..13e87d5cfa6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java @@ -24,36 +24,31 @@ */ package jdk.jpackage.internal; -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.DottedVersion; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.DottedVersion; -public final class ToolValidator { +final class ToolValidator { ToolValidator(String tool) { this(Path.of(tool)); } ToolValidator(Path toolPath) { - this.toolPath = toolPath; - args = new ArrayList<>(); - + this.toolPath = Objects.requireNonNull(toolPath); if (OperatingSystem.isLinux()) { setCommandLine("--version"); } - - setToolNotFoundErrorHandler(null); - setToolOldVersionErrorHandler(null); } ToolValidator setCommandLine(String... args) { @@ -67,7 +62,17 @@ ToolValidator setMinimalVersion(Comparable v) { } ToolValidator setMinimalVersion(DottedVersion v) { - return setMinimalVersion(t -> DottedVersion.compareComponents(v, DottedVersion.lazy(t))); + return setMinimalVersion(new Comparable() { + @Override + public int compareTo(String o) { + return DottedVersion.compareComponents(v, DottedVersion.lazy(o)); + } + + @Override + public String toString() { + return v.toString(); + } + }); } ToolValidator setVersionParser(Function, String> v) { @@ -75,69 +80,85 @@ ToolValidator setVersionParser(Function, String> v) { return this; } - ToolValidator setToolNotFoundErrorHandler( - BiFunction v) { + ToolValidator setToolNotFoundErrorHandler(Function v) { toolNotFoundErrorHandler = v; return this; } - ToolValidator setToolOldVersionErrorHandler(BiFunction v) { + ToolValidator setToolOldVersionErrorHandler(BiFunction v) { toolOldVersionErrorHandler = v; return this; } + ToolValidator checkExistsOnly(boolean v) { + checkExistsOnly = v; + return this; + } + + ToolValidator checkExistsOnly() { + return checkExistsOnly(true); + } + ConfigException validate() { + if (checkExistsOnly) { + if (Files.isExecutable(toolPath) && !Files.isDirectory(toolPath)) { + return null; + } else if (Files.exists(toolPath)) { + return new ConfigException( + I18N.format("error.tool-not-executable", toolPath), (String)null); + } else if (toolNotFoundErrorHandler != null) { + return toolNotFoundErrorHandler.apply(toolPath); + } else { + return new ConfigException( + I18N.format("error.tool-not-found", toolPath), + I18N.format("error.tool-not-found.advice", toolPath)); + } + } + List cmdline = new ArrayList<>(); cmdline.add(toolPath.toString()); - cmdline.addAll(args); + if (args != null) { + cmdline.addAll(args); + } - String name = IOUtils.getFileName(toolPath).toString(); - try { - ProcessBuilder pb = new ProcessBuilder(cmdline); - AtomicBoolean canUseTool = new AtomicBoolean(); - if (minimalVersion == null) { - // No version check. - canUseTool.setPlain(true); - } + boolean canUseTool[] = new boolean[1]; + if (minimalVersion == null) { + // No version check. + canUseTool[0] = true; + } - String[] version = new String[1]; - Executor.of(pb).setQuiet(true).setOutputConsumer(lines -> { + String[] version = new String[1]; + + try { + Executor.of(cmdline.toArray(String[]::new)).setQuiet(true).setOutputConsumer(lines -> { if (versionParser != null && minimalVersion != null) { version[0] = versionParser.apply(lines); - if (minimalVersion.compareTo(version[0]) < 0) { - canUseTool.setPlain(true); + if (version[0] != null && minimalVersion.compareTo(version[0]) <= 0) { + canUseTool[0] = true; } } }).execute(); - - if (!canUseTool.getPlain()) { - if (toolOldVersionErrorHandler != null) { - return toolOldVersionErrorHandler.apply(name, version[0]); - } - return new ConfigException(MessageFormat.format(I18N.getString( - "error.tool-old-version"), name, minimalVersion), - MessageFormat.format(I18N.getString( - "error.tool-old-version.advice"), name, - minimalVersion)); - } } catch (IOException e) { - if (toolNotFoundErrorHandler != null) { - return toolNotFoundErrorHandler.apply(name, e); - } - return new ConfigException(MessageFormat.format(I18N.getString( - "error.tool-not-found"), name, e.getMessage()), - MessageFormat.format(I18N.getString( - "error.tool-not-found.advice"), name), e); + return new ConfigException(I18N.format("error.tool-error", toolPath, e.getMessage()), null, e); } - // All good. Tool can be used. - return null; + if (canUseTool[0]) { + // All good. Tool can be used. + return null; + } else if (toolOldVersionErrorHandler != null) { + return toolOldVersionErrorHandler.apply(toolPath, version[0]); + } else { + return new ConfigException( + I18N.format("error.tool-old-version", toolPath, minimalVersion), + I18N.format("error.tool-old-version.advice", toolPath, minimalVersion)); + } } private final Path toolPath; private List args; private Comparable minimalVersion; private Function, String> versionParser; - private BiFunction toolNotFoundErrorHandler; - private BiFunction toolOldVersionErrorHandler; + private Function toolNotFoundErrorHandler; + private BiFunction toolOldVersionErrorHandler; + private boolean checkExistsOnly; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 684a97bc1bd..967549f6855 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -66,10 +66,13 @@ error.no-content-types-for-file-association.advice=Specify MIME type for File As error.too-many-content-types-for-file-association=More than one MIME types was specified for File Association number {0} error.too-many-content-types-for-file-association.advice=Specify only one MIME type for File Association number {0} -error.tool-not-found=Can not find {0}. Reason: {1} -error.tool-not-found.advice=Please install {0} -error.tool-old-version=Can not find {0} {1} or newer -error.tool-old-version.advice=Please install {0} {1} or newer +error.tool-error=Can not validate "{0}". Reason: {1} +error.tool-not-executable="{0}" is not executable +error.tool-not-found=Can not find "{0}" +error.tool-not-found.advice=Please install "{0}" +error.tool-old-version=Can not find "{0}" {1} or newer +error.tool-old-version.advice=Please install "{0}" {1} or newer + error.jlink.failed=jlink failed with: {0} error.blocked.option=jlink option [{0}] is not permitted in --jlink-options error.no.name=Name not specified with --name and cannot infer one from app-image diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java index 211a55897d0..6d7532bbd74 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java @@ -24,21 +24,141 @@ */ package jdk.jpackage.internal.util; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + import java.io.ByteArrayInputStream; import java.io.IOException; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; +import java.util.stream.Stream; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.util.function.ThrowingSupplier; +import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.SAXException; +/** + * Property list (plist) file reader. + */ public final class PListReader { + public record Raw(String value, Type type) { + + public enum Type { + STRING, + BOOLEAN, + REAL, + INTEGER, + DATE, + DATA; + + private static Optional fromElementName(String name) { + switch (name) { + case "string" -> { + return Optional.of(STRING); + } + case "true" -> { + return Optional.of(BOOLEAN); + } + case "false" -> { + return Optional.of(BOOLEAN); + } + case "real" -> { + return Optional.of(REAL); + } + case "integer" -> { + return Optional.of(INTEGER); + } + case "date" -> { + return Optional.of(DATE); + } + case "data" -> { + return Optional.of(DATA); + } + default -> { + return Optional.empty(); + } + } + } + } + + public Raw { + Objects.requireNonNull(value); + Objects.requireNonNull(type); + } + + private static Optional tryCreate(Element e) { + return Type.fromElementName(e.getNodeName()).map(type -> { + if (type == Type.BOOLEAN) { + if ("true".equals(e.getNodeName())) { + return new Raw(Boolean.TRUE.toString(), type); + } else { + return new Raw(Boolean.FALSE.toString(), type); + } + } else { + return new Raw(e.getTextContent(), type); + } + }); + } + } + + /** + * Returns the contents of the the underlying "dict" element as a Map. + *

+ * The keys in the returned map are names of the properties. + *

+ * Values of nested "dict" properties are stored as {@code Map} + * or {@code PListReader} objects depending on the value of the + * {@code fetchDictionaries} parameter. + *

+ * Values of "array" properties are stored as {@code List} objects. + *

+ * Values of other properties are stored as {@code Raw} objects. + * + * @param fetchDictionaries controls the type of objects of nested "dict" + * elements. If the value is {@code true}, + * {@code Map} type is used, and + * {@code PListReader} type otherwise. + * @return the contents of the the underlying "dict" element as a Map + */ + public Map toMap(boolean fetchDictionaries) { + Map reply = new HashMap<>(); + var nodes = root.getChildNodes(); + for (int i = 0; i != nodes.getLength(); i++) { + if (nodes.item(i) instanceof Element e) { + tryCreateValue(e, fetchDictionaries).ifPresent(value -> { + final var query = "preceding-sibling::*[1]"; + Optional.ofNullable(toSupplier(() -> { + return (Node) XPathSingleton.INSTANCE.evaluate(query, e, XPathConstants.NODE); + }).get()).ifPresent(n -> { + if ("key".equals(n.getNodeName())) { + var keyName = n.getTextContent(); + reply.putIfAbsent(keyName, value); + } + }); + }); + } + } + + return reply; + } + + /** + * Returns the value of the given string property in the underlying "dict" + * element. + * + * @param keyName the name of a string property whose value to query + * @return the value of the string property with the specified name in the + * underlying "dict" element + * @throws NoSuchElementException if there is no string property with the given + * name in the underlying "dict" element + */ public String queryValue(String keyName) { final var node = getNode(keyName); switch (node.getNodeName()) { @@ -51,6 +171,38 @@ public String queryValue(String keyName) { } } + /** + * Returns the value of the given "dict" property in the underlying "dict" + * element. + * + * @param keyName the name of a "dict" property whose value to query + * @return the value of the "dict" property with the specified name in the + * underlying "dict" element + * @throws NoSuchElementException if there is no "dict" property with the given + * name in the underlying "dict" element + */ + public PListReader queryDictValue(String keyName) { + final var node = getNode(keyName); + switch (node.getNodeName()) { + case "dict" -> { + return new PListReader(node); + } + default -> { + throw new NoSuchElementException(); + } + } + } + + /** + * Returns the value of the given boolean property in the underlying "dict" + * element. + * + * @param keyName the name of a boolean property whose value to query + * @return the value of the boolean property with the specified name in the + * underlying "dict" element + * @throws NoSuchElementException if there is no string property with the given + * name in the underlying "dict" element + */ public boolean queryBoolValue(String keyName) { final var node = getNode(keyName); switch (node.getNodeName()) { @@ -66,13 +218,58 @@ public boolean queryBoolValue(String keyName) { } } - public List queryArrayValue(String keyName) { + /** + * Returns the value of the given array property in the underlying "dict" + * element as a list of strings. + *

+ * Processes the result of calling {@link #queryArrayValue(String)} on the + * specified property name by filtering {@link Raw} instances of type + * {@link Raw.Type#STRING}. + * + * @param keyName the name of an array property whose value to query + * @return the value of the array property with the specified name in the + * underlying "dict" element + * @throws NoSuchElementException if there is no array property with the given + * name in the underlying "dict" element + */ + public List queryStringArrayValue(String keyName) { + return queryArrayValue(keyName, false).map(v -> { + if (v instanceof Raw r) { + if (r.type() == Raw.Type.STRING) { + return r.value(); + } + } + return (String)null; + }).filter(Objects::nonNull).toList(); + } + + /** + * Returns the value of the given array property in the underlying "dict" + * element as a stream of {@link Object}-s. + *

+ * Values of "dict" array items are stored as {@code Map} or + * {@code PListReader} objects depending on the value of the + * {@code fetchDictionaries} parameter. + *

+ * Values of "array" array items are stored as {@code List} objects. + *

+ * Values of other types are stored as {@code Raw} objects. + * + * @param keyName the name of an array property whose value to query + * @param fetchDictionaries controls the type of objects of "dict" elements. If + * the value is {@code true}, + * {@code Map} type is used, and + * {@code PListReader} type otherwise. + * @return the value of the array property with the specified name in the + * underlying "dict" element + * @throws NoSuchElementException if there is no array key with the given name + * in the underlying "dict" element + */ + public Stream queryArrayValue(String keyName, boolean fetchDictionaries) { final var node = getNode(keyName); switch (node.getNodeName()) { case "array" -> { - return XmlUtils.toStream(node.getChildNodes()).filter(n -> { - return n.getNodeName().equals("string"); - }).map(Node::getTextContent).toList(); + return readArray(node, fetchDictionaries); } default -> { throw new NoSuchElementException(); @@ -80,21 +277,75 @@ public List queryArrayValue(String keyName) { } } - public PListReader(Node doc) { - this.root = Objects.requireNonNull(doc); + /** + * Creates plist reader from the given node. + *

+ * If the specified node is an element with the name "dict", the reader is bound + * to the specified node; otherwise, it is bound to the {@code /plist/dict} + * element in the document. + * + * @param node the node + * @throws NoSuchElementException if the specified node is not an element with + * name "dict" and there is no + * {@code /plist/dict} node in the document + */ + public PListReader(Node node) { + Objects.requireNonNull(node); + if (node.getNodeName().equals("dict")) { + this.root = node; + } else { + this.root = Optional.ofNullable(toSupplier(() -> { + return (Node) XPathSingleton.INSTANCE.evaluate("/plist[1]/dict[1]", node, XPathConstants.NODE); + }).get()).orElseThrow(NoSuchElementException::new); + } } public PListReader(byte[] xmlData) throws ParserConfigurationException, SAXException, IOException { this(XmlUtils.initDocumentBuilder().parse(new ByteArrayInputStream(xmlData))); } + private Optional tryCreateValue(Element e, boolean fetchDictionaries) { + switch (e.getNodeName()) { + case "dict" -> { + var plistReader = new PListReader(e); + if (fetchDictionaries) { + return Optional.of(plistReader.toMap(fetchDictionaries)); + } else { + return Optional.of(plistReader); + } + } + case "array" -> { + return Optional.of(readArray(e, fetchDictionaries).toList()); + } + default -> { + return Raw.tryCreate(e); + } + } + } + + private Stream readArray(Node node, boolean fetchDictionaries) { + return XmlUtils.toStream(node.getChildNodes()).map(n -> { + if (n instanceof Element e) { + return tryCreateValue(e, fetchDictionaries); + } else { + return Optional.empty(); + } + }).filter(Optional::isPresent).map(Optional::get); + } + private Node getNode(String keyName) { - final var xPath = XPathFactory.newInstance().newXPath(); - final var query = String.format("//*[preceding-sibling::key = \"%s\"][1]", keyName); - return Optional.ofNullable(ThrowingSupplier.toSupplier(() -> { - return (Node) xPath.evaluate(query, root, XPathConstants.NODE); + Objects.requireNonNull(keyName); + final var query = String.format("*[preceding-sibling::key = \"%s\"][1]", keyName); + return Optional.ofNullable(toSupplier(() -> { + return (Node) XPathSingleton.INSTANCE.evaluate(query, root, XPathConstants.NODE); }).get()).orElseThrow(NoSuchElementException::new); } + + private static final class XPathSingleton { + private static final XPath INSTANCE = XPathFactory.newInstance().newXPath(); + } + + private final Node root; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/Result.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/Result.java new file mode 100644 index 00000000000..7bd6408183a --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/Result.java @@ -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. + * + * 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.jpackage.internal.util; + +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; +import java.util.stream.StreamSupport; + + +public record Result(Optional value, Collection errors) { + public Result { + if (value.isEmpty() == errors.isEmpty()) { + throw new IllegalArgumentException(); + } + + if (value.isEmpty() && errors.isEmpty()) { + throw new IllegalArgumentException("Error collection must be non-empty"); + } + + } + + public T orElseThrow() { + firstError().ifPresent(ex -> { + rethrowUnchecked(ex); + }); + return value.orElseThrow(); + } + + public boolean hasValue() { + return value.isPresent(); + } + + public boolean hasErrors() { + return !errors.isEmpty(); + } + + public Result map(Function conv) { + return new Result<>(value.map(conv), errors); + } + + public Result flatMap(Function> conv) { + return value.map(conv).orElseGet(() -> { + return new Result<>(Optional.empty(), errors); + }); + } + + public Result mapErrors(UnaryOperator> errorsMapper) { + return new Result<>(value, errorsMapper.apply(errors)); + } + + public Result mapErrors() { + return new Result<>(Optional.empty(), errors); + } + + public Result peekErrors(Consumer> consumer) { + if (hasErrors()) { + consumer.accept(errors); + } + return this; + } + + public Result peekValue(Consumer consumer) { + value.ifPresent(consumer); + return this; + } + + public Optional firstError() { + return errors.stream().findFirst(); + } + + public static Result create(Supplier supplier) { + try { + return ofValue(supplier.get()); + } catch (Exception ex) { + return ofError(ex); + } + } + + public static Result ofValue(T value) { + return new Result<>(Optional.of(value), List.of()); + } + + public static Result ofErrors(Collection errors) { + return new Result<>(Optional.empty(), List.copyOf(errors)); + } + + public static Result ofError(Exception error) { + return ofErrors(List.of(error)); + } + + public static boolean allHaveValues(Iterable> results) { + return StreamSupport.stream(results.spliterator(), false).allMatch(Result::hasValue); + } + + public static boolean allHaveValues(Result... results) { + return allHaveValues(List.of(results)); + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index 54f43f05715..9ce758eb3c7 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -24,17 +24,11 @@ */ package jdk.jpackage.internal; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; -import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; - -import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardCopyOption; import java.util.Map; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.WinExePackage; +import jdk.jpackage.internal.model.WinMsiPackage; @SuppressWarnings("restricted") public class WinExeBundler extends AbstractBundler { @@ -79,63 +73,23 @@ public Path execute(Map params, Path outdir) throws PackagerException { // Order is important! - var pkg = WinFromParams.MSI_PACKAGE.fetchFrom(params); + var pkg = WinFromParams.EXE_PACKAGE.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - IOUtils.writableOutputDir(outdir); - - Path msiDir = env.buildRoot().resolve("msi"); - toRunnable(() -> Files.createDirectories(msiDir)).run(); - - // Write msi to temporary directory. - Path msi = msiBundler.execute(params, msiDir); - - try { - new ScriptRunner() - .setDirectory(msi.getParent()) - .setResourceCategoryId("resource.post-msi-script") - .setScriptNameSuffix("post-msi") - .setEnvironmentVariable("JpMsiFile", msi.toAbsolutePath().toString()) - .run(env, pkg.packageName()); - - var exePkg = new WinExePackageBuilder(pkg).icon(ICON.fetchFrom(params)).create(); - return buildEXE(env, exePkg, msi, outdir); - } catch (IOException|ConfigException ex) { - Log.verbose(ex); - throw new PackagerException(ex); - } + var msiOutputDir = env.buildRoot().resolve("msi"); + + return Packager.build().outputDir(msiOutputDir) + .pkg(pkg.msiPackage()) + .env(env) + .pipelineBuilderMutatorFactory((packagingEnv, msiPackage, _) -> { + var msiPackager = new WinMsiPackager(packagingEnv, msiPackage, + msiOutputDir, msiBundler.sysEnv.orElseThrow()); + var exePackager = new WinExePackager(packagingEnv, pkg, outdir, msiOutputDir); + return msiPackager.andThen(exePackager); + }).execute(WinPackagingPipeline.build()); } - private Path buildEXE(BuildEnv env, WinExePackage pkg, Path msi, - Path outdir) throws IOException { - - Log.verbose(I18N.format("message.outputting-to-location", outdir.toAbsolutePath())); - - // Copy template msi wrapper next to msi file - final Path exePath = msi.getParent().resolve(pkg.packageFileNameWithSuffix()); - - env.createResource("msiwrapper.exe") - .setCategory(I18N.getString("resource.installer-exe")) - .setPublicName("installer.exe") - .saveToFile(exePath); - - new ExecutableRebrander(pkg, env::createResource, resourceLock -> { - // Embed msi in msi wrapper exe. - embedMSI(resourceLock, msi.toAbsolutePath().toString()); - }).execute(env, exePath, pkg.icon()); - - Path dstExePath = outdir.resolve(exePath.getFileName()); - - Files.copy(exePath, dstExePath, StandardCopyOption.REPLACE_EXISTING); - - dstExePath.toFile().setExecutable(true); - - Log.verbose(I18N.format("message.output-location", outdir.toAbsolutePath())); - - return dstExePath; - } + static native int embedMSI(long resourceLock, String msiPath); private final WinMsiBundler msiBundler = new WinMsiBundler(); - - private static native int embedMSI(long resourceLock, String msiPath); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java new file mode 100644 index 00000000000..9a13a0f954d --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java @@ -0,0 +1,108 @@ +/* + * 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.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Objects; +import java.util.function.Consumer; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; +import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; +import jdk.jpackage.internal.PackagingPipeline.TaskID; +import jdk.jpackage.internal.model.WinExePackage; + +final record WinExePackager(BuildEnv env, WinExePackage pkg, Path outputDir, Path msiOutputDir) implements Consumer { + + WinExePackager { + Objects.requireNonNull(env); + Objects.requireNonNull(pkg); + Objects.requireNonNull(outputDir); + Objects.requireNonNull(msiOutputDir); + } + + enum ExePackageTaskID implements TaskID { + RUN_POST_MSI_USER_SCRIPT, + WRAP_MSI_IN_EXE + } + + @Override + public void accept(PackagingPipeline.Builder pipelineBuilder) { + pipelineBuilder.excludeDirFromCopying(outputDir) + .task(ExePackageTaskID.RUN_POST_MSI_USER_SCRIPT) + .action(this::runPostMsiScript) + .addDependency(PackageTaskID.CREATE_PACKAGE_FILE) + .add() + .task(ExePackageTaskID.WRAP_MSI_IN_EXE) + .action(this::wrapMsiInExe) + .addDependency(ExePackageTaskID.RUN_POST_MSI_USER_SCRIPT) + .addDependent(PrimaryTaskID.PACKAGE) + .add(); + } + + private Path msi() { + return msiOutputDir.resolve(pkg.msiPackage().packageFileNameWithSuffix()); + } + + private void runPostMsiScript() throws IOException { + new ScriptRunner() + .setDirectory(msiOutputDir) + .setResourceCategoryId("resource.post-msi-script") + .setScriptNameSuffix("post-msi") + .setEnvironmentVariable("JpMsiFile", msi().toAbsolutePath().toString()) + .run(env, pkg.msiPackage().packageName()); + } + + private void wrapMsiInExe() throws IOException { + + Log.verbose(I18N.format("message.outputting-to-location", outputDir.toAbsolutePath())); + + final var msi = msi(); + + // Copy template msi wrapper next to msi file + final Path exePath = msi.getParent().resolve(pkg.packageFileNameWithSuffix()); + + env.createResource("msiwrapper.exe") + .setCategory(I18N.getString("resource.installer-exe")) + .setPublicName("installer.exe") + .saveToFile(exePath); + + new ExecutableRebrander(pkg, env::createResource, resourceLock -> { + // Embed msi in msi wrapper exe. + WinExeBundler.embedMSI(resourceLock, msi.toAbsolutePath().toString()); + }).execute(env, exePath, pkg.icon()); + + Path dstExePath = outputDir.resolve(exePath.getFileName()); + + Files.createDirectories(dstExePath.getParent()); + Files.copy(exePath, dstExePath, StandardCopyOption.REPLACE_EXISTING); + + dstExePath.toFile().setExecutable(true); + + Log.verbose(I18N.format("message.output-location", outputDir.toAbsolutePath())); + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java index e2259535058..29c1b665f86 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -31,6 +31,7 @@ import static jdk.jpackage.internal.FromParams.createPackageBuilder; import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; import static jdk.jpackage.internal.FromParams.findLauncherShortcut; +import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; import static jdk.jpackage.internal.WinPackagingPipeline.APPLICATION_LAYOUT; import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; @@ -41,6 +42,7 @@ import java.util.UUID; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.WinApplication; +import jdk.jpackage.internal.model.WinExePackage; import jdk.jpackage.internal.model.WinLauncher; import jdk.jpackage.internal.model.WinLauncherMixin; import jdk.jpackage.internal.model.WinMsiPackage; @@ -99,12 +101,26 @@ private static WinMsiPackage createWinMsiPackage(Map par return pkgBuilder.create(); } + private static WinExePackage createWinExePackage(Map params) throws ConfigException, IOException { + + final var msiPkg = MSI_PACKAGE.fetchFrom(params); + + final var pkgBuilder = new WinExePackageBuilder(msiPkg); + + ICON.copyInto(params, pkgBuilder::icon); + + return pkgBuilder.create(); + } + static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( WinFromParams::createWinApplication); static final BundlerParamInfo MSI_PACKAGE = createPackageBundlerParam( WinFromParams::createWinMsiPackage); + static final BundlerParamInfo EXE_PACKAGE = createPackageBundlerParam( + WinFromParams::createWinExePackage); + private static final BundlerParamInfo WIN_MENU_HINT = createStringBundlerParam( Arguments.CLIOptions.WIN_MENU_HINT.getId()); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 9bd0c679146..3ca26f38f82 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -27,115 +27,16 @@ import static jdk.jpackage.internal.model.ConfigException.rethrowConfigException; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.io.Writer; -import java.nio.charset.Charset; -import java.nio.file.FileSystems; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.PackagingPipeline.PackageBuildEnv; -import jdk.jpackage.internal.model.AppImageLayout; -import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.model.WinMsiPackage; -import org.w3c.dom.Document; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; +import jdk.jpackage.internal.util.Result; -/** - * WinMsiBundler - * - * Produces .msi installer from application image. Uses WiX Toolkit to build - * .msi installer. - *

- * {@link #execute} method creates a number of source files with the description - * of installer to be processed by WiX tools. Generated source files are stored - * in "config" subdirectory next to "app" subdirectory in the root work - * directory. The following WiX source files are generated: - *

    - *
  • main.wxs. Main source file with the installer description - *
  • bundle.wxf. Source file with application and Java run-time directory tree - * description. - *
  • ui.wxf. Source file with UI description of the installer. - *
- * - *

- * main.wxs file is a copy of main.wxs resource from - * jdk.jpackage.internal.resources package. It is parametrized with the - * following WiX variables: - *

    - *
  • JpAppName. Name of the application. Set to the value of --name command - * line option - *
  • JpAppVersion. Version of the application. Set to the value of - * --app-version command line option - *
  • JpAppVendor. Vendor of the application. Set to the value of --vendor - * command line option - *
  • JpAppDescription. Description of the application. Set to the value of - * --description command line option - *
  • JpProductCode. Set to product code UUID of the application. Random value - * generated by jpackage every time {@link #execute} method is called - *
  • JpProductUpgradeCode. Set to upgrade code UUID of the application. Random - * value generated by jpackage every time {@link #execute} method is called if - * --win-upgrade-uuid command line option is not specified. Otherwise this - * variable is set to the value of --win-upgrade-uuid command line option - *
  • JpAllowUpgrades. Set to "yes", but all that matters is it is defined. - *
  • JpAllowDowngrades. Defined for application installers, and undefined for - * Java runtime installers. - *
  • JpConfigDir. Absolute path to the directory with generated WiX source - * files. - *
  • JpIsSystemWide. Set to "yes" if --win-per-user-install command line - * option was not specified. Undefined otherwise - *
  • JpAppSizeKb. Set to estimated size of the application in kilobytes - *
  • JpHelpURL. Set to value of --win-help-url command line option if it - * was specified. Undefined otherwise - *
  • JpAboutURL. Set to value of --about-url command line option if it - * was specified. Undefined otherwise - *
  • JpUpdateURL. Set to value of --win-update-url command line option if it - * was specified. Undefined otherwise - *
- * - *

- * ui.wxf file is generated based on --license-file, --win-shortcut-prompt, - * --win-dir-chooser command line options. It is parametrized with the following - * WiX variables: - *

    - *
  • JpLicenseRtf. Set to the value of --license-file command line option. - * Undefined if --license-file command line option was not specified - *
- */ public class WinMsiBundler extends AbstractBundler { public WinMsiBundler() { - wixFragments = Stream.of( - Map.entry("bundle.wxf", new WixAppImageFragmentBuilder()), - Map.entry("ui.wxf", new WixUiFragmentBuilder()), - Map.entry("os-condition.wxf", OSVersionCondition.createWixFragmentBuilder()) - ).map(e -> { - e.getValue().setOutputFileName(e.getKey()); - return e.getValue(); - }).toList(); } @Override @@ -156,10 +57,12 @@ public String getBundleType() { @Override public boolean supported(boolean platformInstaller) { try { - if (wixToolset == null) { - wixToolset = WixTool.createToolset(); + try { + sysEnv.orElseThrow(); + return true; + } catch (RuntimeException ex) { + ConfigException.rethrowConfigException(ex); } - return true; } catch (ConfigException ce) { Log.error(ce.getMessage()); if (ce.getAdvice() != null) { @@ -184,9 +87,7 @@ public boolean validate(Map params) WinFromParams.APPLICATION.fetchFrom(params); BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - if (wixToolset == null) { - wixToolset = WixTool.createToolset(); - } + final var wixToolset = sysEnv.orElseThrow().wixToolset(); for (var tool : wixToolset.getType().getTools()) { Log.verbose(I18N.format("message.tool-version", @@ -194,367 +95,23 @@ public boolean validate(Map params) wixToolset.getVersion())); } - wixFragments.forEach(wixFragment -> wixFragment.setWixVersion(wixToolset.getVersion(), - wixToolset.getType())); - - wixFragments.stream().map(WixFragmentBuilder::getLoggableWixFeatures).flatMap( - List::stream).distinct().toList().forEach(Log::verbose); - return true; } catch (RuntimeException re) { throw rethrowConfigException(re); } } - private void prepareProto(Package pkg, BuildEnv env, AppImageLayout appImageLayout) throws - PackagerException, IOException { - - // Configure installer icon - if (appImageLayout instanceof RuntimeLayout runtimeLayout) { - // Use icon from java launcher. - // Assume java.exe exists in Java Runtime being packed. - // Ignore custom icon if any as we don't want to copy anything in - // Java Runtime image. - installerIcon = runtimeLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")); - } else if (appImageLayout instanceof ApplicationLayout appLayout) { - installerIcon = appLayout.launchersDirectory().resolve( - pkg.app().mainLauncher().orElseThrow().executableNameWithSuffix()); - } - installerIcon = installerIcon.toAbsolutePath(); - - pkg.licenseFile().ifPresent(licenseFile -> { - // need to copy license file to the working directory - // and convert to rtf if needed - Path destFile = env.configDir().resolve(licenseFile.getFileName()); - - try { - IOUtils.copyFile(licenseFile, destFile); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - destFile.toFile().setWritable(true); - ensureByMutationFileIsRTF(destFile); - }); - } - @Override public Path execute(Map params, Path outputParentDir) throws PackagerException { - IOUtils.writableOutputDir(outputParentDir); - - // Order is important! - var pkg = WinFromParams.MSI_PACKAGE.fetchFrom(params); - var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - - WinPackagingPipeline.build() - .excludeDirFromCopying(outputParentDir) - .task(PackagingPipeline.PackageTaskID.CREATE_CONFIG_FILES) - .packageAction(this::prepareConfigFiles) - .add() - .task(PackagingPipeline.PackageTaskID.CREATE_PACKAGE_FILE) - .packageAction(this::buildPackage) - .add() - .create().execute(env, pkg, outputParentDir); - - return outputParentDir.resolve(pkg.packageFileNameWithSuffix()).toAbsolutePath(); - } - - private void prepareConfigFiles(PackageBuildEnv env) throws PackagerException, IOException { - prepareProto(env.pkg(), env.env(), env.resolvedLayout()); - for (var wixFragment : wixFragments) { - wixFragment.initFromParams(env.env(), env.pkg()); - wixFragment.addFilesToConfigRoot(); - } - - final var msiOut = env.outputDir().resolve(env.pkg().packageFileNameWithSuffix()); - - Log.verbose(I18N.format("message.preparing-msi-config", msiOut.toAbsolutePath())); - - final var wixVars = createWixVars(env); - - final var wixObjDir = env.env().buildRoot().resolve("wixobj"); - - final var configDir = env.env().configDir(); - - final var wixPipelineBuilder = WixPipeline.build() - .setWixObjDir(wixObjDir) - .setWorkDir(env.env().appImageDir()) - .addSource(configDir.resolve("main.wxs"), wixVars); - - for (var wixFragment : wixFragments) { - wixFragment.configureWixPipeline(wixPipelineBuilder); - } - - switch (wixToolset.getType()) { - case Wix3 -> { - wixPipelineBuilder.addLightOptions("-sice:ICE27"); - - if (!env.pkg().isSystemWideInstall()) { - wixPipelineBuilder.addLightOptions("-sice:ICE91"); - } - } - case Wix4 -> { - } - default -> { - throw new IllegalArgumentException(); - } - } - - var primaryWxlFiles = Stream.of("de", "en", "ja", "zh_CN").map(loc -> { - return configDir.resolve("MsiInstallerStrings_" + loc + ".wxl"); - }).toList(); - - var wixResources = new WixSourceConverter.ResourceGroup(wixToolset.getType()); - - // Copy standard l10n files. - for (var path : primaryWxlFiles) { - var name = path.getFileName().toString(); - wixResources.addResource(env.env().createResource(name).setPublicName(name).setCategory( - I18N.getString("resource.wxl-file")), path); - } - - wixResources.addResource(env.env().createResource("main.wxs").setPublicName("main.wxs"). - setCategory(I18N.getString("resource.main-wix-file")), configDir.resolve("main.wxs")); - - wixResources.addResource(env.env().createResource("overrides.wxi").setPublicName( - "overrides.wxi").setCategory(I18N.getString("resource.overrides-wix-file")), - configDir.resolve("overrides.wxi")); - - // Filter out custom l10n files that were already used to - // override primary l10n files. Ignore case filename comparison, - // both lists are expected to be short. - List customWxlFiles = env.env().resourceDir() - .map(WinMsiBundler::getWxlFilesFromDir) - .orElseGet(Collections::emptyList) - .stream() - .filter(custom -> primaryWxlFiles.stream().noneMatch(primary -> - primary.getFileName().toString().equalsIgnoreCase( - custom.getFileName().toString()))) - .peek(custom -> Log.verbose(I18N.format( - "message.using-custom-resource", String.format("[%s]", - I18N.getString("resource.wxl-file")), - custom.getFileName()))).toList(); - - // Copy custom l10n files. - for (var path : customWxlFiles) { - var name = path.getFileName().toString(); - wixResources.addResource(env.env().createResource(name).setPublicName(name). - setSourceOrder(OverridableResource.Source.ResourceDir).setCategory(I18N. - getString("resource.wxl-file")), configDir.resolve(name)); - } - - // Save all WiX resources into config dir. - wixResources.saveResources(); - - // All l10n files are supplied to WiX with "-loc", but only - // Cultures from custom files and a single primary Culture are - // included into "-cultures" list - for (var wxl : primaryWxlFiles) { - wixPipelineBuilder.addLightOptions("-loc", wxl.toString()); - } - - List cultures = new ArrayList<>(); - for (var wxl : customWxlFiles) { - wxl = configDir.resolve(wxl.getFileName()); - wixPipelineBuilder.addLightOptions("-loc", wxl.toString()); - cultures.add(getCultureFromWxlFile(wxl)); - } - - // Append a primary culture bases on runtime locale. - final Path primaryWxlFile = configDir.resolve( - I18N.getString("resource.wxl-file-name")); - cultures.add(getCultureFromWxlFile(primaryWxlFile)); - - // Build ordered list of unique cultures. - Set uniqueCultures = new LinkedHashSet<>(); - uniqueCultures.addAll(cultures); - switch (wixToolset.getType()) { - case Wix3 -> { - wixPipelineBuilder.addLightOptions(uniqueCultures.stream().collect(Collectors.joining(";", - "-cultures:", ""))); - } - case Wix4 -> { - uniqueCultures.forEach(culture -> { - wixPipelineBuilder.addLightOptions("-culture", culture); - }); - } - default -> { - throw new IllegalArgumentException(); - } - } - - Files.createDirectories(wixObjDir); - wixPipeline = wixPipelineBuilder.create(wixToolset); - } - - private void buildPackage(PackageBuildEnv env) throws PackagerException, IOException { - final var msiOut = env.outputDir().resolve(env.pkg().packageFileNameWithSuffix()); - Log.verbose(I18N.format("message.generating-msi", msiOut.toAbsolutePath())); - wixPipeline.buildMsi(msiOut.toAbsolutePath()); - } - - private Map createWixVars(PackageBuildEnv env) throws IOException { - Map data = new HashMap<>(); - - final var pkg = env.pkg(); - - data.put("JpProductCode", pkg.productCode().toString()); - data.put("JpProductUpgradeCode", pkg.upgradeCode().toString()); - - Log.verbose(I18N.format("message.product-code", pkg.productCode())); - Log.verbose(I18N.format("message.upgrade-code", pkg.upgradeCode())); - - data.put("JpAllowUpgrades", "yes"); - if (!pkg.isRuntimeInstaller()) { - data.put("JpAllowDowngrades", "yes"); - } - - data.put("JpAppName", pkg.packageName()); - data.put("JpAppDescription", pkg.description()); - data.put("JpAppVendor", pkg.app().vendor()); - data.put("JpAppVersion", pkg.version()); - if (Files.exists(installerIcon)) { - data.put("JpIcon", installerIcon.toString()); - } - - pkg.helpURL().ifPresent(value -> { - data.put("JpHelpURL", value); - }); - - pkg.updateURL().ifPresent(value -> { - data.put("JpUpdateURL", value); - }); - - pkg.aboutURL().ifPresent(value -> { - data.put("JpAboutURL", value); - }); - - data.put("JpAppSizeKb", Long.toString(AppImageLayout.toPathGroup( - env.resolvedLayout()).sizeInBytes() >> 10)); - - data.put("JpConfigDir", env.env().configDir().toAbsolutePath().toString()); - - if (pkg.isSystemWideInstall()) { - data.put("JpIsSystemWide", "yes"); - } - - return data; - } - - private static List getWxlFilesFromDir(Path dir) { - final String glob = "glob:**/*.wxl"; - final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher( - glob); - - try (var walk = Files.walk(dir, 1)) { - return walk - .filter(Files::isReadable) - .filter(pathMatcher::matches) - .sorted((a, b) -> a.getFileName().toString().compareToIgnoreCase(b.getFileName().toString())) - .toList(); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - } - - private static String getCultureFromWxlFile(Path wxlPath) { - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(false); - DocumentBuilder builder = factory.newDocumentBuilder(); - - Document doc = builder.parse(wxlPath.toFile()); - - XPath xPath = XPathFactory.newInstance().newXPath(); - NodeList nodes = (NodeList) xPath.evaluate( - "//WixLocalization/@Culture", doc, XPathConstants.NODESET); - if (nodes.getLength() != 1) { - throw new IOException(I18N.format( - "error.extract-culture-from-wix-l10n-file", - wxlPath.toAbsolutePath().normalize())); - } - - return nodes.item(0).getNodeValue(); - } catch (XPathExpressionException | ParserConfigurationException - | SAXException ex) { - throw new UncheckedIOException(new IOException( - I18N.format("error.read-wix-l10n-file", wxlPath.toAbsolutePath().normalize()), ex)); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - } - - private static void ensureByMutationFileIsRTF(Path f) { - try { - boolean existingLicenseIsRTF = false; - - try (InputStream fin = Files.newInputStream(f)) { - byte[] firstBits = new byte[7]; - - if (fin.read(firstBits) == firstBits.length) { - String header = new String(firstBits); - existingLicenseIsRTF = "{\\rtf1\\".equals(header); - } - } - - if (!existingLicenseIsRTF) { - List oldLicense = Files.readAllLines(f); - try (Writer w = Files.newBufferedWriter( - f, Charset.forName("Windows-1252"))) { - w.write("{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033" - + "{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}}\n" - + "\\viewkind4\\uc1\\pard\\sa200\\sl276" - + "\\slmult1\\lang9\\fs20 "); - oldLicense.forEach(l -> { - try { - for (char c : l.toCharArray()) { - // 0x00 <= ch < 0x20 Escaped (\'hh) - // 0x20 <= ch < 0x80 Raw(non - escaped) char - // 0x80 <= ch <= 0xFF Escaped(\ 'hh) - // 0x5C, 0x7B, 0x7D (special RTF characters - // \,{,})Escaped(\'hh) - // ch > 0xff Escaped (\\ud###?) - if (c < 0x10) { - w.write("\\'0"); - w.write(Integer.toHexString(c)); - } else if (c > 0xff) { - w.write("\\ud"); - w.write(Integer.toString(c)); - // \\uc1 is in the header and in effect - // so we trail with a replacement char if - // the font lacks that character - '?' - w.write("?"); - } else if ((c < 0x20) || (c >= 0x80) || - (c == 0x5C) || (c == 0x7B) || - (c == 0x7D)) { - w.write("\\'"); - w.write(Integer.toHexString(c)); - } else { - w.write(c); - } - } - // blank lines are interpreted as paragraph breaks - if (l.length() < 1) { - w.write("\\par"); - } else { - w.write(" "); - } - w.write("\r\n"); - } catch (IOException e) { - Log.verbose(e); - } - }); - w.write("}\r\n"); - } - } - } catch (IOException e) { - Log.verbose(e); - } + return Packager.build().outputDir(outputParentDir) + .pkg(WinFromParams.MSI_PACKAGE.fetchFrom(params)) + .env(BuildEnvFromParams.BUILD_ENV.fetchFrom(params)) + .pipelineBuilderMutatorFactory((env, pkg, outputDir) -> { + return new WinMsiPackager(env, pkg, outputDir, sysEnv.orElseThrow()); + }).execute(WinPackagingPipeline.build()); } - private Path installerIcon; - private WixToolset wixToolset; - private WixPipeline wixPipeline; - private final List wixFragments; + final Result sysEnv = WinSystemEnvironment.create(); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java new file mode 100644 index 00000000000..99b6c367fec --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java @@ -0,0 +1,486 @@ +/* + * 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.jpackage.internal; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.io.Writer; +import java.nio.charset.Charset; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.RuntimeLayout; +import jdk.jpackage.internal.model.WinMsiPackage; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +/** + * WinMsiPackager + * + * Produces .msi installer from application image. Uses WiX Toolkit to build + * .msi installer. + *

+ * Creates a number of source files with the description + * of installer to be processed by WiX tools. Generated source files are stored + * in "config" subdirectory next to "app" subdirectory in the root work + * directory. The following WiX source files are generated: + *

    + *
  • main.wxs. Main source file with the installer description + *
  • bundle.wxf. Source file with application and Java run-time directory tree + * description. + *
  • ui.wxf. Source file with UI description of the installer. + *
+ * + *

+ * main.wxs file is a copy of main.wxs resource from + * jdk.jpackage.internal.resources package. It is parametrized with the + * following WiX variables: + *

    + *
  • JpAppName. Name of the application. Set to the value of --name command + * line option + *
  • JpAppVersion. Version of the application. Set to the value of + * --app-version command line option + *
  • JpAppVendor. Vendor of the application. Set to the value of --vendor + * command line option + *
  • JpAppDescription. Description of the application. Set to the value of + * --description command line option + *
  • JpProductCode. Set to product code UUID of the application. Random value + * generated by jpackage every time {@link #execute} method is called + *
  • JpProductUpgradeCode. Set to upgrade code UUID of the application. Random + * value generated by jpackage every time {@link #execute} method is called if + * --win-upgrade-uuid command line option is not specified. Otherwise this + * variable is set to the value of --win-upgrade-uuid command line option + *
  • JpAllowUpgrades. Set to "yes", but all that matters is it is defined. + *
  • JpAllowDowngrades. Defined for application installers, and undefined for + * Java runtime installers. + *
  • JpConfigDir. Absolute path to the directory with generated WiX source + * files. + *
  • JpIsSystemWide. Set to "yes" if --win-per-user-install command line + * option was not specified. Undefined otherwise + *
  • JpAppSizeKb. Set to estimated size of the application in kilobytes + *
  • JpHelpURL. Set to value of --win-help-url command line option if it + * was specified. Undefined otherwise + *
  • JpAboutURL. Set to value of --about-url command line option if it + * was specified. Undefined otherwise + *
  • JpUpdateURL. Set to value of --win-update-url command line option if it + * was specified. Undefined otherwise + *
+ * + *

+ * ui.wxf file is generated based on --license-file, --win-shortcut-prompt, + * --win-dir-chooser command line options. It is parametrized with the following + * WiX variables: + *

    + *
  • JpLicenseRtf. Set to the value of --license-file command line option. + * Undefined if --license-file command line option was not specified + *
+ */ +final class WinMsiPackager implements Consumer { + + WinMsiPackager(BuildEnv env, WinMsiPackage pkg, Path outputDir, WixToolset wixToolset) { + this.pkg = Objects.requireNonNull(pkg); + this.env = Objects.requireNonNull(env); + this.outputDir = Objects.requireNonNull(outputDir); + this.wixToolset = Objects.requireNonNull(wixToolset); + + wixFragments = Stream.of( + Map.entry("bundle.wxf", new WixAppImageFragmentBuilder()), + Map.entry("ui.wxf", new WixUiFragmentBuilder()), + Map.entry("os-condition.wxf", OSVersionCondition.createWixFragmentBuilder()) + ).map(e -> { + e.getValue().setOutputFileName(e.getKey()); + return e.getValue(); + }).toList(); + + // Configure installer icon + if (env.appImageLayout() instanceof RuntimeLayout runtimeLayout) { + // Use icon from java launcher. + // Assume java.exe exists in Java Runtime being packed. + // Ignore custom icon if any as we don't want to copy anything in + // Java Runtime image. + installerIcon = runtimeLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")).toAbsolutePath(); + } else { + installerIcon = env.asApplicationLayout().orElseThrow().launchersDirectory().resolve( + pkg.app().mainLauncher().orElseThrow().executableNameWithSuffix()).toAbsolutePath(); + } + + wixFragments.forEach(wixFragment -> wixFragment.setWixVersion(wixToolset.getVersion(), + wixToolset.getType())); + + wixFragments.stream().map(WixFragmentBuilder::getLoggableWixFeatures).flatMap( + List::stream).distinct().toList().forEach(Log::verbose); + } + + WinMsiPackager(BuildEnv env, WinMsiPackage pkg, Path outputDir, WinSystemEnvironment sysEnv) { + this(env, pkg, outputDir, sysEnv.wixToolset()); + } + + @Override + public void accept(PackagingPipeline.Builder pipelineBuilder) { + pipelineBuilder.excludeDirFromCopying(outputDir) + .task(PackagingPipeline.PackageTaskID.CREATE_CONFIG_FILES) + .action(this::prepareConfigFiles) + .add() + .task(PackagingPipeline.PackageTaskID.CREATE_PACKAGE_FILE) + .action(this::buildPackage) + .add(); + } + + private void prepareConfigFiles() throws PackagerException, IOException { + + pkg.licenseFile().ifPresent(licenseFile -> { + // need to copy license file to the working directory + // and convert to rtf if needed + Path destFile = env.configDir().resolve(licenseFile.getFileName()); + + try { + IOUtils.copyFile(licenseFile, destFile); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + destFile.toFile().setWritable(true); + ensureByMutationFileIsRTF(destFile); + }); + + for (var wixFragment : wixFragments) { + wixFragment.initFromParams(env, pkg); + wixFragment.addFilesToConfigRoot(); + } + + final var msiOut = outputDir.resolve(pkg.packageFileNameWithSuffix()); + + Log.verbose(I18N.format("message.preparing-msi-config", msiOut.toAbsolutePath())); + + final var wixVars = createWixVars(); + + final var wixObjDir = env.buildRoot().resolve("wixobj"); + + final var configDir = env.configDir(); + + final var wixPipelineBuilder = WixPipeline.build() + .setWixObjDir(wixObjDir) + .setWorkDir(env.appImageDir()) + .addSource(configDir.resolve("main.wxs"), wixVars); + + for (var wixFragment : wixFragments) { + wixFragment.configureWixPipeline(wixPipelineBuilder); + } + + switch (wixToolset.getType()) { + case Wix3 -> { + wixPipelineBuilder.addLightOptions("-sice:ICE27"); + + if (!pkg.isSystemWideInstall()) { + wixPipelineBuilder.addLightOptions("-sice:ICE91"); + } + } + case Wix4 -> { + } + default -> { + throw new IllegalArgumentException(); + } + } + + var primaryWxlFiles = Stream.of("de", "en", "ja", "zh_CN").map(loc -> { + return configDir.resolve("MsiInstallerStrings_" + loc + ".wxl"); + }).toList(); + + var wixResources = new WixSourceConverter.ResourceGroup(wixToolset.getType()); + + // Copy standard l10n files. + for (var path : primaryWxlFiles) { + var name = path.getFileName().toString(); + wixResources.addResource(env.createResource(name).setPublicName(name).setCategory( + I18N.getString("resource.wxl-file")), path); + } + + wixResources.addResource(env.createResource("main.wxs").setPublicName("main.wxs"). + setCategory(I18N.getString("resource.main-wix-file")), configDir.resolve("main.wxs")); + + wixResources.addResource(env.createResource("overrides.wxi").setPublicName( + "overrides.wxi").setCategory(I18N.getString("resource.overrides-wix-file")), + configDir.resolve("overrides.wxi")); + + // Filter out custom l10n files that were already used to + // override primary l10n files. Ignore case filename comparison, + // both lists are expected to be short. + List customWxlFiles = env.resourceDir() + .map(WinMsiPackager::getWxlFilesFromDir) + .orElseGet(Collections::emptyList) + .stream() + .filter(custom -> primaryWxlFiles.stream().noneMatch(primary -> + primary.getFileName().toString().equalsIgnoreCase( + custom.getFileName().toString()))) + .peek(custom -> Log.verbose(I18N.format( + "message.using-custom-resource", String.format("[%s]", + I18N.getString("resource.wxl-file")), + custom.getFileName()))).toList(); + + // Copy custom l10n files. + for (var path : customWxlFiles) { + var name = path.getFileName().toString(); + wixResources.addResource(env.createResource(name).setPublicName(name). + setSourceOrder(OverridableResource.Source.ResourceDir).setCategory(I18N. + getString("resource.wxl-file")), configDir.resolve(name)); + } + + // Save all WiX resources into config dir. + wixResources.saveResources(); + + // All l10n files are supplied to WiX with "-loc", but only + // Cultures from custom files and a single primary Culture are + // included into "-cultures" list + for (var wxl : primaryWxlFiles) { + wixPipelineBuilder.addLightOptions("-loc", wxl.toString()); + } + + List cultures = new ArrayList<>(); + for (var wxl : customWxlFiles) { + wxl = configDir.resolve(wxl.getFileName()); + wixPipelineBuilder.addLightOptions("-loc", wxl.toString()); + cultures.add(getCultureFromWxlFile(wxl)); + } + + // Append a primary culture bases on runtime locale. + final Path primaryWxlFile = configDir.resolve( + I18N.getString("resource.wxl-file-name")); + cultures.add(getCultureFromWxlFile(primaryWxlFile)); + + // Build ordered list of unique cultures. + Set uniqueCultures = new LinkedHashSet<>(); + uniqueCultures.addAll(cultures); + switch (wixToolset.getType()) { + case Wix3 -> { + wixPipelineBuilder.addLightOptions(uniqueCultures.stream().collect(Collectors.joining(";", + "-cultures:", ""))); + } + case Wix4 -> { + uniqueCultures.forEach(culture -> { + wixPipelineBuilder.addLightOptions("-culture", culture); + }); + } + default -> { + throw new IllegalArgumentException(); + } + } + + Files.createDirectories(wixObjDir); + wixPipeline = wixPipelineBuilder.create(wixToolset); + } + + private void buildPackage() throws PackagerException, IOException { + final var msiOut = outputDir.resolve(pkg.packageFileNameWithSuffix()); + Log.verbose(I18N.format("message.generating-msi", msiOut.toAbsolutePath())); + wixPipeline.buildMsi(msiOut.toAbsolutePath()); + } + + private Map createWixVars() throws IOException { + Map data = new HashMap<>(); + + data.put("JpProductCode", pkg.productCode().toString()); + data.put("JpProductUpgradeCode", pkg.upgradeCode().toString()); + + Log.verbose(I18N.format("message.product-code", pkg.productCode())); + Log.verbose(I18N.format("message.upgrade-code", pkg.upgradeCode())); + + data.put("JpAllowUpgrades", "yes"); + if (!pkg.isRuntimeInstaller()) { + data.put("JpAllowDowngrades", "yes"); + } + + data.put("JpAppName", pkg.packageName()); + data.put("JpAppDescription", pkg.description()); + data.put("JpAppVendor", pkg.app().vendor()); + data.put("JpAppVersion", pkg.version()); + if (Files.exists(installerIcon)) { + data.put("JpIcon", installerIcon.toString()); + } + + pkg.helpURL().ifPresent(value -> { + data.put("JpHelpURL", value); + }); + + pkg.updateURL().ifPresent(value -> { + data.put("JpUpdateURL", value); + }); + + pkg.aboutURL().ifPresent(value -> { + data.put("JpAboutURL", value); + }); + + data.put("JpAppSizeKb", Long.toString(AppImageLayout.toPathGroup( + env.appImageLayout()).sizeInBytes() >> 10)); + + data.put("JpConfigDir", env.configDir().toAbsolutePath().toString()); + + if (pkg.isSystemWideInstall()) { + data.put("JpIsSystemWide", "yes"); + } + + return data; + } + + private static List getWxlFilesFromDir(Path dir) { + final String glob = "glob:**/*.wxl"; + final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher( + glob); + + try (var walk = Files.walk(dir, 1)) { + return walk + .filter(Files::isReadable) + .filter(pathMatcher::matches) + .sorted((a, b) -> a.getFileName().toString().compareToIgnoreCase(b.getFileName().toString())) + .toList(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + private static String getCultureFromWxlFile(Path wxlPath) { + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(false); + DocumentBuilder builder = factory.newDocumentBuilder(); + + Document doc = builder.parse(wxlPath.toFile()); + + XPath xPath = XPathFactory.newInstance().newXPath(); + NodeList nodes = (NodeList) xPath.evaluate( + "//WixLocalization/@Culture", doc, XPathConstants.NODESET); + if (nodes.getLength() != 1) { + throw new RuntimeException(I18N.format( + "error.extract-culture-from-wix-l10n-file", + wxlPath.toAbsolutePath().normalize())); + } + + return nodes.item(0).getNodeValue(); + } catch (XPathExpressionException | ParserConfigurationException | SAXException ex) { + throw new RuntimeException(I18N.format( + "error.read-wix-l10n-file", wxlPath.toAbsolutePath().normalize()), ex); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + private static void ensureByMutationFileIsRTF(Path f) { + try { + boolean existingLicenseIsRTF = false; + + try (InputStream fin = Files.newInputStream(f)) { + byte[] firstBits = new byte[7]; + + if (fin.read(firstBits) == firstBits.length) { + String header = new String(firstBits); + existingLicenseIsRTF = "{\\rtf1\\".equals(header); + } + } + + if (!existingLicenseIsRTF) { + List oldLicense = Files.readAllLines(f); + try (Writer w = Files.newBufferedWriter( + f, Charset.forName("Windows-1252"))) { + w.write("{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033" + + "{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}}\n" + + "\\viewkind4\\uc1\\pard\\sa200\\sl276" + + "\\slmult1\\lang9\\fs20 "); + oldLicense.forEach(l -> { + try { + for (char c : l.toCharArray()) { + // 0x00 <= ch < 0x20 Escaped (\'hh) + // 0x20 <= ch < 0x80 Raw(non - escaped) char + // 0x80 <= ch <= 0xFF Escaped(\ 'hh) + // 0x5C, 0x7B, 0x7D (special RTF characters + // \,{,})Escaped(\'hh) + // ch > 0xff Escaped (\\ud###?) + if (c < 0x10) { + w.write("\\'0"); + w.write(Integer.toHexString(c)); + } else if (c > 0xff) { + w.write("\\ud"); + w.write(Integer.toString(c)); + // \\uc1 is in the header and in effect + // so we trail with a replacement char if + // the font lacks that character - '?' + w.write("?"); + } else if ((c < 0x20) || (c >= 0x80) || + (c == 0x5C) || (c == 0x7B) || + (c == 0x7D)) { + w.write("\\'"); + w.write(Integer.toHexString(c)); + } else { + w.write(c); + } + } + // blank lines are interpreted as paragraph breaks + if (l.length() < 1) { + w.write("\\par"); + } else { + w.write(" "); + } + w.write("\r\n"); + } catch (IOException e) { + Log.verbose(e); + } + }); + w.write("}\r\n"); + } + } + } catch (IOException e) { + Log.verbose(e); + } + } + + private final WinMsiPackage pkg; + private final BuildEnv env; + private final Path outputDir; + private final WixToolset wixToolset; + private final List wixFragments; + private final Path installerIcon; + private WixPipeline wixPipeline; +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinSystemEnvironment.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinSystemEnvironment.java new file mode 100644 index 00000000000..33b5a09a31b --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinSystemEnvironment.java @@ -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. 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.jpackage.internal; + +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + +import java.util.Objects; +import jdk.jpackage.internal.util.Result; + +record WinSystemEnvironment(WixToolset wixToolset) implements SystemEnvironment { + + WinSystemEnvironment { + Objects.requireNonNull(wixToolset); + } + + static Result create() { + return Result.create(toSupplier(WixTool::createToolset)).map(WinSystemEnvironment::new); + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java index 7e4353876b4..6e72511e080 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java @@ -183,13 +183,12 @@ static Optional lookup(WixTool tool, Optional lookupDir) final boolean[] tooOld = new boolean[1]; final String[] parsedVersion = new String[1]; - final var validator = new ToolValidator(toolPath).setMinimalVersion(tool.minimalVersion). - setToolNotFoundErrorHandler((name, ex) -> { - return new ConfigException("", ""); - }).setToolOldVersionErrorHandler((name, version) -> { - tooOld[0] = true; - return null; - }); + final var validator = new ToolValidator(toolPath) + .setMinimalVersion(tool.minimalVersion) + .setToolOldVersionErrorHandler((name, version) -> { + tooOld[0] = true; + return null; + }); final Function, String> versionParser; diff --git a/src/jdk.jshell/share/classes/jdk/jshell/OuterWrapMap.java b/src/jdk.jshell/share/classes/jdk/jshell/OuterWrapMap.java index 6f7f3fe42c3..61fb3bdfc9a 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/OuterWrapMap.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/OuterWrapMap.java @@ -73,7 +73,11 @@ private CompoundWrap wrappedInClass(String className, String imports, List OuterWrap wrapInClass(Set except, Collection plus, List snippets, List wraps) { - String imports = state.maps.packageAndImportsExcept(except, plus); + List extraImports = + plus.stream() + .map(psi -> psi.importLine(state)) + .toList(); + String imports = state.maps.packageAndImportsExcept(except, extraImports); // className is unique to the set of snippets and their version (seq) String className = REPL_CLASS_PREFIX + snippets.stream() .sorted((sn1, sn2) -> sn1.key().index() - sn2.key().index()) @@ -86,9 +90,16 @@ OuterWrap wrapInClass(Set except, Collection plus, } OuterWrap wrapInTrialClass(Wrap wrap) { - String imports = state.maps.packageAndImportsExcept(null, null); + return wrapInTrialClass(List.of(), List.of(), wrap); + } + + OuterWrap wrapInTrialClass(List extraImports, List preWraps, Wrap wrap) { + String imports = state.maps.packageAndImportsExcept(null, extraImports); + List allWraps = new ArrayList<>(); + allWraps.addAll(preWraps); + allWraps.add(wrap); CompoundWrap w = wrappedInClass(REPL_DOESNOTMATTER_CLASS_NAME, imports, - Collections.singletonList(wrap)); + allWraps); return new OuterWrap(w); } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java b/src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java index bd0c9d86db3..992d97a7040 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java @@ -105,7 +105,7 @@ List snippetList() { return new ArrayList<>(snippets); } - String packageAndImportsExcept(Set except, Collection plus) { + String packageAndImportsExcept(Set except, Collection extraImports) { StringBuilder sb = new StringBuilder(); sb.append("package ").append(REPL_PACKAGE).append(";\n"); for (Snippet si : keyIndexToSnippet) { @@ -113,9 +113,7 @@ String packageAndImportsExcept(Set except, Collection plus) { sb.append(si.importLine(state)); } } - if (plus != null) { - plus.forEach(psi -> sb.append(psi.importLine(state))); - } + extraImports.forEach(sb::append); return sb.toString(); } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index 045734d9f55..19bad110a5d 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -300,17 +300,8 @@ private List completionSuggestionsImpl(String code, int cursor, int[ identifier = m.group(); } } - code = code.substring(0, cursor); - if (code.trim().isEmpty()) { //TODO: comment handling - code += ";"; - } - boolean[] moduleImport = new boolean[1]; - OuterWrap codeWrap = switch (guessKind(code, moduleImport)) { - case IMPORT -> moduleImport[0] ? proc.outerMap.wrapImport(Wrap.simpleWrap(code), null) - : proc.outerMap.wrapImport(Wrap.simpleWrap(code + "any.any"), null); - case CLASS, METHOD -> proc.outerMap.wrapInTrialClass(Wrap.classMemberWrap(code)); - default -> proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code)); - }; + + OuterWrap codeWrap = wrapCodeForCompletion(code, cursor, true); String[] requiredPrefix = new String[] {identifier}; return computeSuggestions(codeWrap, code, cursor, requiredPrefix, anchor).stream() .filter(s -> filteringText(s).startsWith(requiredPrefix[0]) && !s.continuation().equals(REPL_DOESNOTMATTER_CLASS_NAME)) @@ -1740,15 +1731,11 @@ public List documentation(String code, int cursor, boolean comput }; private List documentationImpl(String code, int cursor, boolean computeJavadoc) { - code = code.substring(0, cursor); - if (code.trim().isEmpty()) { //TODO: comment handling - code += ";"; - } - - if (guessKind(code) == Kind.IMPORT) + OuterWrap codeWrap = wrapCodeForCompletion(code, cursor, false); + if (codeWrap == null) { + //import: return Collections.emptyList(); - - OuterWrap codeWrap = proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code)); + } return proc.taskFactory.analyze(codeWrap, List.of(keepParameterNames), at -> { SourcePositions sp = at.trees().getSourcePositions(); CompilationUnitTree topLevel = at.firstCuTree(); @@ -2303,7 +2290,8 @@ private void appendModulePaths(MemoryFileManager fm, Location loc, Collection { try { long lastModified = Files.getLastModifiedTime(p).toMillis(); @@ -2334,6 +2322,10 @@ private ClassIndex indexForPath(Path path) { } } + private static boolean isJRTMarkerFile(Path path) { + return path.equals(Paths.get(System.getProperty("java.home"), "lib", "modules")); + } + //create an index based on the content of the given dirs; the original JavaFileManager entry is originalPath. private ClassIndex doIndex(long timestamp, Path originalPath, Iterable dirs) { Set packages = new HashSet<>(); @@ -2429,6 +2421,99 @@ public static void waitCurrentBackgroundTasksFinished() throws Exception { INDEXER.submit(() -> {}).get(); } + private OuterWrap wrapCodeForCompletion(String code, int cursor, boolean wrapImports) { + code = code.substring(0, cursor); + if (code.trim().isEmpty()) { //TODO: comment handling + code += ";"; + } + + List imports = new ArrayList<>(); + List declarationParts = new ArrayList<>(); + String lastImport = null; + boolean lastImportIsModuleImport = false; + Wrap declarationWrap = null; + Wrap pendingWrap = null; + String input = code; + boolean cont = true; + int startOffset = 0; + + while (cont) { + if (lastImport != null) { + imports.add(lastImport); + lastImport = null; + } + if (declarationWrap != null) { + declarationParts.add(declarationWrap); + declarationWrap = null; + pendingWrap = null; + } + + String current; + SourceCodeAnalysis.CompletionInfo completeness = analyzeCompletion(input); + int newStartOffset; + + if (completeness.completeness().isComplete() && !completeness.remaining().isBlank()) { + current = input.substring(0, input.length() - completeness.remaining().length()); + newStartOffset = startOffset + input.length() - completeness.remaining().length(); + input = completeness.remaining(); + cont = true; + } else { + current = input; + cont = false; + newStartOffset = startOffset; + } + + boolean[] moduleImport = new boolean[1]; + + switch (guessKind(current, moduleImport)) { + case IMPORT -> { + lastImport = current; + lastImportIsModuleImport = moduleImport[0]; + } + case CLASS, METHOD -> { + pendingWrap = declarationWrap = Wrap.classMemberWrap(whitespaces(code, startOffset) + current); + } + case VARIABLE -> { + declarationWrap = Wrap.classMemberWrap(whitespaces(code, startOffset) + current); + pendingWrap = Wrap.methodWrap(whitespaces(code, startOffset) + current); + } + default -> { + pendingWrap = declarationWrap = Wrap.methodWrap(whitespaces(code, startOffset) + current); + } + } + + startOffset = newStartOffset; + } + + if (lastImport != null) { + if (wrapImports) { + return proc.outerMap.wrapImport(Wrap.simpleWrap(whitespaces(code, startOffset) + lastImport + (!lastImportIsModuleImport ? "any.any" : "")), null); + } else { + return null; + } + } + + if (pendingWrap != null) { + return proc.outerMap.wrapInTrialClass(imports, declarationParts, pendingWrap); + } + + throw new IllegalStateException("No pending wrap for: " + code); + } + + private static String whitespaces(String input, int offset) { + StringBuilder result = new StringBuilder(); + + for (int i = 0; i < offset; i++) { + if (input.charAt(i) == '\n') { + result.append('\n'); + } else { + result.append(' '); + } + } + + return result.toString(); + } + /** * A candidate for continuation of the given user's input. */ diff --git a/src/jdk.management/aix/native/libmanagement_ext/UnixOperatingSystem.c b/src/jdk.management/aix/native/libmanagement_ext/UnixOperatingSystem.c index 228c5eb5c14..ec738c6c1ce 100644 --- a/src/jdk.management/aix/native/libmanagement_ext/UnixOperatingSystem.c +++ b/src/jdk.management/aix/native/libmanagement_ext/UnixOperatingSystem.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2015, 2020 SAP SE. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -28,20 +28,111 @@ /* Implement and update https://bugs.openjdk.org/browse/JDK-8030957 */ #include +#include +#include +#include +#include #include "com_sun_management_internal_OperatingSystemImpl.h" +static struct perfMetrics{ + unsigned long long timebase; + perfstat_process_t stats; + perfstat_cpu_total_t cpu_total; +} counters; + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +int perfInit() { + static int initialized = 0; + if (!initialized) { + + perfstat_id_t id; + counters.stats = (perfstat_process_t){0}; + counters.timebase = 0; + int rc = perfstat_cpu_total(NULL, &counters.cpu_total, sizeof(perfstat_cpu_total_t), 1); + if (rc < 0) { + return -1; + } + rc = perfstat_process(&id, &counters.stats, sizeof(perfstat_process_t), 1); + if (rc < 0) { + return -1; + } + counters.timebase = counters.stats.last_timebase; + initialized = 1; + } + return initialized ? 0 : -1; +} + JNIEXPORT jdouble JNICALL Java_com_sun_management_internal_OperatingSystemImpl_getCpuLoad0 (JNIEnv *env, jobject dummy) { - return -1.0; + double load = -1.0; + pthread_mutex_lock(&lock); + if (perfInit() == 0) { + int ret; + perfstat_cpu_total_t cpu_total; + ret = perfstat_cpu_total(NULL, &cpu_total, sizeof(perfstat_cpu_total_t), 1); + if (ret < 0) { + return -1.0; + } + long long user_diff = cpu_total.user - counters.cpu_total.user; + long long sys_diff = cpu_total.sys - counters.cpu_total.sys; + long long idle_diff = cpu_total.idle - counters.cpu_total.idle; + long long wait_diff = cpu_total.wait - counters.cpu_total.wait; + long long total = user_diff + sys_diff + idle_diff + wait_diff; + if (total < (user_diff + sys_diff)) { + total = user_diff + sys_diff; + } + if (total == 0) { + load = 0.0; + } else { + load = (double)(user_diff + sys_diff) / total; + load = MAX(load, 0.0); + load = MIN(load, 1.0); + } + counters.cpu_total = cpu_total; + } + pthread_mutex_unlock(&lock); + return load; } JNIEXPORT jdouble JNICALL Java_com_sun_management_internal_OperatingSystemImpl_getProcessCpuLoad0 (JNIEnv *env, jobject dummy) { - return -1.0; + perfstat_process_t curr_stats; + perfstat_id_t id; + unsigned long long curr_timebase, timebase_diff; + double user_diff, sys_diff, delta_time; + double cpu_load = -1.0; + pthread_mutex_lock(&lock); + if (perfInit() == 0) { + int ret; + ret = perfstat_process(&id, &curr_stats, sizeof(perfstat_process_t), 1); + if (ret < 0) { + return -1.0; + } + curr_timebase = curr_stats.last_timebase; + timebase_diff = curr_timebase - counters.timebase; + if ((long long)timebase_diff < 0 || XINTFRAC == 0) { + return -1.0; + } + delta_time = HTIC2NANOSEC(timebase_diff) / 1000000000.0; + user_diff = (double)(curr_stats.ucpu_time - counters.stats.ucpu_time); + sys_diff = (double)(curr_stats.scpu_time - counters.stats.scpu_time); + counters.stats = curr_stats; + counters.timebase = curr_timebase; + if (delta_time == 0) { + cpu_load = 0.0; + } else { + cpu_load = (user_diff + sys_diff) / delta_time; + cpu_load = MAX(cpu_load, 0.0); + cpu_load = MIN(cpu_load, 1.0); + } + } + pthread_mutex_unlock(&lock); + return (jdouble)cpu_load; } JNIEXPORT jdouble JNICALL diff --git a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json index 57ef5c8b859..bf52bb3915d 100644 --- a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json +++ b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json @@ -78,6 +78,10 @@ "description": "The blocker object responsible for the thread parking." } }, + "owner": { + "type": "string", + "description": "The thread identifier of the owner when the parkBlocker is an AbstractOwnableSynchronizer." + } "required": [ "object" ] @@ -115,9 +119,9 @@ "items": { "type": [ "string", - null + "null" ], - "description": "The object for which the monitor is owned by the thread, null if eliminated" + "description": "The object for which the monitor is owned by the thread, null if eliminated." } } }, diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputBlock.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputBlock.java index 6670470b5e8..a5b282f9de1 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputBlock.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputBlock.java @@ -135,7 +135,7 @@ void addSuccessor(InputBlock b) { successors.add(b); } - void setArtificial() { + public void setArtificial() { this.artificial = true; } diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputNode.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputNode.java index 48a000bf7b9..df1cbbacc0c 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputNode.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,9 @@ */ public class InputNode extends Properties.Entity { + public static final String LABEL_PROPERTY = "label"; + public static final String COLOR_PROPERTY = "color"; + private int id; public InputNode(InputNode n) { @@ -51,6 +54,17 @@ public int getId() { return id; } + // Return the node properties that are present in the input graph, excluding + // properties computed by IGV itself. This is useful e.g. to produce the + // difference view, where nodes should be compared based only on their + // intrinsic characteristics. + public Properties getPrimaryProperties() { + Properties primaryProperties = new Properties(getProperties()); + primaryProperties.setProperty(LABEL_PROPERTY, null); + primaryProperties.setProperty(COLOR_PROPERTY, null); + return primaryProperties; + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -72,14 +86,14 @@ public String toString() { public void setCustomColor(Color color) { if (color != null) { String hexColor = String.format("#%08X", color.getRGB()); - getProperties().setProperty("color", hexColor); + getProperties().setProperty(COLOR_PROPERTY, hexColor); } else { - getProperties().setProperty("color", null); + getProperties().setProperty(COLOR_PROPERTY, null); } } public Color getCustomColor() { - String hexColor = getProperties().get("color"); + String hexColor = getProperties().get(COLOR_PROPERTY); if (hexColor != null) { try { String hex = hexColor.startsWith("#") ? hexColor.substring(1) : hexColor; diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Parser.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Parser.java index dfe60372eda..06887ba22f4 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Parser.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Parser.java @@ -81,7 +81,7 @@ public class Parser implements GraphParser { public static final String FROM_INDEX_PROPERTY = "fromIndex"; public static final String TO_INDEX_PROPERTY = "toIndex"; public static final String TO_INDEX_ALT_PROPERTY = "index"; - public static final String LABEL_PROPERTY = "label"; + public static final String EDGE_LABEL_PROPERTY = "label"; public static final String METHOD_ELEMENT = "method"; public static final String INLINE_ELEMENT = "inline"; public static final String BYTECODES_ELEMENT = "bytecodes"; @@ -655,7 +655,7 @@ protected InputEdge start() throws SAXException { toIndex = Integer.parseInt(toIndexString); } - label = readAttribute(LABEL_PROPERTY); + label = readAttribute(EDGE_LABEL_PROPERTY); type = readAttribute(TYPE_PROPERTY); from = lookupID(readRequiredAttribute(FROM_PROPERTY)); diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/Scheduler.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/Scheduler.java index 1fe6ac3342a..4ff960f7c3d 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/Scheduler.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/services/Scheduler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, 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,9 +24,7 @@ */ package com.sun.hotspot.igv.data.services; -import com.sun.hotspot.igv.data.InputBlock; import com.sun.hotspot.igv.data.InputGraph; -import java.util.Collection; /** * @@ -34,5 +32,9 @@ */ public interface Scheduler { - public Collection schedule(InputGraph graph); + // Compute a set of scheduled blocks for the given graph, creating new + // blocks if these are not found in the graph. + public void schedule(InputGraph graph); + // Schedule locally the set of blocks in the given graph. + public void scheduleLocally(InputGraph graph); } diff --git a/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java b/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java index c904e8c6083..e3888be31be 100644 --- a/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java +++ b/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java @@ -114,6 +114,9 @@ private static InputGraph createDiff(InputGraph a, InputGraph b, Set p Map blocksMap = new HashMap<>(); for (InputBlock blk : a.getBlocks()) { InputBlock diffblk = graph.addBlock(blk.getName()); + if (blk.isArtificial()) { + diffblk.setArtificial(); + } blocksMap.put(blk, diffblk); } for (InputBlock blk : b.getBlocks()) { @@ -121,6 +124,9 @@ private static InputGraph createDiff(InputGraph a, InputGraph b, Set p if (diffblk == null) { diffblk = graph.addBlock(blk.getName()); } + if (blk.isArtificial()) { + diffblk.setArtificial(); + } blocksMap.put(blk, diffblk); } @@ -249,6 +255,9 @@ private static InputGraph createDiff(InputGraph a, InputGraph b, Set p } } + Scheduler s = Lookup.getDefault().lookup(Scheduler.class); + s.scheduleLocally(graph); + return graph; } @@ -356,7 +365,7 @@ private static void markAsSame(InputEdge e) { private static void markAsChanged(InputNode n, InputNode firstNode, InputNode otherNode) { boolean difference = false; - for (Property p : otherNode.getProperties()) { + for (Property p : otherNode.getPrimaryProperties()) { String s = firstNode.getProperties().get(p.getName()); if (!p.getValue().equals(s)) { difference = true; @@ -364,7 +373,7 @@ private static void markAsChanged(InputNode n, InputNode firstNode, InputNode ot } } - for (Property p : firstNode.getProperties()) { + for (Property p : firstNode.getPrimaryProperties()) { String s = otherNode.getProperties().get(p.getName()); if (s == null && p.getValue().length() > 0) { difference = true; diff --git a/src/utils/IdealGraphVisualizer/Filter/pom.xml b/src/utils/IdealGraphVisualizer/Filter/pom.xml index 176f7a80180..c22ce274493 100644 --- a/src/utils/IdealGraphVisualizer/Filter/pom.xml +++ b/src/utils/IdealGraphVisualizer/Filter/pom.xml @@ -1,6 +1,6 @@ <-----------mtClassShared-------> - tree.reserve_mapping(0, 600, rd); + tree.reserve_mapping(0, 600, rd, not_used); // The committed areas - tree.commit_mapping(100, 125, rd); - tree.commit_mapping(550, 10, rd); - tree.commit_mapping(565, 10, rd); + tree.commit_mapping(100, 125, rd, not_used); + tree.commit_mapping(550, 10, rd, not_used); + tree.commit_mapping(565, 10, rd, not_used); // OK, set tag tree.set_tag(0, 500, mtGC); tree.set_tag(500, 100, mtClassShared); @@ -564,10 +579,11 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {0, 200, mtGC, si, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData gc(si, mtGC); Tree::RegionData compiler(si, mtCompiler); - tree.reserve_mapping(0, 100, gc); - tree.reserve_mapping(100, 100, compiler); + tree.reserve_mapping(0, 100, gc, not_used); + tree.reserve_mapping(100, 100, compiler, not_used); tree.set_tag(0, 200, mtGC); expect_equivalent_form(expected, tree, __LINE__); } @@ -580,10 +596,11 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {100, 200, mtGC, si2, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData gc(si1, mtGC); Tree::RegionData compiler(si2, mtCompiler); - tree.reserve_mapping(0, 100, gc); - tree.reserve_mapping(100, 100, compiler); + tree.reserve_mapping(0, 100, gc, not_used); + tree.reserve_mapping(100, 100, compiler, not_used); tree.set_tag(0, 200, mtGC); expect_equivalent_form(expected, tree, __LINE__); } @@ -595,8 +612,9 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {150, 200, mtCompiler, si, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData compiler(si, mtCompiler); - tree.reserve_mapping(0, 200, compiler); + tree.reserve_mapping(0, 200, compiler, not_used); tree.set_tag(100, 50, mtGC); expect_equivalent_form(expected, tree, __LINE__); } @@ -608,10 +626,11 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {125, 200, mtCompiler, si, State::Reserved}, }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData gc(si, mtGC); Tree::RegionData compiler(si, mtCompiler); - tree.reserve_mapping(0, 100, gc); - tree.reserve_mapping(100, 100, compiler); + tree.reserve_mapping(0, 100, gc, not_used); + tree.reserve_mapping(100, 100, compiler, not_used); tree.set_tag(75, 50, mtClass); expect_equivalent_form(expected, tree, __LINE__); } @@ -624,9 +643,10 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {80, 100, mtClassShared, si, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData class_shared(si, mtClassShared); - tree.reserve_mapping(0, 50, class_shared); - tree.reserve_mapping(75, 25, class_shared); + tree.reserve_mapping(0, 50, class_shared, not_used); + tree.reserve_mapping(75, 25, class_shared, not_used); tree.set_tag(0, 80, mtGC); expect_equivalent_form(expected, tree, __LINE__); } @@ -636,8 +656,9 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {10, 20, mtCompiler, si, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData class_shared(si, mtClassShared); - tree.reserve_mapping(10, 10, class_shared); + tree.reserve_mapping(10, 10, class_shared, not_used); tree.set_tag(0, 100, mtCompiler); expect_equivalent_form(expected, tree, __LINE__); } @@ -651,10 +672,11 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {99, 100, mtGC, si, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData class_shared(si, mtClassShared); - tree.reserve_mapping(0, 100, class_shared); - tree.release_mapping(1, 49); - tree.release_mapping(75, 24); + tree.reserve_mapping(0, 100, class_shared, not_used); + tree.release_mapping(1, 49, not_used); + tree.release_mapping(75, 24, not_used); tree.set_tag(0, 100, mtGC); expect_equivalent_form(expected, tree, __LINE__); } @@ -666,7 +688,8 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { Tree::RegionData rd_Test_cs0(NCS::StackIndex(), mtTest); Tree::RegionData rd_NMT_cs0(NCS::StackIndex(), mtNMT); Tree tree; - VMATree::SummaryDiff all_diff = tree.reserve_mapping(0, 100, rd_Test_cs0); + VMATree::SummaryDiff all_diff; + tree.reserve_mapping(0, 100, rd_Test_cs0, all_diff); // 1 2 3 4 5 6 7 8 9 10 11 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.......... @@ -675,7 +698,7 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { // . - free VMATree::SingleDiff diff = all_diff.tag[NMTUtil::tag_to_index(mtTest)]; EXPECT_EQ(100, diff.reserve); - all_diff = tree.reserve_mapping(50, 25, rd_NMT_cs0); + tree.reserve_mapping(50, 25, rd_NMT_cs0, all_diff); // 1 2 3 4 5 6 7 8 9 10 11 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCC.......... @@ -692,7 +715,8 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { { // Fully release reserved mapping Tree::RegionData rd_Test_cs0(NCS::StackIndex(), mtTest); Tree tree; - VMATree::SummaryDiff all_diff = tree.reserve_mapping(0, 100, rd_Test_cs0); + VMATree::SummaryDiff all_diff; + tree.reserve_mapping(0, 100, rd_Test_cs0, all_diff); // 1 2 3 4 5 6 7 8 9 10 11 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.......... @@ -701,7 +725,7 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { // . - free VMATree::SingleDiff diff = all_diff.tag[NMTUtil::tag_to_index(mtTest)]; EXPECT_EQ(100, diff.reserve); - all_diff = tree.release_mapping(0, 100); + tree.release_mapping(0, 100, all_diff); // 1 2 3 4 5 6 7 8 9 10 11 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 // .............................................................................................................. @@ -712,7 +736,8 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { { // Convert some of a released mapping to a committed one Tree::RegionData rd_Test_cs0(NCS::StackIndex(), mtTest); Tree tree; - VMATree::SummaryDiff all_diff = tree.reserve_mapping(0, 100, rd_Test_cs0); + VMATree::SummaryDiff all_diff; + tree.reserve_mapping(0, 100, rd_Test_cs0, all_diff); // 1 2 3 4 5 6 7 8 9 10 11 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.......... @@ -721,7 +746,7 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { // . - free VMATree::SingleDiff diff = all_diff.tag[NMTUtil::tag_to_index(mtTest)]; EXPECT_EQ(diff.reserve, 100); - all_diff = tree.commit_mapping(0, 100, rd_Test_cs0); + tree.commit_mapping(0, 100, rd_Test_cs0, all_diff); // 1 2 3 4 5 6 7 8 9 10 11 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 // aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......... @@ -735,7 +760,8 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { { // Adjacent reserved mappings with same type Tree::RegionData rd_Test_cs0(NCS::StackIndex(), mtTest); Tree tree; - VMATree::SummaryDiff all_diff = tree.reserve_mapping(0, 10, rd_Test_cs0); + VMATree::SummaryDiff all_diff; + tree.reserve_mapping(0, 10, rd_Test_cs0, all_diff); // 1 2 // 01234567890123456789 // AAAAAAAAAA.......... @@ -744,7 +770,7 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { // . - free VMATree::SingleDiff diff = all_diff.tag[NMTUtil::tag_to_index(mtTest)]; EXPECT_EQ(diff.reserve, 10); - all_diff = tree.reserve_mapping(10, 10, rd_Test_cs0); + tree.reserve_mapping(10, 10, rd_Test_cs0, all_diff); // 1 2 3 // 012345678901234567890123456789 // AAAAAAAAAAAAAAAAAAAA.......... @@ -758,7 +784,8 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { Tree::RegionData rd_Test_cs0(NCS::StackIndex(), mtTest); Tree::RegionData rd_NMT_cs0(NCS::StackIndex(), mtNMT); Tree tree; - VMATree::SummaryDiff all_diff = tree.reserve_mapping(0, 10, rd_Test_cs0); + VMATree::SummaryDiff all_diff; + tree.reserve_mapping(0, 10, rd_Test_cs0, all_diff); // 1 2 // 01234567890123456789 // AAAAAAAAAA.......... @@ -767,7 +794,7 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { // . - free VMATree::SingleDiff diff = all_diff.tag[NMTUtil::tag_to_index(mtTest)]; EXPECT_EQ(diff.reserve, 10); - all_diff = tree.reserve_mapping(10, 10, rd_NMT_cs0); + tree.reserve_mapping(10, 10, rd_NMT_cs0, all_diff); // 1 2 3 // 012345678901234567890123456789 // AAAAAAAAAABBBBBBBBBB.......... @@ -784,22 +811,23 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { { // A commit with two previous commits inside of it should only register // the new memory in the commit diff. Tree tree; + VMATree::SummaryDiff diff; Tree::RegionData rd_Test_cs0(NCS::StackIndex(), mtTest); - tree.commit_mapping(16, 16, rd_Test_cs0); + tree.commit_mapping(16, 16, rd_Test_cs0, diff); // 1 2 3 4 // 0123456789012345678901234567890123456789 // ................aaaaaaaaaaaaaaaa.......... // Legend: // a - Test (committed) // . - free - tree.commit_mapping(32, 32, rd_Test_cs0); + tree.commit_mapping(32, 32, rd_Test_cs0, diff); // 1 2 3 4 5 6 7 // 0123456789012345678901234567890123456789012345678901234567890123456789 // ................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......... // Legend: // a - Test (committed) // . - free - VMATree::SummaryDiff diff = tree.commit_mapping(0, 64, rd_Test_cs0); + tree.commit_mapping(0, 64, rd_Test_cs0, diff); // 1 2 3 4 5 6 7 // 0123456789012345678901234567890123456789012345678901234567890123456789 // aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......... @@ -814,11 +842,12 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { TEST_VM_F(NMTVMATreeTest, SummaryAccountingReserveAsUncommit) { Tree tree; Tree::RegionData rd(NCS::StackIndex(), mtTest); - VMATree::SummaryDiff diff1 = tree.reserve_mapping(1200, 100, rd); - VMATree::SummaryDiff diff2 = tree.commit_mapping(1210, 50, rd); + VMATree::SummaryDiff diff1, diff2, diff3; + tree.reserve_mapping(1200, 100, rd, diff1); + tree.commit_mapping(1210, 50, rd, diff2); EXPECT_EQ(100, diff1.tag[NMTUtil::tag_to_index(mtTest)].reserve); EXPECT_EQ(50, diff2.tag[NMTUtil::tag_to_index(mtTest)].commit); - VMATree::SummaryDiff diff3 = tree.reserve_mapping(1220, 20, rd); + tree.reserve_mapping(1220, 20, rd, diff3); EXPECT_EQ(-20, diff3.tag[NMTUtil::tag_to_index(mtTest)].commit); EXPECT_EQ(0, diff3.tag[NMTUtil::tag_to_index(mtTest)].reserve); } @@ -951,13 +980,13 @@ TEST_VM_F(NMTVMATreeTest, TestConsistencyWithSimpleTracker) { VMATree::SummaryDiff simple_diff; if (kind == SimpleVMATracker::Reserved) { simple_diff = tr->reserve(start, size, stack, mem_tag); - tree_diff = tree.reserve_mapping(start, size, data); + tree.reserve_mapping(start, size, data, tree_diff); } else if (kind == SimpleVMATracker::Committed) { simple_diff = tr->commit(start, size, stack, mem_tag); - tree_diff = tree.commit_mapping(start, size, data); + tree.commit_mapping(start, size, data, tree_diff); } else { simple_diff = tr->release(start, size); - tree_diff = tree.release_mapping(start, size); + tree.release_mapping(start, size, tree_diff); } for (int j = 0; j < mt_number_of_tags; j++) { @@ -1024,33 +1053,34 @@ TEST_VM_F(NMTVMATreeTest, TestConsistencyWithSimpleTracker) { TEST_VM_F(NMTVMATreeTest, SummaryAccountingWhenUseTagInplace) { Tree tree; + VMATree::SummaryDiff diff; VMATree::RegionData rd_Test_cs0(si[0], mtTest); VMATree::RegionData rd_None_cs1(si[1], mtNone); -// 1 2 3 4 5 -// 012345678901234567890123456789012345678901234567890 -// .................................................. - tree.reserve_mapping(0, 50, rd_Test_cs0); -// 1 2 3 4 5 -// 012345678901234567890123456789012345678901234567890 -// rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr -VMATree::SummaryDiff diff = tree.commit_mapping(0, 25, rd_None_cs1, true); -// 1 2 3 4 5 -// 012345678901234567890123456789012345678901234567890 -// CCCCCCCCCCCCCCCCCCCCCCCCCrrrrrrrrrrrrrrrrrrrrrrrrr + // 1 2 3 4 5 + // 012345678901234567890123456789012345678901234567890 + // .................................................. + tree.reserve_mapping(0, 50, rd_Test_cs0, diff); + // 1 2 3 4 5 + // 012345678901234567890123456789012345678901234567890 + // rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr + tree.commit_mapping(0, 25, rd_None_cs1, diff, true); + // 1 2 3 4 5 + // 012345678901234567890123456789012345678901234567890 + // CCCCCCCCCCCCCCCCCCCCCCCCCrrrrrrrrrrrrrrrrrrrrrrrrr EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); EXPECT_EQ(25, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); - diff = tree.commit_mapping(30, 5, rd_None_cs1, true); -// 1 2 3 4 5 -// 012345678901234567890123456789012345678901234567890 -// CCCCCCCCCCCCCCCCCCCCCCCCCrrrrrCCCCCrrrrrrrrrrrrrrr + tree.commit_mapping(30, 5, rd_None_cs1, diff, true); + // 1 2 3 4 5 + // 012345678901234567890123456789012345678901234567890 + // CCCCCCCCCCCCCCCCCCCCCCCCCrrrrrCCCCCrrrrrrrrrrrrrrr EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); EXPECT_EQ(5, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); - diff = tree.uncommit_mapping(0, 25, rd_None_cs1); -// 1 2 3 4 5 -// 012345678901234567890123456789012345678901234567890 -// rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrCCCCCrrrrrrrrrrrrrrr + tree.uncommit_mapping(0, 25, rd_None_cs1, diff); + // 1 2 3 4 5 + // 012345678901234567890123456789012345678901234567890 + // rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrCCCCCrrrrrrrrrrrrrrr EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); EXPECT_EQ(-25, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); } @@ -1079,7 +1109,8 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { {// Check committing into a reserved region inherits the call stacks Tree tree; - tree.reserve_mapping(0, 50, rd_Test_cs1); // reserve in an empty tree + VMATree::SummaryDiff diff; + tree.reserve_mapping(0, 50, rd_Test_cs1, diff); // reserve in an empty tree // Pre: empty tree. // Post: // 1 2 3 4 5 @@ -1091,7 +1122,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { {-1 , si_1 , -1 }, {-1 , -1 , -1 }}; check_tree(tree, et1, __LINE__); - tree.commit_mapping(25, 10, rd_None_cs2, true); // commit at the middle of the region + tree.commit_mapping(25, 10, rd_None_cs2, diff, true); // commit at the middle of the region // Post: // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 @@ -1103,7 +1134,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { {-1 , -1 , si_2 , -1 , -1 }}; check_tree(tree, et2, __LINE__); - tree.commit_mapping(0, 20, rd_None_cs2, true); // commit at the beginning of the region + tree.commit_mapping(0, 20, rd_None_cs2, diff, true); // commit at the beginning of the region // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // CCCCCCCCCCCCCCCCCCCCrrrrrCCCCCCCCCCrrrrrrrrrrrrrrr. @@ -1114,7 +1145,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { {-1 , si_2 , -1 , si_2 , -1 , -1 }}; check_tree(tree, et3, __LINE__); - tree.commit_mapping(40, 10, rd_None_cs2, true); // commit at the end of the region + tree.commit_mapping(40, 10, rd_None_cs2, diff, true); // commit at the end of the region // Post: // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 @@ -1128,7 +1159,8 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { } {// committing overlapped regions does not destroy the old call-stacks Tree tree; - tree.reserve_mapping(0, 50, rd_Test_cs1); // reserving in an empty tree + VMATree::SummaryDiff diff; + tree.reserve_mapping(0, 50, rd_Test_cs1, diff); // reserving in an empty tree // Pre: empty tree. // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 @@ -1140,7 +1172,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { {-1 , -1 , -1 }}; check_tree(tree, et1, __LINE__); - tree.commit_mapping(10, 10, rd_None_cs2, true); + tree.commit_mapping(10, 10, rd_None_cs2, diff, true); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrrCCCCCCCCCCrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr @@ -1154,7 +1186,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { SIndex si_3 = si[2]; VMATree::RegionData rd_Test_cs3(si_3, mtTest); // commit with overlap at the region's start - tree.commit_mapping(5, 10, rd_Test_cs3); + tree.commit_mapping(5, 10, rd_Test_cs3, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrCCCCCCCCCCCCCCCrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr @@ -1168,7 +1200,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { SIndex si_4 = si[3]; VMATree::RegionData call_stack_4(si_4, mtTest); // commit with overlap at the region's end - tree.commit_mapping(15, 10, call_stack_4); + tree.commit_mapping(15, 10, call_stack_4, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrCCCCCCCCCCCCCCCCCCCCrrrrrrrrrrrrrrrrrrrrrrrrr @@ -1181,13 +1213,14 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { } {// uncommit should not store any call-stack Tree tree; - tree.reserve_mapping(0, 50, rd_Test_cs1); + VMATree::SummaryDiff diff; + tree.reserve_mapping(0, 50, rd_Test_cs1, diff); - tree.commit_mapping(10, 10, rd_None_cs2, true); + tree.commit_mapping(10, 10, rd_None_cs2, diff, true); - tree.commit_mapping(0, 5, rd_None_cs2, true); + tree.commit_mapping(0, 5, rd_None_cs2, diff, true); - tree.uncommit_mapping(0, 3, rd_None_cs2); + tree.uncommit_mapping(0, 3, rd_None_cs2, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrCCrrrrrCCCCCCCCCCrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr @@ -1198,7 +1231,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { {-1 , -1 , si_2 , -1 , si_2 , -1 , -1 }}; check_tree(tree, et1, __LINE__); - tree.uncommit_mapping(5, 10, rd_None_cs2); + tree.uncommit_mapping(5, 10, rd_None_cs2, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrCCrrrrrrrrrrCCCCCrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr. @@ -1214,8 +1247,9 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { VMATree::RegionData call_stack_4(si_4, mtTest); Tree tree; - tree.reserve_mapping(0, 50, rd_Test_cs1); - tree.reserve_mapping(10, 10, call_stack_4); + VMATree::SummaryDiff diff; + tree.reserve_mapping(0, 50, rd_Test_cs1, diff); + tree.reserve_mapping(10, 10, call_stack_4, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr @@ -1228,7 +1262,8 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { } {// commit without reserve Tree tree; - tree.commit_mapping(0, 50, rd_Test_cs1); + VMATree::SummaryDiff diff; + tree.commit_mapping(0, 50, rd_Test_cs1, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC @@ -1241,8 +1276,9 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { } {// reserve after commit Tree tree; - tree.commit_mapping(0, 50, rd_None_cs2); - tree.reserve_mapping(0, 50, rd_Test_cs1); + VMATree::SummaryDiff diff; + tree.commit_mapping(0, 50, rd_None_cs2, diff); + tree.reserve_mapping(0, 50, rd_Test_cs1, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr @@ -1287,7 +1323,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows0To3) { {-1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCCCCCCC.......................... @@ -1314,7 +1351,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows0To3) { {-1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 15, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 15, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCC............................... @@ -1359,7 +1397,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows4to7) { {-1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(20, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(20, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrr..........CCCCCCCCCCCCCCCCCCCC........... @@ -1386,7 +1425,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows4to7) { {-1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(10, 10, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(10, 10, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....rrrrrCCCCCCCCCC............................... @@ -1413,7 +1453,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows4to7) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(7, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(7, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrr..CCCCCCCCCCCCCCCCCCCC........................ @@ -1440,7 +1481,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows4to7) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(7, 13, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(7, 13, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrr..CCCCCCCCCCCCC............................... @@ -1492,7 +1534,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows8to11) { {-1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(10, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(10, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrrCCCCCCCCCCCCCCCCCCCC..................... @@ -1519,7 +1562,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows8to11) { {-1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(0, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(0, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // CCCCCCCCCCCCCCCCCCCC............................... @@ -1546,7 +1590,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows8to11) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCCCCCCC.......................... @@ -1573,7 +1618,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows8to11) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 15, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 15, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCC............................... @@ -1619,7 +1665,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows12to15) { {-1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCCCCCCC.....rrrrrrrrrr........... @@ -1646,7 +1693,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows12to15) { {-1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCCCCCCCrrrrr..................... @@ -1673,7 +1721,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows12to15) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCCCCCCC.....rrrrrrrrrr........... @@ -1700,7 +1749,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows12to15) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 15, rd_Test_cs2, false); + VMATree::SummaryDiff diff ; + tree.commit_mapping(5, 15, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCC..........rrrrrrrrrr........... @@ -1745,7 +1795,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows16to19) { {-1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(15, 10, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(15, 10, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrr.....CCCCCCCCCC.....rrrrrrrrrr........... @@ -1772,7 +1823,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows16to19) { {-1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(15, 10, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(15, 10, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrr.....CCCCCCCCCCrrrrr..................... @@ -1799,7 +1851,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows16to19) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(7, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(7, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrr..CCCCCCCCCCCCCCCCCCCC...rrrrrrrrrr........... @@ -1826,7 +1879,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows16to19) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(7, 13, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(7, 13, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrr..CCCCCCCCCCCCC..........rrrrrrrrrr........... @@ -1872,7 +1926,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows20to23) { {-1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(10, 15, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(10, 15, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrrCCCCCCCCCCCCCCC.....rrrrrrrrrr........... @@ -1899,7 +1954,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows20to23) { {-1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(10, 15, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(10, 15, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrrCCCCCCCCCCCCCCCrrrrr..................... @@ -1926,7 +1982,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows20to23) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrCCCCCCCCCCCCCCCCCCCC.....rrrrrrrrrr........... @@ -1953,7 +2010,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows20to23) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 15, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 15, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrCCCCCCCCCCCCCCC..........rrrrrrrrrr........... diff --git a/test/hotspot/gtest/runtime/test_os_linux.cpp b/test/hotspot/gtest/runtime/test_os_linux.cpp index 21133788a36..c8467784b0a 100644 --- a/test/hotspot/gtest/runtime/test_os_linux.cpp +++ b/test/hotspot/gtest/runtime/test_os_linux.cpp @@ -35,6 +35,7 @@ #include "unittest.hpp" #include +#include static bool using_explicit_hugepages() { return UseLargePages && !UseTransparentHugePages; } @@ -468,4 +469,27 @@ TEST_VM(os_linux, glibc_mallinfo_wrapper) { #endif // ADDRESS_SANITIZER #endif // __GLIBC__ +static void test_set_thread_name(const char* name, const char* expected) { + os::set_native_thread_name(name); + char buf[16]; + int rc = prctl(PR_GET_NAME, buf); + ASSERT_EQ(0, rc); + ASSERT_STREQ(buf, expected); +} + +TEST_VM(os_linux, set_thread_name) { + char buf[16]; + // retrieve current name + int rc = prctl(PR_GET_NAME, buf); + ASSERT_EQ(0, rc); + + test_set_thread_name("shortname", "shortname"); + test_set_thread_name("012345678901234", "012345678901234"); + test_set_thread_name("0123456789012345", "0123456..012345"); + test_set_thread_name("MyAllocationWorkerThread22", "MyAlloc..read22"); + + // restore current name + test_set_thread_name(buf, buf); +} + #endif // LINUX diff --git a/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp b/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp index 556b9876acc..4242302997a 100644 --- a/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp +++ b/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp @@ -94,6 +94,7 @@ class VirtualMemoryTrackerTest { RegionsTree* rtree = vmt.tree(); size_t size = 0x01000000; const address addr = (address)0x0000A000; + VMATree::SummaryDiff diff; vmt.add_reserved_region(addr, size, CALLER_PC, mtTest); @@ -115,45 +116,45 @@ class VirtualMemoryTrackerTest { // Commit adjacent regions with same stack { // Commit one region - rtree->commit_region(addr + cs, cs, stack); + rtree->commit_region(addr + cs, cs, stack, diff); R r[] = { {addr + cs, cs} }; check(vmt, rmr, r); } { // Commit adjacent - lower address - rtree->commit_region(addr, cs, stack); + rtree->commit_region(addr, cs, stack, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } { // Commit adjacent - higher address - rtree->commit_region(addr + 2 * cs, cs, stack); + rtree->commit_region(addr + 2 * cs, cs, stack, diff); R r[] = { {addr, 3 * cs} }; check(vmt,rmr, r); } // Cleanup - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 0u); // Commit adjacent regions with different stacks { // Commit one region - rtree->commit_region(addr + cs, cs, stack); + rtree->commit_region(addr + cs, cs, stack, diff); R r[] = { {addr + cs, cs} }; check(vmt, rmr, r); } { // Commit adjacent - lower address - rtree->commit_region(addr, cs, stack2); + rtree->commit_region(addr, cs, stack2, diff); R r[] = { {addr, cs}, {addr + cs, cs} }; check(vmt, rmr, r); } { // Commit adjacent - higher address - rtree->commit_region(addr + 2 * cs, cs, stack2); + rtree->commit_region(addr + 2 * cs, cs, stack2, diff); R r[] = { {addr, cs}, {addr + cs, cs}, {addr + 2 * cs, cs} }; @@ -161,12 +162,13 @@ class VirtualMemoryTrackerTest { } // Cleanup - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 0u); } static void test_add_committed_region_adjacent_overlapping() { VirtualMemoryTracker vmt(true); + VMATree::SummaryDiff diff; RegionsTree* rtree = vmt.tree(); size_t size = 0x01000000; const address addr = (address)0x0000A000; @@ -190,46 +192,46 @@ class VirtualMemoryTrackerTest { // Commit adjacent and overlapping regions with same stack { // Commit two non-adjacent regions - rtree->commit_region(addr, 2 * cs, stack); - rtree->commit_region(addr + 3 * cs, 2 * cs, stack); + rtree->commit_region(addr, 2 * cs, stack, diff); + rtree->commit_region(addr + 3 * cs, 2 * cs, stack, diff); R r[] = { {addr, 2 * cs}, {addr + 3 * cs, 2 * cs} }; check(vmt, rmr, r); } { // Commit adjacent and overlapping - rtree->commit_region(addr + 2 * cs, 2 * cs, stack); + rtree->commit_region(addr + 2 * cs, 2 * cs, stack, diff); R r[] = { {addr, 5 * cs} }; check(vmt, rmr, r); } // revert to two non-adjacent regions - rtree->uncommit_region(addr + 2 * cs, cs); + rtree->uncommit_region(addr + 2 * cs, cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 4 * cs); { // Commit overlapping and adjacent - rtree->commit_region(addr + cs, 2 * cs, stack); + rtree->commit_region(addr + cs, 2 * cs, stack, diff); R r[] = { {addr, 5 * cs} }; check(vmt, rmr, r); } // Cleanup - rtree->uncommit_region(addr, 5 * cs); + rtree->uncommit_region(addr, 5 * cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 0u); // Commit adjacent and overlapping regions with different stacks { // Commit two non-adjacent regions - rtree->commit_region(addr, 2 * cs, stack); - rtree->commit_region(addr + 3 * cs, 2 * cs, stack); + rtree->commit_region(addr, 2 * cs, stack, diff); + rtree->commit_region(addr + 3 * cs, 2 * cs, stack, diff); R r[] = { {addr, 2 * cs}, {addr + 3 * cs, 2 * cs} }; check(vmt, rmr, r); } { // Commit adjacent and overlapping - rtree->commit_region(addr + 2 * cs, 2 * cs, stack2); + rtree->commit_region(addr + 2 * cs, 2 * cs, stack2, diff); R r[] = { {addr, 2 * cs}, {addr + 2 * cs, 2 * cs}, {addr + 4 * cs, cs} }; @@ -237,12 +239,12 @@ class VirtualMemoryTrackerTest { } // revert to two non-adjacent regions - rtree->commit_region(addr, 5 * cs, stack); - rtree->uncommit_region(addr + 2 * cs, cs); + rtree->commit_region(addr, 5 * cs, stack, diff); + rtree->uncommit_region(addr + 2 * cs, cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 4 * cs); { // Commit overlapping and adjacent - rtree->commit_region(addr + cs, 2 * cs, stack2); + rtree->commit_region(addr + cs, 2 * cs, stack2, diff); R r[] = { {addr, cs}, {addr + cs, 2 * cs}, {addr + 3 * cs, 2 * cs} }; @@ -254,6 +256,7 @@ class VirtualMemoryTrackerTest { static void test_add_committed_region_overlapping() { VirtualMemoryTracker vmt(true); + VMATree::SummaryDiff diff; RegionsTree* rtree = vmt.tree(); size_t size = 0x01000000; const address addr = (address)0x0000A000; @@ -279,77 +282,77 @@ class VirtualMemoryTrackerTest { // With same stack { // Commit one region - rtree->commit_region(addr, cs, stack); + rtree->commit_region(addr, cs, stack, diff); R r[] = { {addr, cs} }; check(vmt, rmr, r); } { // Commit the same region - rtree->commit_region(addr, cs, stack); + rtree->commit_region(addr, cs, stack, diff); R r[] = { {addr, cs} }; check(vmt, rmr, r); } { // Commit a succeeding region - rtree->commit_region(addr + cs, cs, stack); + rtree->commit_region(addr + cs, cs, stack, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } { // Commit over two regions - rtree->commit_region(addr, 2 * cs, stack); + rtree->commit_region(addr, 2 * cs, stack, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } {// Commit first part of a region - rtree->commit_region(addr, cs, stack); + rtree->commit_region(addr, cs, stack, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } { // Commit second part of a region - rtree->commit_region(addr + cs, cs, stack); + rtree->commit_region(addr + cs, cs, stack, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } { // Commit a third part - rtree->commit_region(addr + 2 * cs, cs, stack); + rtree->commit_region(addr + 2 * cs, cs, stack, diff); R r[] = { {addr, 3 * cs} }; check(vmt, rmr, r); } { // Commit in the middle of a region - rtree->commit_region(addr + 1 * cs, cs, stack); + rtree->commit_region(addr + 1 * cs, cs, stack, diff); R r[] = { {addr, 3 * cs} }; check(vmt, rmr, r); } // Cleanup - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 0u); // With preceding region - rtree->commit_region(addr, cs, stack); - rtree->commit_region(addr + 2 * cs, 3 * cs, stack); + rtree->commit_region(addr, cs, stack, diff); + rtree->commit_region(addr + 2 * cs, 3 * cs, stack, diff); - rtree->commit_region(addr + 2 * cs, cs, stack); + rtree->commit_region(addr + 2 * cs, cs, stack, diff); { R r[] = { {addr, cs}, {addr + 2 * cs, 3 * cs} }; check(vmt, rmr, r); } - rtree->commit_region(addr + 3 * cs, cs, stack); + rtree->commit_region(addr + 3 * cs, cs, stack, diff); { R r[] = { {addr, cs}, {addr + 2 * cs, 3 * cs} }; check(vmt, rmr, r); } - rtree->commit_region(addr + 4 * cs, cs, stack); + rtree->commit_region(addr + 4 * cs, cs, stack, diff); { R r[] = { {addr, cs}, {addr + 2 * cs, 3 * cs} }; @@ -357,57 +360,57 @@ class VirtualMemoryTrackerTest { } // Cleanup - rtree->uncommit_region(addr, 5 * cs); + rtree->uncommit_region(addr, 5 * cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 0u); // With different stacks { // Commit one region - rtree->commit_region(addr, cs, stack); + rtree->commit_region(addr, cs, stack, diff); R r[] = { {addr, cs} }; check(vmt, rmr, r); } { // Commit the same region - rtree->commit_region(addr, cs, stack2); + rtree->commit_region(addr, cs, stack2, diff); R r[] = { {addr, cs} }; check(vmt, rmr, r); } { // Commit a succeeding region - rtree->commit_region(addr + cs, cs, stack); + rtree->commit_region(addr + cs, cs, stack, diff); R r[] = { {addr, cs}, {addr + cs, cs} }; check(vmt, rmr, r); } { // Commit over two regions - rtree->commit_region(addr, 2 * cs, stack); + rtree->commit_region(addr, 2 * cs, stack, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } {// Commit first part of a region - rtree->commit_region(addr, cs, stack2); + rtree->commit_region(addr, cs, stack2, diff); R r[] = { {addr, cs}, {addr + cs, cs} }; check(vmt, rmr, r); } { // Commit second part of a region - rtree->commit_region(addr + cs, cs, stack2); + rtree->commit_region(addr + cs, cs, stack2, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } { // Commit a third part - rtree->commit_region(addr + 2 * cs, cs, stack2); + rtree->commit_region(addr + 2 * cs, cs, stack2, diff); R r[] = { {addr, 3 * cs} }; check(vmt, rmr, r); } { // Commit in the middle of a region - rtree->commit_region(addr + 1 * cs, cs, stack); + rtree->commit_region(addr + 1 * cs, cs, stack, diff); R r[] = { {addr, cs}, {addr + cs, cs}, {addr + 2 * cs, cs} }; @@ -430,6 +433,7 @@ class VirtualMemoryTrackerTest { static void test_remove_uncommitted_region() { VirtualMemoryTracker vmt(true); + VMATree::SummaryDiff diff; RegionsTree* rtree = vmt.tree(); size_t size = 0x01000000; const address addr = (address)0x0000A000; @@ -451,105 +455,105 @@ class VirtualMemoryTrackerTest { const size_t cs = 0x1000; { // Commit regions - rtree->commit_region(addr, 3 * cs, stack); + rtree->commit_region(addr, 3 * cs, stack, diff); R r[] = { {addr, 3 * cs} }; check(vmt, rmr, r); // Remove only existing - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); check_empty(vmt, rmr); } { - rtree->commit_region(addr + 0 * cs, cs, stack); - rtree->commit_region(addr + 2 * cs, cs, stack); - rtree->commit_region(addr + 4 * cs, cs, stack); + rtree->commit_region(addr + 0 * cs, cs, stack, diff); + rtree->commit_region(addr + 2 * cs, cs, stack, diff); + rtree->commit_region(addr + 4 * cs, cs, stack, diff); { // Remove first - rtree->uncommit_region(addr, cs); + rtree->uncommit_region(addr, cs, diff); R r[] = { {addr + 2 * cs, cs}, {addr + 4 * cs, cs} }; check(vmt, rmr, r); } // add back - rtree->commit_region(addr, cs, stack); + rtree->commit_region(addr, cs, stack, diff); { // Remove middle - rtree->uncommit_region(addr + 2 * cs, cs); + rtree->uncommit_region(addr + 2 * cs, cs, diff); R r[] = { {addr + 0 * cs, cs}, {addr + 4 * cs, cs} }; check(vmt, rmr, r); } // add back - rtree->commit_region(addr + 2 * cs, cs, stack); + rtree->commit_region(addr + 2 * cs, cs, stack, diff); { // Remove end - rtree->uncommit_region(addr + 4 * cs, cs); + rtree->uncommit_region(addr + 4 * cs, cs, diff); R r[] = { {addr + 0 * cs, cs}, {addr + 2 * cs, cs} }; check(vmt, rmr, r); } - rtree->uncommit_region(addr, 5 * cs); + rtree->uncommit_region(addr, 5 * cs, diff); check_empty(vmt, rmr); } { // Remove larger region - rtree->commit_region(addr + 1 * cs, cs, stack); - rtree->uncommit_region(addr, 3 * cs); + rtree->commit_region(addr + 1 * cs, cs, stack, diff); + rtree->uncommit_region(addr, 3 * cs, diff); check_empty(vmt, rmr); } { // Remove smaller region - in the middle - rtree->commit_region(addr, 3 * cs, stack); - rtree->uncommit_region(addr + 1 * cs, cs); + rtree->commit_region(addr, 3 * cs, stack, diff); + rtree->uncommit_region(addr + 1 * cs, cs, diff); R r[] = { { addr + 0 * cs, cs}, { addr + 2 * cs, cs} }; check(vmt, rmr, r); - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); check_empty(vmt, rmr); } { // Remove smaller region - at the beginning - rtree->commit_region(addr, 3 * cs, stack); - rtree->uncommit_region(addr + 0 * cs, cs); + rtree->commit_region(addr, 3 * cs, stack, diff); + rtree->uncommit_region(addr + 0 * cs, cs, diff); R r[] = { { addr + 1 * cs, 2 * cs} }; check(vmt, rmr, r); - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); check_empty(vmt, rmr); } { // Remove smaller region - at the end - rtree->commit_region(addr, 3 * cs, stack); - rtree->uncommit_region(addr + 2 * cs, cs); + rtree->commit_region(addr, 3 * cs, stack, diff); + rtree->uncommit_region(addr + 2 * cs, cs, diff); R r[] = { { addr, 2 * cs} }; check(vmt, rmr, r); - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); check_empty(vmt, rmr); } { // Remove smaller, overlapping region - at the beginning - rtree->commit_region(addr + 1 * cs, 4 * cs, stack); - rtree->uncommit_region(addr, 2 * cs); + rtree->commit_region(addr + 1 * cs, 4 * cs, stack, diff); + rtree->uncommit_region(addr, 2 * cs, diff); R r[] = { { addr + 2 * cs, 3 * cs} }; check(vmt, rmr, r); - rtree->uncommit_region(addr + 1 * cs, 4 * cs); + rtree->uncommit_region(addr + 1 * cs, 4 * cs, diff); check_empty(vmt, rmr); } { // Remove smaller, overlapping region - at the end - rtree->commit_region(addr, 3 * cs, stack); - rtree->uncommit_region(addr + 2 * cs, 2 * cs); + rtree->commit_region(addr, 3 * cs, stack, diff); + rtree->uncommit_region(addr + 2 * cs, 2 * cs, diff); R r[] = { { addr, 2 * cs} }; check(vmt, rmr, r); - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); check_empty(vmt, rmr); } diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt index 4216eddb885..3c74d7bf816 100644 --- a/test/hotspot/jtreg/ProblemList-Virtual.txt +++ b/test/hotspot/jtreg/ProblemList-Virtual.txt @@ -25,7 +25,6 @@ # Bugs serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java 8308026 generic-all -serviceability/jvmti/GetThreadListStackTraces/OneGetThreadListStackTraces.java 8308027 generic-all serviceability/jvmti/Heap/IterateHeapWithEscapeAnalysisEnabled.java 8264699 generic-all vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java 8308367 generic-all diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index d061236c957..f02ba70ba87 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -79,6 +79,17 @@ compiler/c2/TestVerifyConstraintCasts.java 8355574 generic-all compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64 +compiler/whitebox/DeoptimizeRelocatedNMethod.java#G1 8369147 generic-all +compiler/whitebox/DeoptimizeRelocatedNMethod.java#Parallel 8369147 generic-all +compiler/whitebox/DeoptimizeRelocatedNMethod.java#Serial 8369147 generic-all +compiler/whitebox/DeoptimizeRelocatedNMethod.java#ZGC 8369147 generic-all +compiler/whitebox/RelocateNMethod.java#G1 8369147 generic-all +compiler/whitebox/RelocateNMethod.java#Parallel 8369147 generic-all +compiler/whitebox/RelocateNMethod.java#Serial 8369147 generic-all +compiler/whitebox/RelocateNMethod.java#ZGC 8369147 generic-all +compiler/whitebox/StressNMethodRelocation.java 8369147,8369148,8369149 generic-all +serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java 8369150,8369151 generic-all + ############################################################################# # :hotspot_gc diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 580d9bd11d7..fd9dd6eb4c0 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -92,6 +92,7 @@ hotspot_vector_1 = \ compiler/c2/cr6340864 \ compiler/c2/irTests \ compiler/codegen \ + compiler/gallery \ compiler/loopopts/superword \ compiler/vectorapi \ compiler/vectorization \ diff --git a/test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java b/test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java index 98f26f120b1..3f32f78871c 100644 --- a/test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java +++ b/test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java @@ -76,10 +76,7 @@ public long test1(long value) { @Run(test = "test1") public void run1(RunInfo info) { - long res = 0; - for (int i = 0; i < 10000; i++) { - res |= test1(field_L); - } + long res = test1(field_L); Asserts.assertEQ(res, gold_L); } @@ -92,10 +89,7 @@ public int test2(int value) { @Run(test = "test2") public void run2(RunInfo info) { - int res = 0; - for (int i = 0; i < 10000; i++) { - res |= test2(field_I); - } + int res = test2(field_I); Asserts.assertEQ(res, gold_I); } @@ -113,7 +107,7 @@ public int test3(int value) { @Run(test = "test3") public void run3(RunInfo info) { int res = 0; - for (int i = 1; i < 10000; i++) { + for (int i = 1; i < 100; i++) { res |= test3(i); } Asserts.assertLTE(0, res); @@ -133,7 +127,7 @@ public long test4(long value) { @Run(test = "test4") public void run4(RunInfo info) { long res = 0; - for (long i = 1; i < 10000; i++) { + for (long i = 1; i < 100; i++) { res |= test4(i); } Asserts.assertLTE(0L, res); @@ -151,7 +145,7 @@ public long test5(long value) { @Run(test = "test5") public void run5(RunInfo info) { long res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test5((long)i); } Asserts.assertEQ(-1L, res); @@ -169,7 +163,7 @@ public long test6(long value) { @Run(test = "test6") public void run6(RunInfo info) { long res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test6((long)i); } Asserts.assertLTE(0L, res); @@ -188,7 +182,7 @@ public long test7(long value) { @Run(test = "test7") public void run7(RunInfo info) { long res = Long.MIN_VALUE; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res = Long.max(test7((long)i), res); } Asserts.assertGTE(10000L, res); @@ -206,7 +200,7 @@ public int test8(int value) { @Run(test = "test8") public void run8(RunInfo info) { int res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test8(i); } Asserts.assertEQ(-1, res); @@ -224,7 +218,7 @@ public int test9(int value) { @Run(test = "test9") public void run9(RunInfo info) { int res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test9(i); } Asserts.assertLTE(0, res); @@ -243,10 +237,10 @@ public int test10(int value) { @Run(test = "test10") public void run10(RunInfo info) { int res = Integer.MIN_VALUE; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res = Integer.max(test10(i), res); } - Asserts.assertGTE(10000, res); + Asserts.assertGTE(100, res); } @Test @@ -260,7 +254,7 @@ public int test11(int value) { @Run(test = "test11") public void run11(RunInfo info) { int res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test11(i); } Asserts.assertEQ(0, res); @@ -277,7 +271,7 @@ public long test12(long value) { @Run(test = "test12") public void run12(RunInfo info) { long res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test12(i); } Asserts.assertEQ(0L, res); @@ -294,7 +288,7 @@ public int test13(int value) { @Run(test = "test13") public void run13(RunInfo info) { int res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test13(i); } Asserts.assertEQ(0, res); @@ -311,7 +305,7 @@ public long test14(long value) { @Run(test = "test14") public void run14(RunInfo info) { long res = 0; - for (int i = -10000; i < 10000; i++) { + for (int i = -100; i < 100; i++) { res |= test14(i); } Asserts.assertEQ(0L, res); @@ -327,10 +321,7 @@ public int test15(int src, int mask) { @Run (test = "test15") public void run15(RunInfo info) { - int res = 0; - for (int i = 0; i < 10000; i++) { - res |= test15(0, 0); - } + int res = test15(0, 0); Asserts.assertEQ(0, res); } @@ -408,7 +399,7 @@ public void run16(RunInfo info) { int actual = 0; int expected = 0; - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 100; i++) { int arg1 = GEN_I.next(); int arg2 = GEN_I.next(); @@ -492,7 +483,7 @@ public void run17(RunInfo info) { int actual = 0; int expected = 0; - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 100; i++) { int arg1 = GEN_I.next(); int arg2 = GEN_I.next(); @@ -576,7 +567,7 @@ public void run18(RunInfo info) { long actual = 0; long expected = 0; - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 100; i++) { long arg1 = GEN_L.next(); long arg2 = GEN_L.next(); @@ -660,7 +651,7 @@ public void run19(RunInfo info) { long actual = 0; long expected = 0; - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < 100; i++) { long arg1 = GEN_L.next(); long arg2 = GEN_L.next(); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ConstructorBarriers.java b/test/hotspot/jtreg/compiler/c2/irTests/ConstructorBarriers.java index 7252427ffcd..ba7e7d851b0 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ConstructorBarriers.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ConstructorBarriers.java @@ -123,9 +123,12 @@ public VolatileVolatile(long i) { } long l = 42; + volatile Object global; @DontInline - public void consume(Object o) {} + public void consume(Object o) { + global = o; + } @Test @IR(counts = {IRNode.MEMBAR_STORESTORE, "1"}) diff --git a/test/hotspot/jtreg/compiler/ccp/TestModValueMonotonic.java b/test/hotspot/jtreg/compiler/ccp/TestModValueMonotonic.java new file mode 100644 index 00000000000..346b07c547e --- /dev/null +++ b/test/hotspot/jtreg/compiler/ccp/TestModValueMonotonic.java @@ -0,0 +1,66 @@ +/* + * 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 8367967 + * @summary Ensure ModI/LNode::Value is monotonic with potential division by 0 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:CompileOnly=compiler.ccp.TestModValueMonotonic::test* + * -XX:+StressCCP -XX:RepeatCompilation=100 -Xcomp compiler.ccp.TestModValueMonotonic + * @run main compiler.ccp.TestModValueMonotonic + */ +package compiler.ccp; + +public class TestModValueMonotonic { + static int iFld; + static long lFld; + static int limit = 1000; + static boolean flag; + + public static void main(String[] args) { + testInt(); + testLong(); + } + + static void testInt() { + int zero = 0; + + // Make sure loop is not counted such that it is not removed. Created a more complex graph for CCP. + for (int i = 1; i < limit; i*=4) { + zero = 34; + } + int three = flag ? 0 : 3; + iFld = three % zero; // phi[0..3] % phi[0..34] + } + + static void testLong() { + long zero = 0; + + // Make sure loop is not counted such that it is not removed. Created a more complex graph for CCP. + for (int i = 1; i < limit; i*=4) { + zero = 34; + } + long three = flag ? 0 : 3; + lFld = three % zero; // phi[0..3] % phi[0..34] + } +} diff --git a/test/hotspot/jtreg/compiler/codecache/stress/UnexpectedDeoptimizationTest.java b/test/hotspot/jtreg/compiler/codecache/stress/UnexpectedDeoptimizationTest.java index b3def9455c4..5ad047c826e 100644 --- a/test/hotspot/jtreg/compiler/codecache/stress/UnexpectedDeoptimizationTest.java +++ b/test/hotspot/jtreg/compiler/codecache/stress/UnexpectedDeoptimizationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, 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 @@ -31,26 +31,26 @@ * * @build jdk.test.whitebox.WhiteBox compiler.codecache.stress.Helper compiler.codecache.stress.TestCaseImpl * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=240 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:-DeoptimizeRandom * -XX:CompileCommand=dontinline,compiler.codecache.stress.Helper$TestCase::method * -XX:-SegmentedCodeCache * compiler.codecache.stress.UnexpectedDeoptimizationTest - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=240 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:-DeoptimizeRandom * -XX:CompileCommand=dontinline,compiler.codecache.stress.Helper$TestCase::method * -XX:+SegmentedCodeCache * compiler.codecache.stress.UnexpectedDeoptimizationTest - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=240 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:-DeoptimizeRandom * -XX:CompileCommand=dontinline,compiler.codecache.stress.Helper$TestCase::method * -XX:-SegmentedCodeCache * -DhelperVirtualThread=true * compiler.codecache.stress.UnexpectedDeoptimizationTest - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * @run main/othervm/timeout=240 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:-DeoptimizeRandom * -XX:CompileCommand=dontinline,compiler.codecache.stress.Helper$TestCase::method @@ -75,7 +75,7 @@ public static void main(String[] args) { public void run() { Helper.WHITE_BOX.deoptimizeFrames(rng.nextBoolean()); // Sleep a short while to allow the stacks to grow - otherwise - // we end up running almost all code in the interpreter + // we end up running almost all code in the interpreter try { Thread.sleep(10); } catch (Exception e) { diff --git a/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java b/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java new file mode 100644 index 00000000000..e8575cfe6b6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java @@ -0,0 +1,215 @@ +/* + * 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 8364305 +* @summary Test scalar float/double to integral cast +* @requires vm.compiler2.enabled +* @library /test/lib / +* @run main/othervm/native compiler.floatingpoint.ScalarFPtoIntCastTest +*/ + +package compiler.floatingpoint; + +import compiler.lib.ir_framework.*; +import compiler.lib.generators.Generator; +import static compiler.lib.generators.Generators.G; +import compiler.lib.verify.Verify; + +public class ScalarFPtoIntCastTest { + private static final int COUNT = 16; + + private float[] float_arr; + private double[] double_arr; + private long[] long_float_arr; + private long[] long_double_arr; + private int[] int_float_arr; + private int[] int_double_arr; + private short[] short_float_arr; + private short[] short_double_arr; + private byte[] byte_float_arr; + private byte[] byte_double_arr; + + private static final Generator genF = G.floats(); + private static final Generator genD = G.doubles(); + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.start(); + } + + public ScalarFPtoIntCastTest() { + long_float_arr = new long[COUNT]; + long_double_arr = new long[COUNT]; + int_float_arr = new int[COUNT]; + int_double_arr = new int[COUNT]; + short_float_arr = new short[COUNT]; + short_double_arr = new short[COUNT]; + byte_float_arr = new byte[COUNT]; + byte_double_arr = new byte[COUNT]; + float_arr = new float[COUNT]; + double_arr = new double[COUNT]; + + G.fill(genF, float_arr); + G.fill(genD, double_arr); + for (int i = 0; i < COUNT; i++) { + long_float_arr[i] = (long) float_arr[i]; + long_double_arr[i] = (long) double_arr[i]; + int_float_arr[i] = (int) float_arr[i]; + int_double_arr[i] = (int) double_arr[i]; + short_float_arr[i] = (short) float_arr[i]; + short_double_arr[i] = (short) double_arr[i]; + byte_float_arr[i] = (byte) float_arr[i]; + byte_double_arr[i] = (byte) double_arr[i]; + } + } + + @Test + @IR(counts = {IRNode.CONV_F2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_F2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_F2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void float2int() { + for (int i = 0; i < COUNT; i++) { + float float_val = float_arr[i]; + int computed = (int) float_val; + int expected = int_float_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_F2L, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_F2L, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_F2L_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void float2long() { + for (int i = 0; i < COUNT; i++) { + float float_val = float_arr[i]; + long computed = (long) float_val; + long expected = long_float_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_F2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_F2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_F2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void float2short() { + for (int i = 0; i < COUNT; i++) { + float float_val = float_arr[i]; + short computed = (short) float_val; + short expected = short_float_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_F2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_F2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_F2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void float2byte() { + for (int i = 0; i < COUNT; i++) { + float float_val = float_arr[i]; + byte computed = (byte) float_val; + byte expected = byte_float_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_D2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_D2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_D2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void double2int() { + for (int i = 0; i < COUNT; i++) { + double double_val = double_arr[i]; + int computed = (int) double_val; + int expected = int_double_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_D2L, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_D2L, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_D2L_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void double2long() { + for (int i = 0; i < COUNT; i++) { + double double_val = double_arr[i]; + long computed = (long) double_val; + long expected = long_double_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_D2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_D2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_D2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void double2short() { + for (int i = 0; i < COUNT; i++) { + double double_val = double_arr[i]; + short computed = (short) double_val; + short expected = short_double_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_D2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_D2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_D2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void double2byte() { + for (int i = 0; i < COUNT; i++) { + double double_val = double_arr[i]; + byte computed = (byte) double_val; + byte expected = byte_double_arr[i]; + Verify.checkEQ(computed, expected); + } + } +} diff --git a/test/hotspot/jtreg/compiler/gallery/NormalMapping.java b/test/hotspot/jtreg/compiler/gallery/NormalMapping.java new file mode 100644 index 00000000000..100f4ebaaea --- /dev/null +++ b/test/hotspot/jtreg/compiler/gallery/NormalMapping.java @@ -0,0 +1,554 @@ +/* + * 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.gallery; + +import javax.imageio.ImageIO; +import javax.swing.JFrame; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.io.IOException; +import java.util.Random; +import javax.swing.JPanel; +import java.awt.Font; + +import java.net.URL; +import java.net.URISyntaxException; +import java.io.File; +import java.util.Arrays; + +/** + * I presented this demo at the JVMLS 2025 conference, when giving + * a talk about Auto-Vectorization in HotSpot, see: + * https://inside.java/2025/08/16/jvmls-hotspot-auto-vectorization/ + * + * This is a stand-alone test that you can run directly with: + * java NormalMapping.java + * + * If you want to disable the auto-vectorizer, you can run: + * java -XX:-UseSuperWord NormalMapping.java + * + * On x86, you can also play with the UseAVX flag: + * java -XX:UseAVX=1 NormalMapping.java + * + * There is a JTREG test that automatically runs this demo, + * see {@link TestNormalMapping}. + * + * My motivation for JVMLS 2025 was to present something that vectorizes + * in an "embarassingly parallel" way. It should be something that C2's + * SuperWord Auto Vectorizer could already do for many JDK releases, + * and also has some visual appeal. I decided to use normal mapping, see: + * https://en.wikipedia.org/wiki/Normal_mapping + * + * At the conference, I only had the version that loads a normal map + * from an image. I now also added some "generated" cases, which are + * created from 2d height functions, and then converted to normal + * maps. This allows us to show more "surfaces" without having to + * store the images for all those cases. + * + * If you are interested in understanding the components, then look at these: + * - computeLight: the normal mapping "shader / kernel". + * - generateNormals / computeNormals: computing normals from height functions. + * - nextNormals: add you own normal map png or height function. + * - main: setup and endless-loop that triggers normals to be swapped periodically. + * - MyDrawingPanel: drawing all the parts to the screen. + */ +public class NormalMapping { + public static Random RANDOM = new Random(); + + // Increasing this number will make the demo slower. + public static final int NUMBER_OF_LIGHTS = 5; + + public static void main(String[] args) { + System.out.println("Welcome to the Normal Mapping Demo!"); + State state = new State(NUMBER_OF_LIGHTS); + + // Set up a panel we can draw on, and put it in a window. + System.out.println("Setting up Window..."); + MyDrawingPanel panel = new MyDrawingPanel(state); + JFrame frame = new JFrame("Normal Mapping Demo (Auto-Vectorization)"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(2000, 1000); + frame.add(panel); + frame.setVisible(true); + System.out.println("Running Demo..."); + + try { + // Tight loop where we redraw the panel as fast as possible. + int count = 0; + while (true) { + Thread.sleep(1); + state.update(); + panel.repaint(); + if (count++ > 500) { + count = 0; + state.nextNormals(); + } + } + } catch (InterruptedException e) { + System.out.println("Interrputed, terminating demo."); + } finally { + System.out.println("Shut down demo."); + frame.setVisible(false); + frame.dispose(); + } + } + + public static File getLocalFile(String name) { + // If we are in JTREG IR testing mode, we have to get the path via system property, + // if it is run in stand-alone that property is not available, and we can load + // via getResource. + System.out.println("Loading file: " + name); + String testSrc = System.getProperty("test.src", null); + System.out.println("System Property test.src: " + testSrc); + if (testSrc == null) { + URL path = NormalMapping.class.getResource(name); + System.out.println(" Loading via getResource: " + path); + try { + return new File(path.toURI()); + } catch (URISyntaxException e) { + throw new RuntimeException("Could not load: ", e); + } + } else { + return new File(testSrc + "/" + name); + } + } + + public static BufferedImage loadImage(File file) { + try { + return ImageIO.read(file); + } catch (IOException e) { + throw new RuntimeException("Could not load: ", e); + } + } + + /** + * This class represents the lights that are located on the normal map, + * moved around randomly, and shine their color of light on the scene. + */ + public static class Light { + public float x = 0.5f; + public float y = 0.5f; + private float dx; + private float dy; + + private float h; + public float r; + public float g; + public float b; + + Light() { + this.h = RANDOM.nextFloat(); + } + + // Random movement of the Light + public void update() { + // Random acceleration with dampening. + dx *= 0.99; + dy *= 0.99; + dx += RANDOM.nextFloat() * 0.001 - 0.0005; + dy += RANDOM.nextFloat() * 0.001 - 0.0005; + x += dx; + y += dy; + + // Boounce off the walls. + if (x < 0) { dx = +Math.abs(dx); } + if (x > 1) { dx = -Math.abs(dx); } + if (y < 0) { dy = +Math.abs(dy); } + if (y > 1) { dy = -Math.abs(dy); } + + // Rotate the hue -> gets us nice rainbow colors. + h += 0.001 + RANDOM.nextFloat() * 0.0002; + Color c = Color.getHSBColor(h, 1f, 1f); + r = (1f / 256f) * c.getRed(); + g = (1f / 256f) * c.getGreen(); + b = (1f / 256f) * c.getBlue(); + } + } + + /** + * This class manages the state of the demo, including the lights, + * arrays passed in and out of the normal map computation, as well + * as the image buffers and FPS tracking. + */ + public static class State { + private static final int sizeX = 1000; + private static final int sizeY = 1000; + + public Light[] lights; + + public float[] coordsX; + public float[] coordsY; + + private int nextNormalsId = 0; + public BufferedImage normals; + public float[] normalsX; + public float[] normalsY; + public float[] normalsZ; + + public BufferedImage output; + public BufferedImage output_2; + public int[] outputRGB; + public int[] outputRGB_2; + + public long lastTime; + public float fps; + + float luminosityCorrection = 1f; + + public State(int numberOfLights) { + lights = new Light[numberOfLights]; + for (int i = 0; i < lights.length; i++) { + lights[i] = new Light(); + } + + // Coordinates + this.coordsX = new float[sizeX * sizeY]; + this.coordsY = new float[sizeX * sizeY]; + for (int y = 0; y < sizeY; y++) { + for (int x = 0; x < sizeX; x++) { + this.coordsX[y * sizeX + x] = x * (1f / sizeX); + this.coordsY[y * sizeX + x] = y * (1f / sizeY); + } + } + + nextNormals(); + + // Double buffered output images, where we render to. + // Without double buffering, we would get some flickering effects, + // because we would be concurrently updating the buffer and drawing it. + this.output = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_RGB); + this.output_2 = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_RGB); + this.outputRGB = ((DataBufferInt) output.getRaster().getDataBuffer()).getData(); + this.outputRGB_2 = ((DataBufferInt) output_2.getRaster().getDataBuffer()).getData(); + + // Set up the FPS tracker + lastTime = System.nanoTime(); + } + + public void nextNormals() { + switch (nextNormalsId) { + case 0 -> setNormals(loadNormals("normal_map.png")); + case 1 -> setNormals(generateNormals("heart")); + case 2 -> setNormals(generateNormals("hex")); + case 3 -> setNormals(generateNormals("cone")); + case 4 -> setNormals(generateNormals("ripple")); + case 5 -> setNormals(generateNormals("hill")); + case 6 -> setNormals(generateNormals("ripple2")); + case 7 -> setNormals(generateNormals("cones")); + case 8 -> setNormals(generateNormals("spheres")); + case 9 -> setNormals(generateNormals("donut")); + default -> throw new RuntimeException(); + } + nextNormalsId = (nextNormalsId + 1) % 10; + } + + public BufferedImage loadNormals(String name) { + // Extract normal values from RGB image + // The loaded image may not have the desired INT_RGB format, so first convert it + BufferedImage normalsLoaded = loadImage(getLocalFile(name)); + BufferedImage buf = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_RGB); + buf.getGraphics().drawImage(normalsLoaded, 0, 0, null); + return buf; + } + + public void setNormals(BufferedImage buf) { + this.normals = buf; + + int[] normalsRGB = ((DataBufferInt) this.normals.getRaster().getDataBuffer()).getData(); + this.normalsX = new float[sizeX * sizeY]; + this.normalsY = new float[sizeX * sizeY]; + this.normalsZ = new float[sizeX * sizeY]; + for (int y = 0; y < sizeY; y++) { + for (int x = 0; x < sizeX; x++) { + this.coordsY[y * sizeX + x] = y * (1f / sizeY); + int normal = normalsRGB[y * sizeX + x]; + // RGB values in range [0 ... 255] + int nr = (normal >> 16) & 0xff; + int ng = (normal >> 8) & 0xff; + int nb = (normal >> 0) & 0xff; + + // Map range [0..255] -> [-1 .. 1] + float nx = ((float)nr) * (1f / 128f) - 1f; + float ny = ((float)ng) * (1f / 128f) - 1f; + float nz = ((float)nb) * (1f / 128f) - 1f; + + this.normalsX[y * sizeX + x] = -nx; + this.normalsY[y * sizeX + x] = ny; + this.normalsZ[y * sizeX + x] = nz; + } + } + } + + interface HeightFunction { + // x and y should be in [0..1] + double call(double x, double y); + } + + public BufferedImage generateNormals(String name) { + System.out.println(" generate normals for: " + name); + return computeNormals((double x, double y) -> { + // Scale out, so we see a little more + x = 10 * (x - 0.5); + y = 10 * (y - 0.5); + + // A selection of "height functions": + return switch (name) { + case "cone" -> 0.1 * Math.max(0, 2 - Math.sqrt(x * x + y * y)); + case "heart" -> { + double heart = Math.abs(Math.pow(x * x + y * y - 1, 3) - x * x * Math.pow(-y, 3)); + double decay = Math.exp(-(x * x + y * y)); + yield 0.1 * heart * decay; + } + case "hill" -> 0.5 * Math.exp(-(x * x + y * y)); + case "ripple" -> 0.01 * Math.sin(x * x + y * y); + case "ripple2" -> 0.3 * Math.sin(x) * Math.sin(y); + case "donut" -> { + double d = Math.sqrt(x * x + y * y) - 2; + double i = 1 - d*d; + yield (i >= 0) ? 0.1 * Math.sqrt(i) : 0; + } + case "hex" -> { + double f = 3.0; + double a = Math.cos(f * x); + double b = Math.cos(f * (-0.5 * x + Math.sqrt(3) / 2.0 * y)); + double c = Math.cos(f * (-0.5 * x - Math.sqrt(3) / 2.0 * y)); + yield 0.03 * (a + b + c); + } + case "cones" -> { + double scale = 2.0; + double r = 0.8; + double cx = scale * (Math.floor(x / scale) + 0.5); + double cy = scale * (Math.floor(y / scale) + 0.5); + double dx = x - cx; + double dy = y - cy; + double d = Math.sqrt(dx * dx + dy * dy); + yield 0.1 * Math.max(0, 0.8 - d); + } + case "spheres" -> { + double scale = 2.0; + double r = 0.8; + double cx = scale * (Math.floor(x / scale) + 0.5); + double cy = scale * (Math.floor(y / scale) + 0.5); + double dx = x - cx; + double dy = y - cy; + double d2 = dx * dx + dy * dy; + if (d2 <= r * r) { + yield 0.03 * Math.sqrt(r * r - d2); + } + yield 0.0; + } + default -> throw new RuntimeException("not supported: " + name); + }; + }); + } + + public static BufferedImage computeNormals(HeightFunction fun) { + BufferedImage out = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_RGB); + int[] arr = ((DataBufferInt) out.getRaster().getDataBuffer()).getData(); + int sx = out.getWidth(); + int sy = out.getHeight(); + + double delta = 0.00001; + double dxx = 1.0 / sx; + double dyy = 1.0 / sy; + for (int yy = 0; yy < sy; yy++) { + int nStart = sy * yy; + for (int xx = 0; xx < sx; xx++) { + double x = xx * dxx; + double y = yy * dyy; + + // Compute the partial derivatives in x and y direction; + double fdx = fun.call(x + delta, y) - fun.call(x - delta, y); + double fdy = fun.call(x, y + delta) - fun.call(x, y - delta); + // We can compute the normal from the cross product of: + // + // df/dx x df/dy = [2*delta, 0, fdx] x [0, 2*delta, fdy] + // = [0*fdy - fdx*2*delta, fdx*0 - 2*delta*fdy, 2*delta*2*delta - 0*0] + double nx = -fdx * 2 * delta; + double ny = -2 * delta * fdy; + double nz = 2 * delta * 2 * delta; + + // normalize + float dist = (float)Math.sqrt(nx * nx + ny * ny + nz * nz); + nx /= dist; + ny /= dist; + nz /= dist; + + // Now transform [-1..1] -> [0..255] + int r = (int)(nx * 127f + 127f) & 0xff; + int g = (int)(ny * 127f + 127f) & 0xff; + int b = (int)(nz * 127f + 127f) & 0xff; + int c = (r << 16) + (g << 8) + b; + arr[nStart + xx] = c; + } + } + return out; + } + + public void update() { + long nowTime = System.nanoTime(); + float newFPS = 1e9f / (nowTime - lastTime); + fps = 0.99f * fps + 0.01f * newFPS; + lastTime = nowTime; + + for (Light light : lights) { + light.update(); + } + + // Reset the buffer + int[] outputArray = ((DataBufferInt) output.getRaster().getDataBuffer()).getData(); + Arrays.fill(outputArray, 0); + + // Add in the contribution of each light + for (Light l : lights) { + computeLight(l); + } + computeLuminosityCorrection(); + + // Swap the buffers for double buffering. + var outputTmp = output; + output = output_2; + output_2 = outputTmp; + + var outputRGBTmp = outputRGB; + outputRGB = outputRGB_2; + outputRGB_2 = outputRGBTmp; + } + + public void computeLight(Light l) { + for (int i = 0; i < outputRGB.length; i++) { + float x = coordsX[i]; + float y = coordsY[i]; + float nx = normalsX[i]; + float ny = normalsY[i]; + float nz = normalsZ[i]; + + // Compute distance vector between the light and the pixel + float dx = x - l.x; + float dy = y - l.y; + float dz = 0.2f; // how much the lights float above the scene + + // Compute the distance (dot product of d with itself) + float d2 = dx * dx + dy * dy + dz * dz; + float d = (float)Math.sqrt(d2); + float d3 = d * d2; + + // Compute dot-product between distance and normal vector + float dotProduct = nx * dx + ny * dy + nz * dz; + + // If the dot-product is negative: + // Light on wrong side -> 0 + // If the dot-product is positive: + // There should be light normalize by distance (d), and divide by the + // squared distance (d2) to have physically accurately decaying light. + // Correct the luminosity so the RGB values are going to be close + // to 255, but not over. + float luminosity = Math.max(0, dotProduct / d3) * luminosityCorrection; + + // Now we compute the color values that hopefully end up in the range + // [0..255]. If the hack/trick with luminosityCorrection fails, we may + // occasionally go out of the range and generate an overflow in the masking. + // This can lead to some funky visual artifacts around the lights, but it + // is quite rare. + // + // Feel free to play with the targetExposure below, and see if you can + // observe the artefacts. + int r = (int)(luminosity * l.r) & 0xff; + int g = (int)(luminosity * l.g) & 0xff; + int b = (int)(luminosity * l.b) & 0xff; + int c = (r << 16) + (g << 8) + b; + outputRGB[i] += c; + } + } + + // This is a bit of a horrible hack, but it mostly works. + // Essentially, it tries to solve the "exposure" problem: + // It is hard to know how much light a pixel will receive at most, and + // we have to convert this value to a byte [0..255] at some point. + // If we chose the "exposure" too low, we get a very dark picture + // that is not very exciting to look at. If we over-expose, then we + // may overflow/clip the range [0..255], leading to unpleasant visual + // artifacts. + public void computeLuminosityCorrection() { + // Find maximum R, G, and B value. + float maxR = 0; + float maxG = 0; + float maxB = 0; + for (int i = 0; i < outputRGB.length; i++) { + int c = outputRGB[i]; + int cr = (c >> 16) & 0xff; + int cg = (c >> 8) & 0xff; + int cb = (c >> 0) & 0xff; + + maxR = Math.max(maxR, cr); + maxG = Math.max(maxG, cg); + maxB = Math.max(maxB, cb); + } + + float maxC = Math.max(Math.max(maxR, maxG), maxB); + + // Correct the maximum value to be 230, so we are safely in range 0..255 + // Setting it instead to 255 will make the image brighter, but most likely + // it will give you some funky artefacts. + // Setting it to 100 will make the image darker. + float targetExposure = 230f; + luminosityCorrection *= targetExposure / maxC; + } + } + + public static class MyDrawingPanel extends JPanel { + private final State state; + + public MyDrawingPanel(State state) { + this.state = state; + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + Graphics2D g2d = (Graphics2D) g; + + // Draw color output + g2d.drawImage(state.output_2, 0, 0, null); + + // Draw position of lights + for (Light l : state.lights) { + g2d.setColor(new Color(l.r, l.g, l.b)); + g2d.fillRect((int)(1000f * l.x) - 3, (int)(1000f * l.y) - 3, 6, 6); + } + + g2d.setColor(new Color(0, 0, 0)); + g2d.fillRect(0, 0, 150, 35); + g2d.setColor(new Color(255, 255, 255)); + g2d.setFont(new Font("Consolas", Font.PLAIN, 30)); + g2d.drawString("FPS: " + (int)Math.floor(state.fps), 0, 30); + + g2d.drawImage(state.normals, 1000, 0, null); + } + } +} diff --git a/test/hotspot/jtreg/compiler/gallery/TestNormalMapping.java b/test/hotspot/jtreg/compiler/gallery/TestNormalMapping.java new file mode 100644 index 00000000000..5c133822485 --- /dev/null +++ b/test/hotspot/jtreg/compiler/gallery/TestNormalMapping.java @@ -0,0 +1,115 @@ +/* + * 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=ir + * @bug 8367657 + * @summary Visual example of auto vectorization: normal mapping. + * @library /test/lib / + * @run driver compiler.gallery.TestNormalMapping ir + */ + +/* + * @test id=visual + * @key headful + * @library /test/lib / + * @run main compiler.gallery.TestNormalMapping visual + */ + +package compiler.gallery; + +import jdk.test.lib.Utils; + +import compiler.lib.ir_framework.*; + +/** + * This test is the JTREG version for automatic verification of the stand-alone + * {@link NormalMapping}. If you just want to run the demo and play with it, + * go look at the documentation in {@link NormalMapping}. + * Here, we launch both a visual version that just runs for a few seconds, to see + * that there are no crashes, but we don't do any specific verification. + * We also have an IR test, that ensures that we get vectorization. + */ +public class TestNormalMapping { + public static void main(String[] args) throws InterruptedException { + String mode = args[0]; + System.out.println("Running JTREG test in mode: " + mode); + + switch (mode) { + case "ir" -> runIR(); + case "visual" -> runVisual(); + default -> throw new RuntimeException("Unknown mode: " + mode); + } + } + + private static void runIR() { + System.out.println("Testing with IR rules..."); + String src = System.getProperty("test.src", null); + if (src == null) { throw new RuntimeException("Could not find test.src property."); } + TestFramework.runWithFlags("-Dtest.src=" + src, + "-XX:CompileCommand=inline,compiler.gallery.NormalMapping$State::update", + "-XX:CompileCommand=inline,compiler.gallery.NormalMapping$State::computeLight"); + } + + private static void runVisual() throws InterruptedException { + System.out.println("Testing with 2d Graphics (visual)..."); + + // We will not do anything special here, just launch the application, + // tell it to run for 10 second, interrupt it and let it shut down. + Thread thread = new Thread() { + public void run() { + NormalMapping.main(null); + } + }; + thread.setDaemon(true); + thread.start(); + Thread.sleep(Utils.adjustTimeout(10000)); // let demo run for 10 seconds + thread.interrupt(); + Thread.sleep(Utils.adjustTimeout(1000)); // allow demo 1 second for shutdown + } + + // ---------------------- For the IR testing part only -------------------------------- + NormalMapping.State state = new NormalMapping.State(5); + + @Test + @Warmup(1000) + @IR(counts = {IRNode.REPLICATE_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.REPLICATE_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.LOAD_VECTOR_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.SUB_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.MUL_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.ADD_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.SQRT_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.MAX_VF, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.AND_VI, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.LSHIFT_VI, IRNode.VECTOR_SIZE + "min(max_int, max_float)", "> 0", + IRNode.STORE_VECTOR, "> 0"}, + applyIf = {"AlignVector", "false"}, + applyIfPlatform = {"64-bit", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + private void testIR() { + // This call should inline givne the CompileCommand above. + state.update(); + } +} diff --git a/test/hotspot/jtreg/compiler/gallery/normal_map.png b/test/hotspot/jtreg/compiler/gallery/normal_map.png new file mode 100644 index 00000000000..d3950125e72 Binary files /dev/null and b/test/hotspot/jtreg/compiler/gallery/normal_map.png differ diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java index 8b794e13e3f..06b2afa8a67 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java @@ -98,9 +98,9 @@ public enum CompilePhase { PHASEIDEALLOOP2( "PhaseIdealLoop 2"), PHASEIDEALLOOP3( "PhaseIdealLoop 3"), AUTO_VECTORIZATION1_BEFORE_APPLY( "AutoVectorization 1, before Apply"), - AUTO_VECTORIZATION2_AFTER_REORDER( "AutoVectorization 2, after Apply Memop Reordering"), - AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT( "AutoVectorization 3, after Adjusting Pre-loop Limit"), - AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS("AutoVectorization 4, after Adding Speculative Runtime Checks"), + AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT( "AutoVectorization 2, after Adjusting Pre-loop Limit"), + AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS("AutoVectorization 3, after Adding Speculative Runtime Checks"), + AUTO_VECTORIZATION5_AFTER_APPLY( "AutoVectorization 4, after Apply"), BEFORE_CCP1( "Before PhaseCCP 1"), CCP1( "PhaseCCP 1"), ITER_GVN2( "Iter GVN 2"), diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 88b34841e57..15378feb841 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -610,11 +610,31 @@ public class IRNode { beforeMatchingNameRegex(CONV, "Conv"); } + public static final String CONV_D2I = PREFIX + "CONV_D2I" + POSTFIX; + static { + beforeMatchingNameRegex(CONV_D2I, "ConvD2I"); + } + + public static final String CONV_D2L = PREFIX + "CONV_D2L" + POSTFIX; + static { + beforeMatchingNameRegex(CONV_D2L, "ConvD2L"); + } + public static final String CONV_F2HF = PREFIX + "CONV_F2HF" + POSTFIX; static { beforeMatchingNameRegex(CONV_F2HF, "ConvF2HF"); } + public static final String CONV_F2I = PREFIX + "CONV_F2I" + POSTFIX; + static { + beforeMatchingNameRegex(CONV_F2I, "ConvF2I"); + } + + public static final String CONV_F2L = PREFIX + "CONV_F2L" + POSTFIX; + static { + beforeMatchingNameRegex(CONV_F2L, "ConvF2L"); + } + public static final String CONV_I2L = PREFIX + "CONV_I2L" + POSTFIX; static { beforeMatchingNameRegex(CONV_I2L, "ConvI2L"); @@ -2675,6 +2695,66 @@ public class IRNode { machOnlyNameRegex(VSTOREMASK_TRUECOUNT, "vstoremask_truecount_neon"); } + public static final String X86_SCONV_D2I = PREFIX + "X86_SCONV_D2I" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_D2I, "convD2I_reg_reg"); + } + + public static final String X86_SCONV_D2L = PREFIX + "X86_SCONV_D2L" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_D2L, "convD2L_reg_reg"); + } + + public static final String X86_SCONV_F2I = PREFIX + "X86_SCONV_F2I" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_F2I, "convF2I_reg_reg"); + } + + public static final String X86_SCONV_F2L = PREFIX + "X86_SCONV_F2L" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_F2L, "convF2L_reg_reg"); + } + + public static final String X86_SCONV_D2I_AVX10 = PREFIX + "X86_SCONV2_D2I_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_D2I_AVX10, "convD2I_(reg_reg|reg_mem)_avx10"); + } + + public static final String X86_SCONV_D2L_AVX10 = PREFIX + "X86_SCONV_D2L_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_D2L_AVX10, "convD2L_(reg_reg|reg_mem)_avx10"); + } + + public static final String X86_SCONV_F2I_AVX10 = PREFIX + "X86_SCONV_F2I_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_F2I_AVX10, "convF2I_(reg_reg|reg_mem)_avx10"); + } + + public static final String X86_SCONV_F2L_AVX10 = PREFIX + "X86_SCONV_F2L_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_F2L_AVX10, "convF2L_(reg_reg|reg_mem)_avx10"); + } + + public static final String X86_VCAST_F2X = PREFIX + "X86_VCAST_F2X" + POSTFIX; + static { + machOnlyNameRegex(X86_VCAST_F2X, "castFtoX_reg_(av|eve)x"); + } + + public static final String X86_VCAST_D2X = PREFIX + "X86_VCAST_D2X" + POSTFIX; + static { + machOnlyNameRegex(X86_VCAST_D2X, "castDtoX_reg_(av|eve)x"); + } + + public static final String X86_VCAST_F2X_AVX10 = PREFIX + "X86_VCAST_F2X_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_VCAST_F2X_AVX10, "castFtoX_(reg|mem)_avx10"); + } + + public static final String X86_VCAST_D2X_AVX10 = PREFIX + "X86_VCAST_D2X_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_VCAST_D2X_AVX10, "castDtoX_(reg|mem)_avx10"); + } + public static final String XOR = PREFIX + "XOR" + POSTFIX; static { beforeMatchingNameRegex(XOR, "Xor(I|L)"); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md index 2a454f2990d..1a8149aa28d 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md @@ -180,7 +180,7 @@ The framework provides various stress and debug flags. They should mainly be use - `-DPrintTimes=true`: Print the execution time measurements of each executed test. - `-DPrintRuleMatchingTime=true`: Print the time of matching IR rules per method. Slows down the execution as the rules are warmed up before meassurement. - `-DVerifyVM=true`: The framework runs the test VM with additional verification flags (slows the execution down). -- `-DExcluceRandom=true`: The framework randomly excludes some methods from compilation. IR verification is disabled completely with this flag. +- `-DExcludeRandom=true`: The framework randomly excludes some methods from compilation. IR verification is disabled completely with this flag. - `-DFlipC1C2=true`: The framework compiles all `@Test` annotated method with C1 if a C2 compilation would have been applied and vice versa. IR verification is disabled completely with this flag. - `-DShuffleTests=false`: Disables the random execution order of all tests (such a shuffling is always done by default). - `-DDumpReplay=true`: Add the `DumpReplay` directive to the test VM. @@ -188,7 +188,6 @@ The framework provides various stress and debug flags. They should mainly be use - `-DTestCompilationTimeout=20`: Change the default waiting time (default: 10s) for a compilation of a normal `@Test` annotated method. - `-DWaitForCompilationTimeout=20`: Change the default waiting time (default: 10s) for a compilation of a `@Test` annotated method with compilation level [WAIT\_FOR\_COMPILATION](./CompLevel.java). - `-DIgnoreCompilerControls=true`: Ignore all compiler controls applied in the framework. This includes any compiler control annotations (`@DontCompile`, `@DontInline`, `@ForceCompile`, `@ForceInline`, `@ForceCompileStaticInitializer`), the exclusion of `@Run` and `@Check` methods from compilation, and the directive to not inline `@Test` annotated methods. -- `-DExcludeRandom=true`: Randomly exclude some methods from compilation. - `-DPreferCommandLineFlags=true`: Prefer flags set via the command line over flags specified by the tests. ## 3. Test Framework Execution diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java index 16b4654013a..c05124edcd7 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java @@ -106,6 +106,7 @@ public class IREncodingPrinter { "avx512_fp16", "avx512_vnni", "avx512_vbmi", + "avx10_2", "bmi2", // AArch64 "sha3", diff --git a/test/hotspot/jtreg/compiler/loopstripmining/MissingStoreAfterOuterStripMinedLoop.java b/test/hotspot/jtreg/compiler/loopstripmining/MissingStoreAfterOuterStripMinedLoop.java new file mode 100644 index 00000000000..24e3c4a5d30 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopstripmining/MissingStoreAfterOuterStripMinedLoop.java @@ -0,0 +1,137 @@ +/* + * 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 8364757 + * @summary Moving Store nodes from the main CountedLoop to the OuterStripMinedLoop causes + * subsequent Store nodes to be eventually removed because of missing Phi nodes, + * leading to wrong results. + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation + * -Xcomp -XX:-UseLoopPredicate + * -XX:+UnlockDiagnosticVMOptions -XX:-UseAutoVectorizationPredicate + * -XX:CompileCommand=compileonly,compiler.loopstripmining.MissingStoreAfterOuterStripMinedLoop::test* + * compiler.loopstripmining.MissingStoreAfterOuterStripMinedLoop + * @run main compiler.loopstripmining.MissingStoreAfterOuterStripMinedLoop + * + */ + +package compiler.loopstripmining; + +public class MissingStoreAfterOuterStripMinedLoop { + public static int x = 0; + public static int y = 0; + + static class A { + int field; + } + + // The store node in the loop body is moved to the OuterStripLoop. + // When making the post loop the new store node + // should have the moved store node as memory input, and not the + // initial x = 0 store. + // + // store (x = 0) + // | + // store (x += 1, exit of CountedLoop main) + // | <-- additional rewiring due to absence of phi node + // store (x += 1, exit of CountedLoop post) + // | + // store (x = 0) + static public void test1() { + x = 0; + for (int i = 0; i < 20000; i++) { + x += i; + } + x = 0; + } + + // Two independent stores + // They should be wired independently in the post loop, no aliasing + static public void test2() { + x = 0; + y = 0; + for (int i = 0; i < 20000; i++) { + x += i; + y += i; + } + x = 0; + y = 0; + } + + // Chain of stores with potential aliasing. + // The entire chain is moved to the OuterStripLoop, between the + // inner loop exit and the safepoint. + // The chain should be preserved when cloning the main loop body + // to create the post loop. Only the first store of the post loop + // should be rewired to have the last store of the main loop + // as memory input. + // + // ... + // | + // store (a1.field = v, exit of CountedLoop main) + // | + // store (a2.field = v, exit of CountedLoop main) + // | + // store (a3.field = v, exit of CountedLoop main) + // | <-- only additional rewiring needed + // store (a1.field = v, exit of CountedLoop post) + // | + // store (a2.field = v, exit of CountedLoop post) + // | + // store (a3.field = v, exit of CountedLoop post) + static public void test3(A a1, A a2, A a3) { + a1.field = 0; + a2.field = 0; + a3.field = 0; + int v = 0; + for (int i = 0; i < 20000; i++) { + v++; + a1.field = v; + a2.field = v; + a3.field = v; + } + } + + public static void main(String[] strArr) { + A a1 = new A(); + A a2 = new A(); + A a3 = new A(); + + test1(); + if (x != 0) { + throw new RuntimeException("unexpected value: " + x); + } + + test2(); + if (x != 0 || y != 0) { + throw new RuntimeException("unexpected value: " + x + " " + y); + } + + test3(a1, a2, a3); + if (a1.field != 20000 || a2.field != 20000 || a3.field != 20000) { + throw new RuntimeException("unexpected value: " + a1.field + " " + a2.field + " " + a3.field); + } + } +} diff --git a/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsMany.java b/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsMany.java new file mode 100644 index 00000000000..dbc6e495594 --- /dev/null +++ b/test/hotspot/jtreg/compiler/stringopts/TestStackedConcatsMany.java @@ -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. + */ + +/* + * @test + * @bug 8362394 + * @summary Test that repeated stacked string concatenations do not + * consume too many compilation resources. + * @requires vm.compiler2.enabled + * @library /test/lib / + * @run main/othervm -XX:-OptoScheduling compiler.stringopts.TestStackedConcatsMany + * @run main/othervm -XX:-TieredCompilation -Xcomp -XX:-OptoScheduling + * -XX:CompileOnly=compiler.stringopts.TestStackedConcatsMany::f + * compiler.stringopts.TestStackedConcatsMany + */ + +// The test uses -XX:-OptoScheduling to avoid the assert "too many D-U pinch points" on aarch64 (JDK-8328078). + +package compiler.stringopts; + +import jdk.test.lib.Asserts; + +public class TestStackedConcatsMany { + + public static void main (String... args) { + new StringBuilder(); // Trigger loading of the StringBuilder class. + String s = f(); + String z = "xy"; + for (int i = 0; i < 24; i++) { + z = z + z; + } + Asserts.assertEQ(s, z); + } + + static String f() { + String s = "xy"; + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + s = new StringBuilder().append(s).append(s).toString(); + s = new StringBuilder().append(s).append(s).toString(); + + return s; + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java index 8d5d872375f..1037a2989f9 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 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 @@ -23,8 +23,8 @@ /** * @test -* @bug 8287835 -* @summary Test float/double to integral cast +* @bug 8287835 8364305 +* @summary Test vector float/double to integral cast * @modules jdk.incubator.vector * @requires vm.compiler2.enabled * @library /test/lib / @@ -87,7 +87,11 @@ public VectorFPtoIntCastTest() { @Test @IR(counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE_16, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void float2int() { var cvec = (IntVector)fvec512.convertShape(VectorOperators.F2I, ispec512, 0); cvec.intoArray(int_arr, 0); @@ -96,7 +100,7 @@ public void float2int() { public void checkf2int(int len) { for (int i = 0; i < len; i++) { - int expected = (int)float_arr[i]; + int expected = (int) float_arr[i]; if (int_arr[i] != expected) { throw new RuntimeException("Invalid result: int_arr[" + i + "] = " + int_arr[i] + " != " + expected); } @@ -105,7 +109,11 @@ public void checkf2int(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512dq", "true"}) + applyIfCPUFeatureOr = {"avx512dq", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void float2long() { var cvec = (LongVector)fvec512.convertShape(VectorOperators.F2L, lspec512, 0); cvec.intoArray(long_arr, 0); @@ -114,7 +122,7 @@ public void float2long() { public void checkf2long(int len) { for (int i = 0; i < len; i++) { - long expected = (long)float_arr[i]; + long expected = (long) float_arr[i]; if (long_arr[i] != expected) { throw new RuntimeException("Invalid result: long_arr[" + i + "] = " + long_arr[i] + " != " + expected); } @@ -123,7 +131,11 @@ public void checkf2long(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE_16, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void float2short() { var cvec = (ShortVector)fvec512.convertShape(VectorOperators.F2S, sspec256, 0); cvec.intoArray(short_arr, 0); @@ -132,7 +144,7 @@ public void float2short() { public void checkf2short(int len) { for (int i = 0; i < len; i++) { - short expected = (short)float_arr[i]; + short expected = (short) float_arr[i]; if (short_arr[i] != expected) { throw new RuntimeException("Invalid result: short_arr[" + i + "] = " + short_arr[i] + " != " + expected); } @@ -141,7 +153,11 @@ public void checkf2short(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_F2B, IRNode.VECTOR_SIZE_16, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void float2byte() { var cvec = (ByteVector)fvec512.convertShape(VectorOperators.F2B, bspec128, 0); cvec.intoArray(byte_arr, 0); @@ -150,7 +166,7 @@ public void float2byte() { public void checkf2byte(int len) { for (int i = 0; i < len; i++) { - byte expected = (byte)float_arr[i]; + byte expected = (byte) float_arr[i]; if (byte_arr[i] != expected) { throw new RuntimeException("Invalid result: byte_arr[" + i + "] = " + byte_arr[i] + " != " + expected); } @@ -159,7 +175,11 @@ public void checkf2byte(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void double2int() { var cvec = (IntVector)dvec512.convertShape(VectorOperators.D2I, ispec256, 0); cvec.intoArray(int_arr, 0); @@ -168,7 +188,7 @@ public void double2int() { public void checkd2int(int len) { for (int i = 0; i < len; i++) { - int expected = (int)double_arr[i]; + int expected = (int) double_arr[i]; if (int_arr[i] != expected) { throw new RuntimeException("Invalid result: int_arr[" + i + "] = " + int_arr[i] + " != " + expected); } @@ -177,7 +197,11 @@ public void checkd2int(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512dq", "true"}) + applyIfCPUFeatureOr = {"avx512dq", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void double2long() { var cvec = (LongVector)dvec512.convertShape(VectorOperators.D2L, lspec512, 0); cvec.intoArray(long_arr, 0); @@ -186,7 +210,7 @@ public void double2long() { public void checkd2long(int len) { for (int i = 0; i < len; i++) { - long expected = (long)double_arr[i]; + long expected = (long) double_arr[i]; if (long_arr[i] != expected) { throw new RuntimeException("Invalid result: long_arr[" + i + "] = " + long_arr[i] + " != " + expected); } @@ -195,7 +219,11 @@ public void checkd2long(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void double2short() { var cvec = (ShortVector)dvec512.convertShape(VectorOperators.D2S, sspec128, 0); cvec.intoArray(short_arr, 0); @@ -204,7 +232,7 @@ public void double2short() { public void checkd2short(int len) { for (int i = 0; i < len; i++) { - short expected = (short)double_arr[i]; + short expected = (short) double_arr[i]; if (short_arr[i] != expected) { throw new RuntimeException("Invalid result: short_arr[" + i + "] = " + short_arr[i] + " != " + expected); } @@ -213,7 +241,11 @@ public void checkd2short(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_D2B, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void double2byte() { var cvec = (ByteVector)dvec512.convertShape(VectorOperators.D2B, bspec64, 0); cvec.intoArray(byte_arr, 0); @@ -222,7 +254,7 @@ public void double2byte() { public void checkd2byte(int len) { for (int i = 0; i < len; i++) { - byte expected = (byte)double_arr[i]; + byte expected = (byte) double_arr[i]; if (byte_arr[i] != expected) { throw new RuntimeException("Invalid result: byte_arr[" + i + "] = " + byte_arr[i] + " != " + expected); } diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java index 851113ea4de..235093cceed 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java @@ -35,6 +35,7 @@ * @library /test/lib / * @summary test combining vector not operation with compare * @modules jdk.incubator.vector + * @requires (os.arch != "riscv64" | (os.arch == "riscv64" & vm.cpu.features ~= ".*rvv.*")) * * @run driver compiler.vectorapi.VectorMaskCompareNotTest */ diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java index 3fa636b42f7..4db973ff728 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java @@ -294,8 +294,12 @@ public double[] convertCharToDouble() { // ---------------- Convert F/D to I/L ---------------- @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}, - counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_float, max_int)", ">0"}) + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "avx10_2", "true", "rvv", "true"}, + counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_float, max_int)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public int[] convertFloatToInt() { int[] res = new int[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -305,8 +309,12 @@ public int[] convertFloatToInt() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"}, - counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", ">0"}) + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "avx10_2", "true", "rvv", "true"}, + counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public long[] convertFloatToLong() { long[] res = new long[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -316,8 +324,12 @@ public long[] convertFloatToLong() { } @Test - @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "rvv", "true"}, - counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE + "min(max_double, max_int)", ">0"}) + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true", "rvv", "true"}, + counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE + "min(max_double, max_int)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public int[] convertDoubleToInt() { int[] res = new int[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -327,8 +339,12 @@ public int[] convertDoubleToInt() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"}, - counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE + "min(max_double, max_long)", ">0"}) + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "avx10_2", "true", "rvv", "true"}, + counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE + "min(max_double, max_long)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public long[] convertDoubleToLong() { long[] res = new long[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -339,9 +355,15 @@ public long[] convertDoubleToLong() { // ---------------- Convert F/D to Subword-I ---------------- @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "avx10_2", "true", "rvv", "true"}, applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, - counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_short)", ">0"}) + counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_short)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, + applyIfCPUFeature = {"avx10_2", "true"}) public short[] convertFloatToShort() { short[] res = new short[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -358,9 +380,15 @@ public short[] convertFloatToShort() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "avx10_2", "true", "rvv", "true"}, applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, - counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_char)", ">0"}) + counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_char)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, + applyIfCPUFeature = {"avx10_2", "true"}) public char[] convertFloatToChar() { char[] res = new char[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -379,10 +407,16 @@ public char[] convertFloatToChar() { @Test @IR(applyIfCPUFeature = {"rvv", "true"}, applyIf = {"MaxVectorSize", ">=32"}, - counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", ">0"}) - @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true"}, + counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", "> 0"}) + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true"}, + applyIf = {"MaxVectorSize", ">=16"}, + counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, applyIf = {"MaxVectorSize", ">=16"}, - counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", ">0"}) + applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIf = {"MaxVectorSize", ">=16"}, + applyIfCPUFeature = {"avx10_2", "true"}) public short[] convertDoubleToShort() { short[] res = new short[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -393,11 +427,17 @@ public short[] convertDoubleToShort() { @Test @IR(applyIfCPUFeature = {"rvv", "true"}, - applyIf = {"MaxVectorSize", ">=32"}, - counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", ">0"}) - @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true"}, + applyIf = {"MaxVectorSize", ">= 32"}, + counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", "> 0"}) + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true"}, + applyIf = {"MaxVectorSize", ">= 16"}, + counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIf = {"MaxVectorSize", ">=16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, applyIf = {"MaxVectorSize", ">=16"}, - counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", ">0"}) + applyIfCPUFeature = {"avx10_2", "true"}) public char[] convertDoubleToChar() { char[] res = new char[SIZE]; for (int i = 0; i < SIZE; i++) { diff --git a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java index f87292be019..eb0f70af5c4 100644 --- a/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/test/hotspot/jtreg/compiler/whitebox/CompilerWhiteBoxTest.java @@ -221,15 +221,28 @@ protected final void checkNotCompiled() { * compilation level. */ protected final void checkNotCompiled(boolean isOsr) { - if (WHITE_BOX.isMethodQueuedForCompilation(method)) { - throw new RuntimeException(method + " must not be in queue"); + checkNotCompiled(method, isOsr); + } + + /** + * Checks, that the specified executable is not (OSR-)compiled. + * + * @param executable The method or constructor to check. + * @param isOsr Check for OSR compilation if true + * @throws RuntimeException if {@linkplain #method} is in compiler queue or + * is compiled, or if {@linkplain #method} has zero + * compilation level. + */ + protected static final void checkNotCompiled(Executable executable, boolean isOsr) { + if (WHITE_BOX.isMethodQueuedForCompilation(executable)) { + throw new RuntimeException(executable + " must not be in queue"); } - if (WHITE_BOX.isMethodCompiled(method, isOsr)) { - throw new RuntimeException(method + " must not be " + + if (WHITE_BOX.isMethodCompiled(executable, isOsr)) { + throw new RuntimeException(executable + " must not be " + (isOsr ? "osr_" : "") + "compiled"); } - if (WHITE_BOX.getMethodCompilationLevel(method, isOsr) != 0) { - throw new RuntimeException(method + (isOsr ? " osr_" : " ") + + if (WHITE_BOX.getMethodCompilationLevel(executable, isOsr) != 0) { + throw new RuntimeException(executable + (isOsr ? " osr_" : " ") + "comp_level must be == 0"); } } @@ -242,21 +255,34 @@ protected final void checkNotCompiled(boolean isOsr) { * has nonzero compilation level */ protected final void checkCompiled() { + checkCompiled(method, testCase.isOsr()); + } + + /** + * Checks, that the specified executable is compiled. + * + * @param executable The method or constructor to check. + * @param isOsr Check for OSR compilation if true + * @throws RuntimeException if {@linkplain #method} isn't in compiler queue + * and isn't compiled, or if {@linkplain #method} + * has nonzero compilation level + */ + protected static final void checkCompiled(Executable executable, boolean isOsr) { final long start = System.currentTimeMillis(); - waitBackgroundCompilation(); - if (WHITE_BOX.isMethodQueuedForCompilation(method)) { + waitBackgroundCompilation(executable); + if (WHITE_BOX.isMethodQueuedForCompilation(executable)) { System.err.printf("Warning: %s is still in queue after %dms%n", - method, System.currentTimeMillis() - start); + executable, System.currentTimeMillis() - start); return; } - if (!WHITE_BOX.isMethodCompiled(method, testCase.isOsr())) { - throw new RuntimeException(method + " must be " - + (testCase.isOsr() ? "osr_" : "") + "compiled"); + if (!WHITE_BOX.isMethodCompiled(executable, isOsr)) { + throw new RuntimeException(executable + " must be " + + (isOsr ? "osr_" : "") + "compiled"); } - if (WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr()) + if (WHITE_BOX.getMethodCompilationLevel(executable, isOsr) == 0) { - throw new RuntimeException(method - + (testCase.isOsr() ? " osr_" : " ") + throw new RuntimeException(executable + + (isOsr ? " osr_" : " ") + "comp_level must be != 0"); } } diff --git a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java new file mode 100644 index 00000000000..25314051fdd --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeRelocatedNMethod.java @@ -0,0 +1,157 @@ +/* + * 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. + * + */ + +/* + * @test id=Serial + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Serial + * @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 -Xbatch -XX:+SegmentedCodeCache -XX:+UseSerialGC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +/* + * @test id=Parallel + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Parallel + * @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 -Xbatch -XX:+SegmentedCodeCache -XX:+UseParallelGC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +/* + * @test id=G1 + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.G1 + * @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 -Xbatch -XX:+SegmentedCodeCache -XX:+UseG1GC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +/* + * @test id=Shenandoah + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Shenandoah + * @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 -Xbatch -XX:+SegmentedCodeCache -XX:+UseShenandoahGC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +/* + * @test id=ZGC + * @bug 8316694 + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Z + * @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 -Xbatch -XX:+SegmentedCodeCache -XX:+UseZGC + * -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.DeoptimizeRelocatedNMethod + */ + +package compiler.whitebox; + +import compiler.whitebox.CompilerWhiteBoxTest; +import java.lang.reflect.Method; +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.NMethod; + +public class DeoptimizeRelocatedNMethod { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + public static double FUNCTION_RESULT = 0; + + public static void main(String [] args) throws Exception { + // Get method that will be relocated + Method method = DeoptimizeRelocatedNMethod.class.getMethod("function"); + WHITE_BOX.testSetDontInlineMethod(method, true); + + // Verify not initially compiled + CompilerWhiteBoxTest.checkNotCompiled(method, false); + + // Call function enough to compile + callFunction(); + + // Verify now compiled + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get newly created nmethod + NMethod origNmethod = NMethod.get(method, false); + + // Relocate nmethod and mark old for cleanup + WHITE_BOX.relocateNMethodFromMethod(method, BlobType.MethodProfiled.id); + + // Trigger GC to clean up old nmethod + WHITE_BOX.fullGC(); + + // Verify function still compiled after old was cleaned up + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get new nmethod and verify it's actually new + NMethod newNmethod = NMethod.get(method, false); + if (origNmethod.entry_point == newNmethod.entry_point) { + throw new RuntimeException("Did not create new nmethod"); + } + + // Call to verify everything still works + function(); + + // Deoptimized method + WHITE_BOX.deoptimizeMethod(method); + + CompilerWhiteBoxTest.checkNotCompiled(method, false); + + // Call to verify everything still works + function(); + } + + // Call function multiple times to trigger compilation + private static void callFunction() { + for (int i = 0; i < CompilerWhiteBoxTest.THRESHOLD; i++) { + function(); + } + } + + public static void function() { + FUNCTION_RESULT = Math.random(); + } +} diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java new file mode 100644 index 00000000000..c18a8afa400 --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethod.java @@ -0,0 +1,146 @@ +/* + * 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. + * + */ + +/* + * @test id=Serial + * @bug 8316694 + * @summary test that nmethod::relocate() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Serial + * + * @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 -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseSerialGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod + */ + +/* + * @test id=Parallel + * @bug 8316694 + * @summary test that nmethod::relocate() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Parallel + * + * @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 -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseParallelGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod + */ + +/* + * @test id=G1 + * @bug 8316694 + * @summary test that nmethod::relocate() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.G1 + * + * @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 -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod + */ + +/* + * @test id=Shenandoah + * @bug 8316694 + * @summary test that nmethod::relocate() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Shenandoah + * + * @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 -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod + */ + +/* + * @test id=ZGC + * @bug 8316694 + * @summary test that nmethod::relocate() correctly creates a new nmethod + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @requires vm.opt.DeoptimizeALot != true + * @requires vm.gc.Z + * + * @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 -Xbatch -XX:+SegmentedCodeCache + * -XX:+UseZGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation compiler.whitebox.RelocateNMethod + */ + +package compiler.whitebox; + +import java.lang.reflect.Method; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.NMethod; +import jdk.test.whitebox.WhiteBox; + +import compiler.whitebox.CompilerWhiteBoxTest; + +public class RelocateNMethod extends CompilerWhiteBoxTest { + + public static void main(String[] args) throws Exception { + CompilerWhiteBoxTest.main(RelocateNMethod::new, new String[] {"CONSTRUCTOR_TEST", "METHOD_TEST", "STATIC_TEST"}); + } + + private RelocateNMethod(TestCase testCase) { + super(testCase); + // to prevent inlining of #method + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + @Override + protected void test() throws Exception { + checkNotCompiled(); + + compile(); + + checkCompiled(); + NMethod origNmethod = NMethod.get(method, false); + + WHITE_BOX.relocateNMethodFromMethod(method, BlobType.MethodProfiled.id); + + WHITE_BOX.fullGC(); + + checkCompiled(); + + NMethod newNmethod = NMethod.get(method, false); + if (origNmethod.entry_point == newNmethod.entry_point) { + throw new RuntimeException("Did not create new nmethod"); + } + } +} diff --git a/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java new file mode 100644 index 00000000000..49be3eff8c2 --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/RelocateNMethodMultiplePaths.java @@ -0,0 +1,261 @@ +/* + * 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. + * + */ + +/* + * @test id=SerialC1 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Serial + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @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 -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseSerialGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=SerialC2 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Serial + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @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 -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseSerialGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ParallelC1 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Parallel + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @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 -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseParallelGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ParallelC2 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Parallel + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @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 -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseParallelGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=G1C1 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.G1 + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @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 -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=G1C2 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.G1 + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @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 -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ShenandoahC1 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Shenandoah + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @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 -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ShenandoahC2 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Shenandoah + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @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 -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ZGCC1 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Z + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @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 -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseZGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +/* + * @test id=ZGCC2 + * @bug 8316694 + * @requires vm.debug == true + * @requires vm.gc.Z + * @summary test that relocated nmethod is correctly deoptimized + * @library /test/lib / + * @modules java.base/jdk.internal.misc java.management + * + * @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 -Xbatch -XX:+TieredCompilation + * -XX:+SegmentedCodeCache -XX:-DeoptimizeRandom -XX:+DeoptimizeALot -XX:+UseZGC -XX:+UnlockExperimentalVMOptions -XX:+NMethodRelocation + * compiler.whitebox.RelocateNMethodMultiplePaths + */ + +package compiler.whitebox; + +import compiler.whitebox.CompilerWhiteBoxTest; +import java.lang.reflect.Method; +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.NMethod; + +public class RelocateNMethodMultiplePaths { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + private static final int PATH_ONE_RESULT = 1; + private static final int PATH_TWO_RESULT = 2; + + public static void main(String [] args) throws Exception { + // Get method that will be relocated + Method method = RelocateNMethodMultiplePaths.class.getMethod("function", boolean.class); + WHITE_BOX.testSetDontInlineMethod(method, true); + + // Verify not initially compiled + CompilerWhiteBoxTest.checkNotCompiled(method, false); + + // Call function enough to compile + callFunction(true); + + // Verify now compiled + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get newly created nmethod + NMethod origNmethod = NMethod.get(method, false); + + // Relocate nmethod and mark old for cleanup + WHITE_BOX.relocateNMethodFromMethod(method, BlobType.MethodNonProfiled.id); + + // Trigger GC to clean up old nmethod + WHITE_BOX.fullGC(); + + // Verify function still compiled after old was cleaned up + CompilerWhiteBoxTest.checkCompiled(method, false); + + // Get new nmethod and verify it's actually new + NMethod newNmethod = NMethod.get(method, false); + if (origNmethod.entry_point == newNmethod.entry_point) { + throw new RuntimeException("Did not create new nmethod"); + } + + // Verify function still produces correct result + if (function(true) != PATH_ONE_RESULT) { + throw new RuntimeException("Relocated function produced incorrect result in path one"); + } + + // Call function again with different path and verify result + if (function(false) != PATH_TWO_RESULT) { + throw new RuntimeException("Relocated function produced incorrect result in path two"); + } + + // Verify function can be correctly deoptimized + WHITE_BOX.deoptimizeMethod(method); + CompilerWhiteBoxTest.checkNotCompiled(method, false); + } + + // Call function multiple times to trigger compilation + private static void callFunction(boolean pathOne) { + for (int i = 0; i < CompilerWhiteBoxTest.THRESHOLD; i++) { + function(pathOne); + } + } + + public static int function(boolean pathOne) { + if (pathOne) { + return PATH_ONE_RESULT; + } else { + return PATH_TWO_RESULT; + } + } +} diff --git a/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java new file mode 100644 index 00000000000..3b397f48306 --- /dev/null +++ b/test/hotspot/jtreg/compiler/whitebox/StressNMethodRelocation.java @@ -0,0 +1,239 @@ +/* + * 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. + * + */ + +/* + * @test StressNMethodRelocation + * @summary Call and relocate methods concurrently + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * java.management + * @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 + * -XX:+SegmentedCodeCache -XX:+UnlockExperimentalVMOptions + * -XX:+NMethodRelocation compiler.whitebox.StressNMethodRelocation + */ + +package compiler.whitebox; + +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.CodeBlob; +import jdk.test.whitebox.code.NMethod; + +import jdk.test.lib.compiler.InMemoryJavaCompiler; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Random; + +public class StressNMethodRelocation { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final int C2_LEVEL = 4; + private static final int ACTIVE_METHODS = 1024; + + private static TestMethod[] methods; + private static byte[] num1; + private static byte[] num2; + + private static long DURATION = 60_000; + + public static void main(String[] args) throws Exception { + // Initialize defaults + initNums(); + + // Generate compiled code + methods = new TestMethod[ACTIVE_METHODS]; + generateCode(methods); + + // Create thread that runs compiled methods + RunMethods runMethods = new RunMethods(); + Thread runMethodsThread = new Thread(runMethods); + + // Create thread that relocates compiled methods + RelocateNMethods relocate = new RelocateNMethods(); + Thread relocateThread = new Thread(relocate); + + // Start theads + runMethodsThread.start(); + relocateThread.start(); + + // Wait for threads to finish + runMethodsThread.join(); + relocateThread.join(); + } + + private static byte[] genNum(Random random, int digitCount) { + byte[] num = new byte[digitCount]; + int d; + do { + d = random.nextInt(10); + } while (d == 0); + + num[0] = (byte)d; + for (int i = 1; i < digitCount; ++i) { + num[i] = (byte)random.nextInt(10); + } + return num; + } + + private static void initNums() { + final long seed = 8374592837465123L; + Random random = new Random(seed); + + final int digitCount = 40; + num1 = genNum(random, digitCount); + num2 = genNum(random, digitCount); + } + + private static void generateCode(TestMethod[] m) throws Exception { + byte[] result = new byte[num1.length + 1]; + + for (int i = 0; i < ACTIVE_METHODS; ++i) { + m[i] = new TestMethod(); + m[i].profile(num1, num2, result); + m[i].compileWithC2(); + } + } + + private static final class TestMethod { + private static final String CLASS_NAME = "A"; + private static final String METHOD_TO_COMPILE = "sum"; + private static final String JAVA_CODE = """ + public class A { + + public static void sum(byte[] n1, byte[] n2, byte[] out) { + final int digitCount = n1.length; + int carry = 0; + for (int i = digitCount - 1; i >= 0; --i) { + int sum = n1[i] + n2[i] + carry; + out[i] = (byte)(sum % 10); + carry = sum / 10; + } + if (carry != 0) { + for (int i = digitCount; i > 0; --i) { + out[i] = out[i - 1]; + } + out[0] = (byte)carry; + } + } + }"""; + + private static final byte[] BYTE_CODE; + + static { + BYTE_CODE = InMemoryJavaCompiler.compile(CLASS_NAME, JAVA_CODE); + } + + private final Method method; + + private static ClassLoader createClassLoaderFor() { + return new ClassLoader() { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (!name.equals(CLASS_NAME)) { + return super.loadClass(name); + } + + return defineClass(name, BYTE_CODE, 0, BYTE_CODE.length); + } + }; + } + + public TestMethod() throws Exception { + var cl = createClassLoaderFor().loadClass(CLASS_NAME); + method = cl.getMethod(METHOD_TO_COMPILE, byte[].class, byte[].class, byte[].class); + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + public void profile(byte[] num1, byte[] num2, byte[] result) throws Exception { + method.invoke(null, num1, num2, result); + WHITE_BOX.markMethodProfiled(method); + } + + public void invoke(byte[] num1, byte[] num2, byte[] result) throws Exception { + method.invoke(null, num1, num2, result); + } + + public void compileWithC2() throws Exception { + WHITE_BOX.enqueueMethodForCompilation(method, C2_LEVEL); + while (WHITE_BOX.isMethodQueuedForCompilation(method)) { + Thread.onSpinWait(); + } + if (WHITE_BOX.getMethodCompilationLevel(method) != C2_LEVEL) { + throw new IllegalStateException("Method " + method + " is not compiled by C2."); + } + } + } + + private static final class RelocateNMethods implements Runnable { + public RelocateNMethods() {} + + // Move nmethod back and forth between NonProfiled and Profiled code heaps + public void run() { + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < DURATION) { + // Relocate NonProfiled to Profiled + CodeBlob[] nonProfiledBlobs = CodeBlob.getCodeBlobs(BlobType.MethodNonProfiled); + for (CodeBlob blob : nonProfiledBlobs) { + if (blob.isNMethod) { + WHITE_BOX.relocateNMethodFromAddr(blob.address, BlobType.MethodProfiled.id); + } + } + + // Relocate Profiled to NonProfiled + CodeBlob[] profiledBlobs = CodeBlob.getCodeBlobs(BlobType.MethodProfiled); + for (CodeBlob blob : nonProfiledBlobs) { + if (blob.isNMethod) { + WHITE_BOX.relocateNMethodFromAddr(blob.address, BlobType.MethodNonProfiled.id); + } + } + } + } + } + + private static final class RunMethods implements Runnable { + public RunMethods() {} + + public void run() { + try { + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < DURATION) { + callMethods(); + } + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + } + + private void callMethods() throws Exception { + for (var m : methods) { + byte[] result = new byte[num1.length + 1]; + m.invoke(num1, num2, result); + } + } + } + +} diff --git a/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryDataRunner.java b/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryDataRunner.java index 309ba722787..d478f811490 100644 --- a/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryDataRunner.java +++ b/test/hotspot/jtreg/gc/g1/TestShrinkAuxiliaryDataRunner.java @@ -29,6 +29,7 @@ * @bug 8038423 8061715 * @summary Checks that decommitment occurs for JVM with different ObjectAlignmentInBytes values * @requires vm.gc.G1 + * @requires !vm.opt.final.UseLargePages * @library /test/lib * @library / * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java b/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java index 80ab9e21667..1f19222fb8e 100644 --- a/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java +++ b/test/hotspot/jtreg/gc/stress/TestReclaimStringsLeaksMemory.java @@ -24,19 +24,60 @@ package gc.stress; /* - * @test TestReclaimStringsLeaksMemory + * @test id=Serial * @bug 8180048 - * @summary Ensure that during a Full GC interned string memory is reclaimed completely. - * @requires vm.gc == "null" + * @summary Ensure that during a Full GC interned string memory is reclaimed completely with SerialGC. + * @requires vm.gc.Serial * @requires !vm.debug * @library /test/lib * @modules java.base/jdk.internal.misc - * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseSerialGC + */ + +/* + * @test id=Parallel + * @bug 8180048 + * @summary Ensure that during a Full GC interned string memory is reclaimed completely with ParallelGC. + * @requires vm.gc.Parallel + * @requires !vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseParallelGC + */ + +/* + * @test id=G1 + * @bug 8180048 + * @summary Ensure that during a Full GC interned string memory is reclaimed completely with G1GC. + * @requires vm.gc.G1 + * @requires !vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseG1GC */ +/* + * @test id=Shenandoah + * @bug 8180048 + * @summary Ensure that during a Full GC interned string memory is reclaimed completely with ShenandoahGC. + * @requires vm.gc.Shenandoah + * @requires !vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseShenandoahGC + */ + +/* + * @test id=Z + * @bug 8180048 + * @summary Ensure that during a Full GC interned string memory is reclaimed completely with ZGC. + * @requires vm.gc.Z + * @requires !vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver/timeout=480 gc.stress.TestReclaimStringsLeaksMemory -XX:+UseZGC + */ + import java.util.Arrays; import java.util.ArrayList; import java.util.regex.Pattern; diff --git a/test/hotspot/jtreg/runtime/NMT/CommandLineDetail.java b/test/hotspot/jtreg/runtime/NMT/CommandLineDetail.java index 57f2302db30..a7561c7792e 100644 --- a/test/hotspot/jtreg/runtime/NMT/CommandLineDetail.java +++ b/test/hotspot/jtreg/runtime/NMT/CommandLineDetail.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,13 +35,14 @@ public class CommandLineDetail { - public static void main(String args[]) throws Exception { - - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:NativeMemoryTracking=detail", - "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("error"); - output.shouldHaveExitValue(0); - } + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-Xlog:nmt=warning", + "-XX:NativeMemoryTracking=detail", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("NMT initialization failed"); + output.shouldNotContain("Could not create the Java Virtual Machine."); + output.shouldHaveExitValue(0); + } } diff --git a/test/hotspot/jtreg/runtime/NMT/CommandLineSummary.java b/test/hotspot/jtreg/runtime/NMT/CommandLineSummary.java index 02b37a40ef4..381fe3eba34 100644 --- a/test/hotspot/jtreg/runtime/NMT/CommandLineSummary.java +++ b/test/hotspot/jtreg/runtime/NMT/CommandLineSummary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,13 +35,14 @@ public class CommandLineSummary { - public static void main(String args[]) throws Exception { - - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:NativeMemoryTracking=summary", - "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("error"); - output.shouldHaveExitValue(0); - } + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-Xlog:nmt=warning", + "-XX:NativeMemoryTracking=summary", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("NMT initialization failed"); + output.shouldNotContain("Could not create the Java Virtual Machine."); + output.shouldHaveExitValue(0); + } } diff --git a/test/hotspot/jtreg/runtime/NMT/MallocLimitTest.java b/test/hotspot/jtreg/runtime/NMT/MallocLimitTest.java index a58ff861a29..8b711304a99 100644 --- a/test/hotspot/jtreg/runtime/NMT/MallocLimitTest.java +++ b/test/hotspot/jtreg/runtime/NMT/MallocLimitTest.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022 SAP SE. All rights reserved. - * 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 @@ -47,7 +47,7 @@ * @requires vm.flagless * @modules java.base/jdk.internal.misc * @library /test/lib - * @run driver MallocLimitTest compiler-limit-fatal + * @run driver/timeout=480 MallocLimitTest compiler-limit-fatal */ /* diff --git a/test/hotspot/jtreg/runtime/cds/appcds/SignedJar.java b/test/hotspot/jtreg/runtime/cds/appcds/SignedJar.java index 1ad28f99408..9e6cb58bb7f 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/SignedJar.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/SignedJar.java @@ -50,8 +50,8 @@ public static void main(String[] args) throws Exception { String skipMsg = "Skipping Hello: Signed JAR"; String lambdaInArchive = "klasses.*=.*app.*Hello[$][$]Lambda.*hidden"; - String loadFromJar = ".class,load. Hello source: file:.*signed_hello.jar"; - String lambdaLoadFromHello = ".class.load. Hello[$][$]Lambda.*/0x.*source.*Hello"; + String loadFromJar = ".class,load\s*. Hello source: file:.*signed_hello.jar"; + String lambdaLoadFromHello = ".class.load\s*. Hello[$][$]Lambda.*/0x.*source.*Hello"; for (String mainArg : mainArgs) { output = TestCommon.dump(signedJar, TestCommon.list(mainClass), diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JavaAgent.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JavaAgent.java index 491a5bf1fa7..758d252f18d 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JavaAgent.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JavaAgent.java @@ -38,6 +38,7 @@ * @test id=dynamic * @bug 8362561 * @summary -javaagent is not allowed when creating dynamic CDS archive + * @requires vm.cds.supports.aot.class.linking * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes * @build JavaAgent JavaAgentTransformer Util * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar JavaAgentApp JavaAgentApp$ShouldBeTransformed diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java index 42161b469bf..732ef4f2810 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java @@ -65,6 +65,7 @@ public String classpath(RunMode runMode) { @Override public String[] vmArgs(RunMode runMode) { return new String[] { + "-Xlog:aot", "-Xlog:aot+class=debug", "-Xlog:aot+resolve=trace", }; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/VerifierFailOver.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/VerifierFailOver.java index 50b47e4424d..8107e3fe0a3 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/VerifierFailOver.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/VerifierFailOver.java @@ -39,7 +39,7 @@ public class VerifierFailOver { public static void main(String... args) throws Exception { SimpleCDSAppTester.of("VerifierFailOver") - .addVmArgs("-Xlog:aot+class=debug") + .addVmArgs("-Xlog:aot,aot+class=debug") .classpath("app.jar") .appCommandLine("VerifierFailOverApp") .setTrainingChecker((OutputAnalyzer out) -> { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java index 9e43d00e872..482f8fb4ad0 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java @@ -118,7 +118,7 @@ public String classpath(RunMode runMode) { @Override public String[] vmArgs(RunMode runMode) { return new String[] { - "-Xlog:cds,aot+load,cds+class=debug,aot+class=debug", + "-Xlog:cds,aot,aot+load,cds+class=debug,aot+class=debug", "-XX:+AOTClassLinking", }; } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/UnloadUnregisteredLoaderTest.java b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/UnloadUnregisteredLoaderTest.java index b7f472f5c0e..db26c6cbd18 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/UnloadUnregisteredLoaderTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/UnloadUnregisteredLoaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, 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 @@ -29,9 +29,10 @@ * @requires vm.cds * @requires vm.cds.custom.loaders * @requires vm.opt.final.ClassUnloading - * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes * @build jdk.test.whitebox.WhiteBox jdk.test.lib.classloader.ClassUnloadCommon * @compile test-classes/UnloadUnregisteredLoader.java test-classes/CustomLoadee.java + * test-classes/CustomLoadee5.java test-classes/CustomLoadee5Child.java * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * jdk.test.lib.classloader.ClassUnloadCommon * jdk.test.lib.classloader.ClassUnloadCommon$1 @@ -49,12 +50,19 @@ public class UnloadUnregisteredLoaderTest { CDSOptions.disableRuntimePrefixForEpsilonGC(); } public static void main(String[] args) throws Exception { - String appJar1 = JarBuilder.build("UnloadUnregisteredLoader_app1", "UnloadUnregisteredLoader"); + String appJar1 = JarBuilder.build("UnloadUnregisteredLoader_app1", + "UnloadUnregisteredLoader", + "UnloadUnregisteredLoader$CustomLoader", + "CustomLoadee5", + "Util"); String appJar2 = JarBuilder.build(true, "UnloadUnregisteredLoader_app2", "jdk/test/lib/classloader/ClassUnloadCommon", "jdk/test/lib/classloader/ClassUnloadCommon$1", "jdk/test/lib/classloader/ClassUnloadCommon$TestFailure"); - String customJarPath = JarBuilder.build("UnloadUnregisteredLoader_custom", "CustomLoadee"); + String customJarPath = JarBuilder.build("UnloadUnregisteredLoader_custom", + "CustomLoadee", + "CustomLoadee5", + "CustomLoadee5Child"); String wbJar = JarBuilder.build(true, "WhiteBox", "jdk/test/whitebox/WhiteBox"); String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar; @@ -66,6 +74,8 @@ public static void main(String[] args) throws Exception { "jdk/test/lib/classloader/ClassUnloadCommon$TestFailure", "java/lang/Object id: 1", "CustomLoadee id: 2 super: 1 source: " + customJarPath, + "CustomLoadee5 id: 3 super: 1 source: " + customJarPath, + "CustomLoadee5Child id: 4 super: 3 source: " + customJarPath, }; OutputAnalyzer output; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/CustomLoadee5.java b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/CustomLoadee5.java index f3cda51c9fa..ba9f6dafa95 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/CustomLoadee5.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/CustomLoadee5.java @@ -21,7 +21,7 @@ * questions. */ -class CustomLoadee5 { +public class CustomLoadee5 { public String toString() { return "this is CustomLoadee5"; } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/UnloadUnregisteredLoader.java b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/UnloadUnregisteredLoader.java index 0e0e814327e..e6bd7407466 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/UnloadUnregisteredLoader.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes/UnloadUnregisteredLoader.java @@ -23,6 +23,7 @@ */ import java.io.File; +import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; import jdk.test.whitebox.WhiteBox; @@ -46,9 +47,11 @@ public static void main(String args[]) throws Exception { } } - public static void doit(URL urls[], String className, boolean isFirstTime) throws Exception { + public static void doit(URL urls[], String className, boolean isFirstTime) throws Exception { ClassLoader appLoader = UnloadUnregisteredLoader.class.getClassLoader(); - URLClassLoader custLoader = new URLClassLoader(urls, appLoader); + CustomLoader custLoader = new CustomLoader(urls, appLoader); + + // Part 1 -- load CustomLoadee. It should be loaded from archive when isFirstTime==true Class klass = custLoader.loadClass(className); WhiteBox wb = WhiteBox.getWhiteBox(); @@ -68,5 +71,43 @@ public static void doit(URL urls[], String className, boolean isFirstTime) throw } } } + + // Part 2 + // + // CustomLoadee5 is never loaded from the archive, because the classfile bytes don't match + // CustomLoadee5Child is never loaded from the archive, its super is not loaded from the archive + try (InputStream in = appLoader.getResourceAsStream("CustomLoadee5.class")) { + byte[] b = in.readAllBytes(); + Util.replace(b, "this is", "DAS IST"); // Modify the bytecodes + Class c = custLoader.myDefineClass(b, 0, b.length); + System.out.println(c.newInstance()); + if (!"DAS IST CustomLoadee5".equals(c.newInstance().toString())) { + throw new RuntimeException("Bytecode modification not successful"); + } + if (wb.isSharedClass(c)) { + throw new RuntimeException(c + "should not be loaded from CDS"); + } + } + + // When isFirstTime==true, the VM will try to load the archived copy of CustomLoadee5Child, + // but it will fail (because CustomLoadee5 was not loaded from the archive) and will recover + // by decoding the class from its classfile data. + // This failure should not leave the JVM in an inconsistent state. + Class child = custLoader.loadClass("CustomLoadee5Child"); + if (wb.isSharedClass(child)) { + throw new RuntimeException(child + "should not be loaded from CDS"); + } + } + + static class CustomLoader extends URLClassLoader { + public CustomLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + public Class myDefineClass(byte[] b, int off, int len) + throws ClassFormatError + { + return super.defineClass(b, off, len); + } } } diff --git a/test/hotspot/jtreg/serviceability/jvmti/GetThreadListStackTraces/OneGetThreadListStackTraces.java b/test/hotspot/jtreg/serviceability/jvmti/GetThreadListStackTraces/OneGetThreadListStackTraces.java index 349824af9ff..20012b70186 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/GetThreadListStackTraces/OneGetThreadListStackTraces.java +++ b/test/hotspot/jtreg/serviceability/jvmti/GetThreadListStackTraces/OneGetThreadListStackTraces.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. * Copyright (c) 2020, NTT DATA. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,6 +27,7 @@ * @bug 8242428 * @summary Verifies JVMTI GetThreadListStackTraces API with thread_count = 1 * @requires vm.jvmti + * @requires test.thread.factory == null * @library /test/lib * @run main/othervm/native -agentlib:OneGetThreadListStackTraces OneGetThreadListStackTraces * diff --git a/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java new file mode 100644 index 00000000000..b12e2c3455c --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java @@ -0,0 +1,178 @@ +/* + * 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. + */ + +/* + * @test + * + * @bug 8316694 + * @summary Verify that nmethod relocation posts the correct JVMTI events + * @requires vm.jvmti + * @library /test/lib /test/hotspot/jtreg + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm/native NMethodRelocationTest + */ + +import static compiler.whitebox.CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION; + +import java.lang.reflect.Executable; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.NMethod; + + +public class NMethodRelocationTest { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-agentlib:NMethodRelocationTest", + "--enable-native-access=ALL-UNNAMED", + "-Xbootclasspath/a:.", + "-XX:+UseSerialGC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:+SegmentedCodeCache", + "-XX:-TieredCompilation", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+NMethodRelocation", + "DoWork"); + + OutputAnalyzer oa = new OutputAnalyzer(pb.start()); + String output = oa.getOutput(); + if (oa.getExitValue() != 0) { + System.err.println(oa.getOutput()); + throw new RuntimeException("Non-zero exit code returned from the test"); + } + Asserts.assertTrue(oa.getExitValue() == 0); + + Pattern pattern = Pattern.compile("(?m)^Relocated nmethod from (0x[0-9a-f]{16}) to (0x[0-9a-f]{16})$"); + Matcher matcher = pattern.matcher(output); + + if (matcher.find()) { + String fromAddr = matcher.group(1); + String toAddr = matcher.group(2); + + // Confirm events sent for both original and relocated nmethod + oa.shouldContain(": name: compiledMethod, code: " + fromAddr); + oa.shouldContain(": name: compiledMethod, code: " + toAddr); + oa.shouldContain(": name: compiledMethod, code: " + fromAddr); + oa.shouldContain(": name: compiledMethod, code: " + toAddr); + } else { + System.err.println(oa.getOutput()); + throw new RuntimeException("Unable to find relocation information"); + } + } +} + +class DoWork { + + protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + /** Load native library if required. */ + static { + try { + System.loadLibrary("NMethodRelocationTest"); + } catch (UnsatisfiedLinkError ule) { + System.err.println("Could not load NMethodRelocationTest library"); + System.err.println("java.library.path: " + + System.getProperty("java.library.path")); + throw ule; + } + } + + /** + * Returns value of VM option. + * + * @param name option's name + * @return value of option or {@code null}, if option doesn't exist + * @throws NullPointerException if name is null + */ + protected static String getVMOption(String name) { + Objects.requireNonNull(name); + return Objects.toString(WHITE_BOX.getVMFlag(name), null); + } + + /** + * Returns value of VM option or default value. + * + * @param name option's name + * @param defaultValue default value + * @return value of option or {@code defaultValue}, if option doesn't exist + * @throws NullPointerException if name is null + * @see #getVMOption(String) + */ + protected static String getVMOption(String name, String defaultValue) { + String result = getVMOption(name); + return result == null ? defaultValue : result; + } + + public static void main(String argv[]) throws Exception { + run(); + } + + public static void run() throws Exception { + Executable method = DoWork.class.getDeclaredMethod("compiledMethod"); + WHITE_BOX.testSetDontInlineMethod(method, true); + + WHITE_BOX.enqueueMethodForCompilation(method, COMP_LEVEL_FULL_OPTIMIZATION); + while (WHITE_BOX.isMethodQueuedForCompilation(method)) { + Thread.onSpinWait(); + } + + NMethod originalNMethod = NMethod.get(method, false); + if (originalNMethod == null) { + throw new AssertionError("Could not find original nmethod"); + } + + WHITE_BOX.relocateNMethodFromMethod(method, BlobType.MethodNonProfiled.id); + + NMethod relocatedNMethod = NMethod.get(method, false); + if (relocatedNMethod == null) { + throw new AssertionError("Could not find relocated nmethod"); + } + + if (originalNMethod.address == relocatedNMethod.address) { + throw new AssertionError("Relocated nmethod same as original"); + } + + WHITE_BOX.deoptimizeAll(); + + WHITE_BOX.fullGC(); + WHITE_BOX.fullGC(); + + WHITE_BOX.lockCompilation(); + + System.out.printf("Relocated nmethod from 0x%016x to 0x%016x%n", originalNMethod.code_begin, relocatedNMethod.code_begin); + System.out.flush(); + } + + public static long compiledMethod() { + return 0; + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/libNMethodRelocationTest.cpp b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/libNMethodRelocationTest.cpp new file mode 100644 index 00000000000..41ba6b10608 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/NMethodRelocation/libNMethodRelocationTest.cpp @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +/** + * Callback for COMPILED_METHOD_LOAD event. + */ +JNIEXPORT void JNICALL +callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, + jint code_size, const void* code_addr, + jint map_length, const jvmtiAddrLocationMap* map, + const void* compile_info) { + char* name = nullptr; + char* sig = nullptr; + + if (jvmti->GetMethodName(method, &name, &sig, nullptr) != JVMTI_ERROR_NONE) { + printf(" [Could not retrieve method name]\n"); + fflush(stdout); + return; + } + + printf(": name: %s, code: 0x%016" PRIxPTR "\n", + name, (uintptr_t)code_addr); + fflush(stdout); +} + +/** + * Callback for COMPILED_METHOD_UNLOAD event. + */ +JNIEXPORT void JNICALL +callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method, + const void* code_addr) { + char* name = nullptr; + char* sig = nullptr; + + if (jvmti->GetMethodName(method, &name, &sig, nullptr) != JVMTI_ERROR_NONE) { + printf(" [Could not retrieve method name]\n"); + fflush(stdout); + return; + } + printf(": name: %s, code: 0x%016" PRIxPTR "\n", + name, (uintptr_t)code_addr); + fflush(stdout); +} + +JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + jvmtiEnv* jvmti = nullptr; + jvmtiError error; + + if (jvm->GetEnv((void **)&jvmti, JVMTI_VERSION_1_0) != JNI_OK) { + printf("Unable to access JVMTI!\n"); + return JNI_ERR; + } + + // Add required capabilities + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); + caps.can_generate_compiled_method_load_events = 1; + error = jvmti->AddCapabilities(&caps); + if (error != JVMTI_ERROR_NONE) { + printf("ERROR: Unable to add capabilities, error=%d\n", error); + return JNI_ERR; + } + + // Set event callbacks + jvmtiEventCallbacks eventCallbacks; + memset(&eventCallbacks, 0, sizeof(eventCallbacks)); + eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad; + eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload; + error = jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks)); + if (error != JVMTI_ERROR_NONE) { + printf("ERROR: Unable to set event callbacks, error=%d\n", error); + return JNI_ERR; + } + + // Enable events + error = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, nullptr); + if (error != JVMTI_ERROR_NONE) { + printf("ERROR: Unable to enable COMPILED_METHOD_LOAD event, error=%d\n", error); + return JNI_ERR; + } + + error = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, nullptr); + if (error != JVMTI_ERROR_NONE) { + printf("ERROR: Unable to enable COMPILED_METHOD_UNLOAD event, error=%d\n", error); + return JNI_ERR; + } + + return JNI_OK; +} diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/AllocateWithoutOomTest/AllocateWithoutOomTest.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/AllocateWithoutOomTest/AllocateWithoutOomTest.java index 51307bb996c..a1bd7acedeb 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/AllocateWithoutOomTest/AllocateWithoutOomTest.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/AllocateWithoutOomTest/AllocateWithoutOomTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, 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 @@ -37,7 +37,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * gc.gctests.AllocateWithoutOomTest.AllocateWithoutOomTest */ diff --git a/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java index 68fe6779e99..252e3a2d40f 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/vector/CircularListLow/TestDescription.java @@ -31,5 +31,6 @@ * * @library /vmTestbase * /test/lib + * @requires vm.gc != "Serial" * @run main/othervm/timeout=480 gc.vector.SimpleGC.SimpleGC -ms low -gp circularList(low) */ diff --git a/test/hotspot/jtreg/vmTestbase/gc/vector/LinearListLow/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/vector/LinearListLow/TestDescription.java index 8ae86af035d..bd094045abf 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/vector/LinearListLow/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/vector/LinearListLow/TestDescription.java @@ -31,5 +31,6 @@ * * @library /vmTestbase * /test/lib + * @requires vm.gc != "Serial" * @run main/othervm gc.vector.SimpleGC.SimpleGC -ms low -gp linearList(low) */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM04/em04t001/em04t001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM04/em04t001/em04t001.cpp index a7244db3441..a8d16a1ecae 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM04/em04t001/em04t001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM04/em04t001/em04t001.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, 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 @@ -118,6 +118,13 @@ cbDynamicCodeGenerated2(jvmtiEnv *jvmti_env, const char *name, } +void JNICALL +cbVMDeath(jvmtiEnv* jvmti, JNIEnv* jni) { + if (!NSK_JVMTI_VERIFY(jvmti->DestroyRawMonitor(syncLock))) { + nsk_jvmti_setFailStatus(); + } +} + /* ============================================================================= */ static int @@ -138,6 +145,7 @@ int setCallBacks(int stage) { eventCallbacks.DynamicCodeGenerated = (stage == 1) ? cbDynamicCodeGenerated1 : cbDynamicCodeGenerated2; + eventCallbacks.VMDeath = &cbVMDeath; if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks)))) return NSK_FALSE; @@ -256,9 +264,6 @@ Agent_OnUnload(JavaVM *jvm) nsk_jvmti_setFailStatus(); } - if (!NSK_JVMTI_VERIFY(jvmti->DestroyRawMonitor(syncLock))) { - nsk_jvmti_setFailStatus(); - } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java index 706b3550dcc..90a6edebd38 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.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 @@ -345,12 +345,10 @@ public boolean eventReceived(Event event) { public boolean eventReceived(Event event) { if (event instanceof VMDisconnectEvent) { display("receieved VMDisconnect"); - synchronized(EventHandler.this) { - vmDisconnected = true; - status = 0; // OK finish - EventHandler.this.notifyAll(); - removeListener(this); - } + vmDisconnected = true; + status = 0; // OK finish + EventHandler.this.notifyAll(); + removeListener(this); return true; } return false; @@ -431,6 +429,10 @@ public void eventSetReceived(EventSet set) { } public boolean eventReceived(Event event) { + if (en.event != null) { + // If we already got the requested event, don't handle this one. + return false; + } EventSet set = en.set; en.set = null; // We'll reset it below if the event matches a request. for (int i = 0; i < requests.length; i++) { @@ -441,11 +443,9 @@ public boolean eventReceived(Event event) { if (request.equals(event.request())) { display("waitForRequestedEventCommon: Received event(" + event + ") for request(" + request + ")"); - synchronized (EventHandler.this) { - en.event = event; - en.set = set; - EventHandler.this.notifyAll(); - } + en.event = event; + en.set = set; + EventHandler.this.notifyAll(); return true; // event was handled } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java index aa40fd36fe5..78cfb9e8bba 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java @@ -204,11 +204,9 @@ private void setCommunicationBreakpoint(ReferenceType refType, String methodName new EventHandler.EventListener() { public boolean eventReceived(Event event) { if (event instanceof BreakpointEvent && bpRequest.equals(event.request())) { - synchronized(eventHandler) { - display("Received communication breakpoint event."); - bpCount++; - eventHandler.notifyAll(); - } + display("Received communication breakpoint event."); + bpCount++; + eventHandler.notifyAll(); return true; } return false; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java index 0401fea13fc..39e7e2c2237 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/runner/ThreadsRunner.java @@ -310,6 +310,10 @@ public void run() { log.info("Unexpected exception during the run."); log.info(t); successful = false; + } finally { + // Finished testing; release memory to avoid OOM. + runnables.clear(); + threads.clear(); } } diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_InternedStrings_Strings/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_InternedStrings_Strings/TestDescription.java index 4e11e51a894..ad7db17e412 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_InternedStrings_Strings/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_InternedStrings_Strings/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 @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp interned(randomString) diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree/TestDescription.java index b058bb2c84d..be4f9f673b7 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree/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 @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp nonbranchyTree(high) diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_ArrayOf/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_ArrayOf/TestDescription.java index 3beeaa76a84..2ca21ae2ee6 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_ArrayOf/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_ArrayOf/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 @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp nonbranchyTree(high) diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_TwoFields/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_TwoFields/TestDescription.java index c1421263a48..01dc687251b 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_TwoFields/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_TwoFields/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 @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp nonbranchyTree(high) diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings/TestDescription.java index 207822c666b..9ba96b7e493 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings/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 @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp randomString diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_InternedStrings/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_InternedStrings/TestDescription.java index 705e47ea68b..30dcfc7502e 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_InternedStrings/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_InternedStrings/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 @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp randomString diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_TwoFields/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_TwoFields/TestDescription.java index 7d5ddc36fcb..8a62d4b07eb 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_TwoFields/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_TwoFields/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 @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp randomString diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_NonbranchyTree/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_NonbranchyTree/TestDescription.java index 38c5b1e6bab..c9c117f0b0e 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_NonbranchyTree/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_NonbranchyTree/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 @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp nonbranchyTree(high) diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_Strings/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_Strings/TestDescription.java index 88d11739141..7d4b6ae3a21 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_Strings/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_Strings/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 @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp randomString diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/stepBreakPopReturn/stepBreakPopReturn.cpp b/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/stepBreakPopReturn/stepBreakPopReturn.cpp index 413450892a5..0f7d1826937 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/stepBreakPopReturn/stepBreakPopReturn.cpp +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/indy/func/jvmti/stepBreakPopReturn/stepBreakPopReturn.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, 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 @@ -89,7 +89,7 @@ MethodEntry(jvmtiEnv *jvmti_env, gIsMethodEntryWorking = JNI_TRUE; if (!gIsBreakpointSet) - NSK_JVMTI_VERIFY(jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, nullptr)); + NSK_JVMTI_VERIFY(jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, thread)); } } @@ -116,7 +116,7 @@ SingleStep(jvmtiEnv *jvmti_env, free(locStr); } - NSK_JVMTI_VERIFY(gJvmtiEnv->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, nullptr)); + NSK_JVMTI_VERIFY(gJvmtiEnv->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, thread)); if (!gIsDebuggerCompatible) { if (!NSK_JVMTI_VERIFY(jvmti_env->SetBreakpoint(method, location))) diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/jni/nativeAndMH/Test.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/jni/nativeAndMH/Test.java index c8264e8f963..abb771e30e7 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/jni/nativeAndMH/Test.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/jni/nativeAndMH/Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, 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 @@ -33,6 +33,7 @@ * another method handle and so on. * The test verifies that arguments are correctly passed between native methods and MHs. * + * @requires vm.compMode != "Xcomp" * @library /vmTestbase * /test/lib * @@ -62,26 +63,32 @@ public class Test extends MultiThreadedTest { private static final String RETURN_VALUE = "test"; + private static final MethodType MT_calledFromNative = MethodType.methodType( + Object.class, + Object.class, Object.class, int.class, long.class, double.class, float.class); + + private static MethodHandle mh; + static { System.loadLibrary("nativeAndMH"); + try { + mh = MethodHandles.lookup().findStatic( + Test.class, + "calledFromNative", + MT_calledFromNative); + } catch (Exception ex) { + throw new RuntimeException("TEST FAILED - Unable to lookup \"calledFromNative\""); + } } private static native Object native01(Object a1, String a2, Object a3, Object a4, Object a5, Object a6, MethodHandle mh); - private static final MethodType MT_calledFromNative = MethodType.methodType( - Object.class, - Object.class, Object.class, int.class, long.class, double.class, float.class); - private static Object calledFromNative(Object s1, Object s2, int i, long l, double d, float f) { return RETURN_VALUE; } @Override protected boolean runThread(int threadNum) throws Throwable { - MethodHandle mh = MethodHandles.lookup().findStatic( - Test.class, - "calledFromNative", - MT_calledFromNative); Stresser stresser = createStresser(); stresser.start(1); diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java index 66ddad86785..9a19c0237d7 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.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,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import javax.xml.catalog.Catalog; import javax.xml.catalog.CatalogException; @@ -49,6 +51,9 @@ import static java.nio.file.StandardOpenOption.CREATE; import static jaxp.library.JAXPTestUtilities.getSystemProperty; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; +import jdk.test.lib.net.URIBuilder; import jdk.test.lib.util.JarUtils; import org.testng.Assert; import org.testng.annotations.AfterClass; @@ -56,13 +61,11 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.xml.sax.InputSource; -import jdk.test.lib.net.SimpleHttpServer; /* * @test * @bug 8151154 8171243 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest /test/lib - * @build jdk.test.lib.net.SimpleHttpServer * @run testng/othervm catalog.CatalogFileInputTest * @summary Verifies that the Catalog API accepts valid URIs only; * Verifies that the CatalogFeatures' builder throws @@ -81,9 +84,9 @@ public class CatalogFileInputTest extends CatalogSupportBase { final static String SCHEME_JARFILE = "jar:"; static final String REMOTE_FILE_LOCATION = "/jar/META-INF"; static final String DOCROOT = SRC_DIR; - static final String TESTCONTEXT = REMOTE_FILE_LOCATION; //mapped to local file path - private SimpleHttpServer httpserver; + private HttpServer httpserver; private String remoteFilePath; + private ExecutorService executor; /* * Initializing fields @@ -92,15 +95,23 @@ public class CatalogFileInputTest extends CatalogSupportBase { public void setUpClass() throws Exception { super.setUp(); // set up HttpServer - httpserver = new SimpleHttpServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), TESTCONTEXT, DOCROOT); + httpserver = SimpleFileServer.createFileServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), + Path.of(DOCROOT), SimpleFileServer.OutputLevel.INFO); + executor = Executors.newCachedThreadPool(); + httpserver.setExecutor(executor); httpserver.start(); - remoteFilePath = httpserver.getAddress() + REMOTE_FILE_LOCATION; + remoteFilePath = URIBuilder.newBuilder() + .scheme("http") + .host(httpserver.getAddress().getAddress()) + .port(httpserver.getAddress().getPort()) + .build().toString() + REMOTE_FILE_LOCATION; } @AfterClass protected void tearDown() { if (httpserver != null) { - httpserver.stop(); + httpserver.stop(0); + executor.shutdown(); } } diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 381c0c8b0be..4799eb3bc0f 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -188,7 +188,6 @@ java/awt/Mixing/AWT_Mixing/JTextFieldOverlapping.java 8158801 windows-all java/awt/Mixing/AWT_Mixing/JToggleButtonInGlassPaneOverlapping.java 8158801 windows-all java/awt/Mixing/AWT_Mixing/JToggleButtonOverlapping.java 8158801 windows-all java/awt/Mixing/NonOpaqueInternalFrame.java 7124549 macosx-all -java/awt/Mouse/EnterExitEvents/DragWindowTest.java 8298823 macosx-all java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowRetaining.java 6829264 generic-all java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java 8080982 generic-all java/awt/datatransfer/SystemFlavorMap/AddFlavorTest.java 8079268 linux-all @@ -249,6 +248,7 @@ sun/awt/datatransfer/SuplementaryCharactersTransferTest.java 8011371 generic-all sun/awt/shell/ShellFolderMemoryLeak.java 8197794 windows-all sun/java2d/DirectX/OverriddenInsetsTest/OverriddenInsetsTest.java 8196102 generic-all sun/java2d/DirectX/RenderingToCachedGraphicsTest/RenderingToCachedGraphicsTest.java 8196180 windows-all,macosx-all +sun/java2d/OpenGL/OpaqueDest.java#id1 8367574 macosx-all sun/java2d/SunGraphics2D/EmptyClipRenderingTest.java 8144029 macosx-all,linux-all sun/java2d/SunGraphics2D/DrawImageBilinear.java 8297175 linux-all sun/java2d/SunGraphics2D/PolyVertTest.java 6986565 generic-all @@ -487,7 +487,6 @@ java/awt/Graphics2D/DrawString/RotTransText.java 8316878 linux-all java/awt/KeyboardFocusmanager/TypeAhead/ButtonActionKeyTest/ButtonActionKeyTest.java 8257529 windows-x64 java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeForModalDialogTest/ConsumeForModalDialogTest.java 8302787 windows-all java/awt/KeyboardFocusmanager/TypeAhead/MenuItemActivatedTest/MenuItemActivatedTest.java 8302787 windows-all -java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemonicKeyTypedTest.java 8321303 linux-all java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java 8266243 macosx-aarch64 java/awt/Dialog/ChoiceModalDialogTest.java 8161475 macosx-all @@ -548,8 +547,6 @@ java/lang/IO/IO.java 8337935 linux-pp # jdk_management -com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java 8030957 aix-all -com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java 8030957 aix-all java/lang/management/MemoryMXBean/Pending.java 8158837 generic-all java/lang/management/ThreadMXBean/ThreadMXBeanStateTest.java 8247426 generic-all @@ -563,7 +560,6 @@ sun/management/jdp/JdpOffTest.java 8308807 aix-ppc6 # jdk_jmx -javax/management/MBeanServer/OldMBeanServerTest.java 8030957 aix-all javax/management/remote/mandatory/connection/BrokenConnectionTest.java 8262312 linux-all @@ -610,7 +606,6 @@ java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java 7146541 linux-al java/rmi/registry/readTest/CodebaseTest.java 8173324 windows-all java/rmi/registry/multipleRegistries/MultipleRegistries.java 8268182 macosx-all -java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java 8365398 generic-all java/rmi/Naming/DefaultRegistryPort.java 8005619 windows-all java/rmi/Naming/legalRegistryNames/LegalRegistryNames.java 8005619 windows-all diff --git a/test/jdk/com/sun/crypto/provider/Cipher/ChaCha20/unittest/ChaCha20CipherUnitTest.java b/test/jdk/com/sun/crypto/provider/Cipher/ChaCha20/unittest/ChaCha20CipherUnitTest.java index 5216f48d5c3..7d5477bef3f 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/ChaCha20/unittest/ChaCha20CipherUnitTest.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/ChaCha20/unittest/ChaCha20CipherUnitTest.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,7 +23,7 @@ /* * @test - * @bug 8153029 + * @bug 8153029 8360463 8368984 * @library /test/lib * @run main ChaCha20CipherUnitTest * @summary Unit test for com.sun.crypto.provider.ChaCha20Cipher. @@ -38,6 +38,7 @@ import java.util.HexFormat; import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.ChaCha20ParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; @@ -66,32 +67,38 @@ public static void main(String[] args) throws Exception { private static void testTransformations() throws Exception { System.out.println("== transformations =="); - checkTransformation("ChaCha20", true); - checkTransformation("ChaCha20/None/NoPadding", true); - checkTransformation("ChaCha20-Poly1305", true); - checkTransformation("ChaCha20-Poly1305/None/NoPadding", true); - - checkTransformation("ChaCha20/ECB/NoPadding", false); - checkTransformation("ChaCha20/None/PKCS5Padding", false); - checkTransformation("ChaCha20-Poly1305/ECB/NoPadding", false); - checkTransformation("ChaCha20-Poly1305/None/PKCS5Padding", false); + Class NSAE = NoSuchAlgorithmException.class; + Class NSPE = NoSuchPaddingException.class; + + checkTransformation("ChaCha20", null); + checkTransformation("ChaCha20/None/NoPadding", null); + checkTransformation("ChaCha20/None//", NSAE); + checkTransformation("ChaCha20/ECB/NoPadding", NSAE); + checkTransformation("ChaCha20/None/PKCS5Padding", NSPE); + checkTransformation("ChaCha20-Poly1305", null); + checkTransformation("ChaCha20-Poly1305/None/NoPadding", null); + checkTransformation("ChaCha20-Poly1305/None//", NSAE); + checkTransformation("ChaCha20-Poly1305/ECB/NoPadding", NSAE); + checkTransformation("ChaCha20-Poly1305/None/PKCS5Padding", NSPE); } - private static void checkTransformation(String transformation, - boolean expected) throws Exception { + private static void checkTransformation(String transformation, Class exCls) + throws Exception { try { - Cipher.getInstance(transformation); - if (!expected) { - throw new RuntimeException( - "Unexpected transformation: " + transformation); + Cipher.getInstance(transformation, + System.getProperty("test.provider.name", "SunJCE")); + if (exCls != null) { + throw new RuntimeException("Expected Exception not thrown: " + + exCls); } else { - System.out.println("Expected transformation: " + transformation); + System.out.println(transformation + ": pass"); } - } catch (NoSuchAlgorithmException e) { - if (!expected) { - System.out.println("Unexpected transformation: " + transformation); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + if (e.getClass() != exCls) { + throw new RuntimeException("Unexpected Exception", e); } else { - throw new RuntimeException("Unexpected fail: " + transformation, e); + System.out.println(transformation + ": got expected " + + exCls.getName()); } } } diff --git a/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java b/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java index 9dc22c77fd0..36f1e1b7706 100644 --- a/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java +++ b/test/jdk/com/sun/crypto/provider/TLS/TestLeadingZeroes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8014618 + * @bug 8014618 8368694 * @summary Need to strip leading zeros in TlsPremasterSecret of DHKeyAgreement * @author Pasi Eronen */ @@ -88,6 +88,26 @@ private void run() throws Exception { throw new Exception("First byte is not zero as expected"); } + // generate generic shared secret + aliceKeyAgree.init(alicePrivKey); + aliceKeyAgree.doPhase(bobPubKey, true); + byte[] genericSecret = + aliceKeyAgree.generateSecret("Generic").getEncoded(); + System.out.println("generic secret:\n" + HEX_FORMATTER.formatHex(genericSecret)); + + // verify that leading zero is present + if (genericSecret.length != 256) { + throw new Exception("Unexpected generic secret length"); + } + if (genericSecret[0] != 0) { + throw new Exception("First byte is not zero as expected"); + } + for (int i = 0; i < genericSecret.length; i++) { + if (genericSecret[i] != sharedSecret[i]) { + throw new Exception("Shared secrets differ"); + } + } + // now, test TLS premaster secret aliceKeyAgree.init(alicePrivKey); aliceKeyAgree.doPhase(bobPubKey, true); diff --git a/test/jdk/com/sun/jdi/SimulResumerTest.java b/test/jdk/com/sun/jdi/SimulResumerTest.java index 92cf4ba9ab5..2942e018418 100644 --- a/test/jdk/com/sun/jdi/SimulResumerTest.java +++ b/test/jdk/com/sun/jdi/SimulResumerTest.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 @@ -30,7 +30,7 @@ * * @run build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g SimulResumerTest.java - * @run driver SimulResumerTest + * @run driver/timeout=180 SimulResumerTest */ import com.sun.jdi.*; import com.sun.jdi.event.*; diff --git a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java index adf643749c7..77020491c29 100644 --- a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java +++ b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8284161 8287008 8309406 8356870 + * @bug 8284161 8287008 8309406 8356870 8365057 * @summary Basic test for com.sun.management.HotSpotDiagnosticMXBean.dumpThreads * @requires vm.continuations * @modules java.base/jdk.internal.vm jdk.management @@ -425,7 +425,9 @@ void testParkedThread(ThreadFactory factory, boolean pinned) throws Exception { ThreadFields fields = findThread(tid, lines); assertNotNull(fields, "thread not found"); assertEquals("WAITING", fields.state()); - assertTrue(contains(lines, "- parking to wait for lines, String text) { .anyMatch(l -> l.contains(text)); } + /** + * Finds the line of a plain text thread dump containing the given text. + */ + private String find(List lines, String text) { + return lines.stream().map(String::trim) + .filter(l -> l.contains(text)) + .findAny() + .orElse(null); + } + /** * Dump threads to a file in plain text format, return the lines in the file. */ diff --git a/test/jdk/com/sun/net/httpserver/SimpleFileServer.java b/test/jdk/com/sun/net/httpserver/SimpleFileServer.java deleted file mode 100644 index bff415c0b98..00000000000 --- a/test/jdk/com/sun/net/httpserver/SimpleFileServer.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.util.concurrent.*; -import java.util.logging.*; -import java.io.*; -import java.net.*; - -import com.sun.net.httpserver.*; - -/** - * Implements a basic static content HTTP server - * which understands text/html, text/plain content types - * - * Must be given an abs pathname to the document root. - * Directory listings together with text + html files - * can be served. - * - * File Server created on files sub-path - * - * Echo server created on echo sub-path - */ -public class SimpleFileServer { - - public static void main (String[] args) throws Exception { - if (args.length != 3) { - System.out.println ("usage: java FileServerHandler rootDir port logfilename"); - System.exit(1); - } - Logger logger = Logger.getLogger("com.sun.net.httpserver"); - ConsoleHandler ch = new ConsoleHandler(); - logger.setLevel(Level.ALL); - ch.setLevel(Level.ALL); - logger.addHandler(ch); - - String rootDir = args[0]; - int port = Integer.parseInt (args[1]); - String logfile = args[2]; - HttpServer server = HttpServer.create (new InetSocketAddress (port), 0); - HttpHandler h = new FileServerHandler (rootDir); - HttpHandler h1 = new EchoHandler (); - - HttpContext c = server.createContext ("/files", h); - c.getFilters().add (new LogFilter (new File (logfile))); - HttpContext c1 = server.createContext ("/echo", h1); - c.getFilters().add (new LogFilter (new File (logfile))); - c1.getFilters().add (new LogFilter (new File (logfile))); - server.setExecutor (Executors.newCachedThreadPool()); - server.start (); - } -} diff --git a/test/jdk/java/awt/Frame/DisposeTest.java b/test/jdk/java/awt/Frame/DisposeTest.java index 08c0def638e..ea1b2428f5c 100644 --- a/test/jdk/java/awt/Frame/DisposeTest.java +++ b/test/jdk/java/awt/Frame/DisposeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, 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 @@ -44,6 +44,7 @@ public class DisposeTest { private static Frame backgroundFrame; private static Frame testedFrame; + private static final int PIXEL_OFFSET = 4; private static final Rectangle backgroundFrameBounds = new Rectangle(100, 100, 200, 200); @@ -74,8 +75,8 @@ private static void test() { BufferedImage bi = robot.createScreenCapture(backgroundFrameBounds); int redPix = Color.RED.getRGB(); - for (int x = 0; x < bi.getWidth(); x++) { - for (int y = 0; y < bi.getHeight(); y++) { + for (int x = PIXEL_OFFSET; x < bi.getWidth() - PIXEL_OFFSET; x++) { + for (int y = PIXEL_OFFSET; y < bi.getHeight() - PIXEL_OFFSET; y++) { if (bi.getRGB(x, y) != redPix) { try { ImageIO.write(bi, "png", diff --git a/test/jdk/java/awt/Headless/HeadlessMalfunctionTest.java b/test/jdk/java/awt/Headless/HeadlessMalfunctionTest.java index 61ebf1df3e8..e9ae66492d4 100644 --- a/test/jdk/java/awt/Headless/HeadlessMalfunctionTest.java +++ b/test/jdk/java/awt/Headless/HeadlessMalfunctionTest.java @@ -38,7 +38,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller * HeadlessMalfunctionAgent * HeadlessMalfunctionAgent$1 - * @run driver HeadlessMalfunctionTest + * @run driver/timeout=240 HeadlessMalfunctionTest */ public class HeadlessMalfunctionTest { diff --git a/test/jdk/java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemonicKeyTypedTest.java b/test/jdk/java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemonicKeyTypedTest.java index 5b2dc2844f1..60c05fb05a6 100644 --- a/test/jdk/java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemonicKeyTypedTest.java +++ b/test/jdk/java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemonicKeyTypedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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,7 @@ /* @test @key headful - @bug 6346690 + @bug 6346690 8361606 8321303 @summary Tests that key_typed is consumed after mnemonic key_pressed is handled for a menu item. @library /test/lib @build jdk.test.lib.Platform diff --git a/test/jdk/java/awt/Mouse/EnterExitEvents/DragWindowTest.java b/test/jdk/java/awt/Mouse/EnterExitEvents/DragWindowTest.java index 4f789668c4a..2a77f294298 100644 --- a/test/jdk/java/awt/Mouse/EnterExitEvents/DragWindowTest.java +++ b/test/jdk/java/awt/Mouse/EnterExitEvents/DragWindowTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, 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 @@ -26,11 +26,8 @@ * @key headful * @bug 7154048 * @summary Window created under a mouse does not receive mouse enter event. - * Mouse Entered/Exited events are wrongly generated during dragging the window - * from one component to another - * @library ../../regtesthelpers - * @build Util - * @author alexandr.scherbatiy area=awt.event + * Mouse Entered/Exited events are wrongly generated during dragging the + * window from one component to another * @run main DragWindowTest */ @@ -50,76 +47,67 @@ import javax.swing.JPanel; import javax.swing.SwingUtilities; -import java.util.concurrent.Callable; - -import test.java.awt.regtesthelpers.Util; - public class DragWindowTest { - private static volatile int dragWindowMouseEnteredCount = 0; - private static volatile int dragWindowMouseReleasedCount = 0; private static volatile int buttonMouseEnteredCount = 0; private static volatile int labelMouseReleasedCount = 0; + + private static volatile Point pointToClick; + private static volatile Point pointToDrag; + private static MyDragWindow dragWindow; private static JLabel label; private static JButton button; + private static JFrame frame; public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(100); - Robot robot = new Robot(); - robot.setAutoDelay(100); - - SwingUtilities.invokeAndWait(new Runnable() { + SwingUtilities.invokeAndWait(DragWindowTest::createAndShowGUI); - @Override - public void run() { - createAndShowGUI(); - } - }); + robot.delay(250); + robot.waitForIdle(); - robot.delay(250); - robot.waitForIdle(); + SwingUtilities.invokeAndWait(() -> { + pointToClick = getCenterPoint(label); + pointToDrag = getCenterPoint(button); + }); - Point pointToClick = Util.invokeOnEDT(new Callable() { + robot.mouseMove(pointToClick.x, pointToClick.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(250); - @Override - public Point call() throws Exception { - return getCenterPoint(label); + if (dragWindowMouseEnteredCount != 1) { + throw new RuntimeException("No MouseEntered event on Drag Window!"); } - }); + // Reset entered count to check if mouse entered starting from here + buttonMouseEnteredCount = 0; + robot.mouseMove(pointToDrag.x, pointToDrag.y); + robot.waitForIdle(); + robot.delay(250); - robot.mouseMove(pointToClick.x, pointToClick.y); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.waitForIdle(); - - if (dragWindowMouseEnteredCount != 1) { - throw new RuntimeException("No MouseEntered event on Drag Window!"); - } - - Point pointToDrag = Util.invokeOnEDT(new Callable() { - - @Override - public Point call() throws Exception { - button.addMouseListener(new ButtonMouseListener()); - return getCenterPoint(button); + if (buttonMouseEnteredCount != 0) { + throw new RuntimeException("Extra MouseEntered event on button!"); } - }); - - robot.mouseMove(pointToDrag.x, pointToDrag.y); - robot.waitForIdle(); - - if (buttonMouseEnteredCount != 0) { - throw new RuntimeException("Extra MouseEntered event on button!"); - } - robot.mouseRelease(InputEvent.BUTTON1_MASK); - robot.waitForIdle(); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(250); - if (labelMouseReleasedCount != 1) { - throw new RuntimeException("No MouseReleased event on label!"); + if (labelMouseReleasedCount != 1) { + throw new RuntimeException("No MouseReleased event on label!"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); } - } private static Point getCenterPoint(Component comp) { @@ -129,8 +117,7 @@ private static Point getCenterPoint(Component comp) { } private static void createAndShowGUI() { - - JFrame frame = new JFrame("Main Frame"); + frame = new JFrame("DragWindowTest"); frame.setSize(300, 200); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -142,6 +129,7 @@ private static void createAndShowGUI() { button = new JButton("Button"); Panel panel = new Panel(new BorderLayout()); + button.addMouseListener(new ButtonMouseListener()); panel.add(label, BorderLayout.NORTH); panel.add(button, BorderLayout.CENTER); @@ -149,7 +137,6 @@ private static void createAndShowGUI() { frame.getContentPane().add(panel); frame.setLocationRelativeTo(null); frame.setVisible(true); - } private static Point getAbsoluteLocation(MouseEvent e) { @@ -157,7 +144,6 @@ private static Point getAbsoluteLocation(MouseEvent e) { } static class MyDragWindow extends Window { - static int d = 30; public MyDragWindow(Window parent, Point location) { @@ -176,8 +162,6 @@ void dragTo(Point point) { } static class LabelMouseListener extends MouseAdapter { - - Point origin; Window parent; public LabelMouseListener(Window parent) { @@ -210,20 +194,13 @@ public void mouseDragged(MouseEvent e) { } static class DragWindowMouseListener extends MouseAdapter { - @Override public void mouseEntered(MouseEvent e) { dragWindowMouseEnteredCount++; } - - @Override - public void mouseReleased(MouseEvent e) { - dragWindowMouseReleasedCount++; - } } static class ButtonMouseListener extends MouseAdapter { - @Override public void mouseEntered(MouseEvent e) { buttonMouseEnteredCount++; diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/SerializationSpecTest.java b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/SerializationSpecTest.java new file mode 100644 index 00000000000..aa50d814264 --- /dev/null +++ b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/SerializationSpecTest.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.OptionalDataException; + +/** + * @test + * @bug 8367384 + * @summary Verify ICC_Profile serialization per spec, all name/data cases + */ +public final class SerializationSpecTest { + + public static void main(String[] args) throws Exception { + // Serialization form for ICC_Profile includes version, profile name, + // and profile data. If the name is invalid or does not match a standard + // profile, the data is used. An exception is thrown only if both the + // name and the data are invalid, or if one of them is missing or is of + // the wrong type. + + // Naming conventions used in test file names: + // null : null reference + // valid : valid standard profile name or valid profile data (byte[]) + // invalid : unrecognized name or data with incorrect ICC header + // wrongType: incorrect type, e.g., int[] instead of String or byte[] + + // No name or data + test("empty", OptionalDataException.class); + + // Cases where only the profile name is present (no profile data) + test("null", OptionalDataException.class); + test("valid", OptionalDataException.class); + test("invalid", OptionalDataException.class); + test("wrongType", InvalidObjectException.class); + + // The test files are named as _.ser + test("null_null", InvalidObjectException.class); + test("null_valid", null); // valid data is enough if name is null + test("null_invalid", InvalidObjectException.class); + test("null_wrongType", InvalidObjectException.class); + + test("invalid_null", InvalidObjectException.class); + test("invalid_valid", null); // valid data is enough if name is invalid + test("invalid_invalid", InvalidObjectException.class); + test("invalid_wrongType", InvalidObjectException.class); + + test("wrongType_null", InvalidObjectException.class); + test("wrongType_valid", InvalidObjectException.class); + test("wrongType_invalid", InvalidObjectException.class); + test("wrongType_wrongType", InvalidObjectException.class); + + test("valid_null", null); // the valid name is enough + test("valid_valid", null); // the valid name is enough + test("valid_invalid", null); // the valid name is enough + test("valid_wrongType", InvalidObjectException.class); + } + + private static void test(String test, Class expected) { + String fileName = test + ".ser"; + File file = new File(System.getProperty("test.src", "."), fileName); + Class actual = null; + try (var fis = new FileInputStream(file); + var ois = new ObjectInputStream(fis)) + { + ois.readObject(); + } catch (Exception e) { + actual = e.getClass(); + } + if (actual != expected) { + System.err.println("Test: " + test); + System.err.println("Expected: " + expected); + System.err.println("Actual: " + actual); + throw new RuntimeException("Test failed"); + } + } +} diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/empty.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/empty.ser new file mode 100644 index 00000000000..3fd70024d65 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/empty.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid.ser new file mode 100644 index 00000000000..dfe071e69dc Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_invalid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_invalid.ser new file mode 100644 index 00000000000..60fb02f7783 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_invalid.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_null.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_null.ser new file mode 100644 index 00000000000..60fb02f7783 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_null.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_valid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_valid.ser new file mode 100644 index 00000000000..e01b5766f62 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_valid.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_wrongType.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_wrongType.ser new file mode 100644 index 00000000000..65485f041d7 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/invalid_wrongType.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null.ser new file mode 100644 index 00000000000..1fc2022f868 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_invalid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_invalid.ser new file mode 100644 index 00000000000..b2847de4f46 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_invalid.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_null.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_null.ser new file mode 100644 index 00000000000..31c87a6cb65 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_null.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_valid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_valid.ser new file mode 100644 index 00000000000..b32c838c80a Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_valid.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_wrongType.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_wrongType.ser new file mode 100644 index 00000000000..3279eec381d Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/null_wrongType.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid.ser new file mode 100644 index 00000000000..a6512d244cf Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_invalid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_invalid.ser new file mode 100644 index 00000000000..dbe11f2c6d6 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_invalid.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_null.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_null.ser new file mode 100644 index 00000000000..dbe11f2c6d6 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_null.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_valid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_valid.ser new file mode 100644 index 00000000000..fbe90d0eb6e Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_valid.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_wrongType.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_wrongType.ser new file mode 100644 index 00000000000..3538676276f Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/valid_wrongType.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType.ser new file mode 100644 index 00000000000..3469f871ef6 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_invalid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_invalid.ser new file mode 100644 index 00000000000..7da24ee9b96 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_invalid.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_null.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_null.ser new file mode 100644 index 00000000000..2c1536cc094 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_null.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_valid.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_valid.ser new file mode 100644 index 00000000000..2c1536cc094 Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_valid.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_wrongType.ser b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_wrongType.ser new file mode 100644 index 00000000000..8520dffcf4c Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/Serialization/SerializationSpecTest/wrongType_wrongType.ser differ diff --git a/test/jdk/java/awt/color/ICC_Profile/Serialization/StandardProfilesRoundTrip.java b/test/jdk/java/awt/color/ICC_Profile/Serialization/StandardProfilesRoundTrip.java new file mode 100644 index 00000000000..6b29fd7f22a --- /dev/null +++ b/test/jdk/java/awt/color/ICC_Profile/Serialization/StandardProfilesRoundTrip.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +/** + * @test + * @bug 8367384 + * @summary Checks ICC_Profile serialization for standard profiles + */ +public final class StandardProfilesRoundTrip { + + private static final ICC_Profile[] PROFILES = { + ICC_Profile.getInstance(ColorSpace.CS_sRGB), + ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB), + ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ), + ICC_Profile.getInstance(ColorSpace.CS_PYCC), + ICC_Profile.getInstance(ColorSpace.CS_GRAY) + }; + + public static void main(String[] args) throws Exception { + // Test profiles one by one + for (ICC_Profile profile : PROFILES) { + test(profile); + } + // Test all profiles at once + test(PROFILES); + } + + private static void test(ICC_Profile... profiles) throws Exception { + byte[] data; + try (var bos = new ByteArrayOutputStream(); + var oos = new ObjectOutputStream(bos)) + { + for (ICC_Profile p : profiles) { + oos.writeObject(p); + } + data = bos.toByteArray(); + } + try (var ois = new ObjectInputStream(new ByteArrayInputStream(data))) { + for (ICC_Profile p : profiles) { + if (p != ois.readObject()) { + throw new RuntimeException("Wrong deserialized object"); + } + } + } + } +} diff --git a/test/jdk/java/awt/color/ICC_Profile/ValidateICCHeaderData/ValidateICCHeaderData.java b/test/jdk/java/awt/color/ICC_Profile/ValidateICCHeaderData/ValidateICCHeaderData.java index 9867b727a09..62c5d4962e4 100644 --- a/test/jdk/java/awt/color/ICC_Profile/ValidateICCHeaderData/ValidateICCHeaderData.java +++ b/test/jdk/java/awt/color/ICC_Profile/ValidateICCHeaderData/ValidateICCHeaderData.java @@ -161,8 +161,8 @@ public static void main(String[] args) throws Exception { testProfileCreation(false); System.out.println("CASE 14: Passed \n"); - System.out.println("CASE 15: Testing Deserialization of ICC_Profile ..."); - testDeserialization(); + System.out.println("CASE 15: Testing loading of ICC_Profile from file ..."); + testLoading(); System.out.println("CASE 15: Passed \n"); System.out.println("Successfully completed testing all 15 cases. Test Passed !!"); @@ -261,9 +261,9 @@ private static void testInvalidHeaderSize() { } } - private static void testDeserialization() throws IOException { - //invalidSRGB.icc is serialized on older version of JDK - //Upon deserialization, the invalid profile is expected to throw IAE + private static void testLoading() throws IOException { + // invalidSRGB.icc is a profile file that was produced by an older JDK + // When attempting to load it, the current JDK is expected to throw IAE try { ICC_Profile.getInstance("./invalidSRGB.icc"); throw new RuntimeException("Test Failed ! Expected IAE NOT thrown"); diff --git a/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java b/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java index 7fb1167a847..06e71c4067f 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintTextTest.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 @@ -23,7 +23,7 @@ /* * @test - * @bug 6425068 7157659 8029204 8132890 8148334 8344637 + * @bug 6425068 7156751 7157659 8029204 8132890 8148334 8344637 * @key printer * @summary Confirm that text prints where we expect to the length we expect. * @library /java/awt/regtesthelpers diff --git a/test/jdk/java/lang/ProcessHandle/TEST.properties b/test/jdk/java/lang/ProcessHandle/TEST.properties new file mode 100644 index 00000000000..c7e8a6850ca --- /dev/null +++ b/test/jdk/java/lang/ProcessHandle/TEST.properties @@ -0,0 +1 @@ +maxOutputSize=6000000 diff --git a/test/jdk/java/lang/StringBuilder/RacingSBThreads.java b/test/jdk/java/lang/StringBuilder/RacingSBThreads.java index 26f5cf9385a..8affa3feffa 100644 --- a/test/jdk/java/lang/StringBuilder/RacingSBThreads.java +++ b/test/jdk/java/lang/StringBuilder/RacingSBThreads.java @@ -28,7 +28,6 @@ * @run main/othervm -esa RacingSBThreads read * @run main/othervm -esa RacingSBThreads insert * @run main/othervm -esa RacingSBThreads append - * @run main/othervm -Xcomp RacingSBThreads */ import java.nio.CharBuffer; diff --git a/test/jdk/java/lang/Thread/virtual/Starvation.java b/test/jdk/java/lang/Thread/virtual/Starvation.java index c55ad3c2494..987c54c1a0c 100644 --- a/test/jdk/java/lang/Thread/virtual/Starvation.java +++ b/test/jdk/java/lang/Thread/virtual/Starvation.java @@ -25,7 +25,7 @@ * @requires vm.continuations * @library /test/lib * @bug 8345294 - * @run main/othervm/timeout=800/native --enable-native-access=ALL-UNNAMED Starvation 100000 + * @run main/othervm/native --enable-native-access=ALL-UNNAMED Starvation */ import java.time.Duration; @@ -37,9 +37,16 @@ public class Starvation { public static void main(String[] args) throws Exception { - int iterations = Integer.parseInt(args[0]); + int iterations; + if (args.length > 0) { + iterations = Integer.parseInt(args[0]); + } else { + int nprocs = Runtime.getRuntime().availableProcessors(); + iterations = 40_000 / nprocs; + } - for (int i = 0; i < iterations; i++) { + for (int i = 1; i <= iterations; i++) { + System.out.format("%s iteration %d of %d ...%n", Instant.now(), i, iterations); var exRef = new AtomicReference(); Thread thread = Thread.startVirtualThread(() -> { try { diff --git a/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java b/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java index a231501894f..8c6132b2815 100644 --- a/test/jdk/java/lang/runtime/SwitchBootstrapsTest.java +++ b/test/jdk/java/lang/runtime/SwitchBootstrapsTest.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 @@ -155,23 +155,60 @@ public void testEnums() throws Throwable { testEnum(E1.B, 0, 0, "B", "C", "A", E1.class); testEnum(E1.B, 1, 3, "B", "C", "A", E1.class); try { - testEnum(E1.B, 1, 3, "B", "C", "A", E2.class); + testEnum(E1.B, 0, -1, E2.class); fail("Didn't get the expected exception."); } catch (IllegalArgumentException ex) { //OK } try { - testEnum(E1.B, 1, 3, "B", "C", "A", String.class); + testEnum(E1.B, 0, -1, String.class); fail("Didn't get the expected exception."); } catch (IllegalArgumentException ex) { //OK } + try { + testEnum(E1.B, 0, -1, 10); + fail("Didn't get the expected exception."); + } catch (IllegalArgumentException ex) { + //OK + } + try { + testEnum(E1.B, 0, -1, new Object()); + fail("Didn't get the expected exception."); + } catch (IllegalArgumentException ex) { + //OK + } + try { + testEnum(E1.B, 0, -1, new Object[] { null }); + fail("Didn't get the expected exception."); + } catch (IllegalArgumentException ex) { + //OK + } + try { + testEnum(E1.B, 0, -1, ""); + fail("Didn't get the expected exception."); + } catch (IllegalArgumentException ex) { + //OK + } + try { + testEnum(E1.B, 0, -1, (Object[]) null); + fail("Didn't get the expected exception."); + } catch (NullPointerException ex) { + //OK + } testEnum(E1.B, 0, 0, "B", "A"); testEnum(E1.A, 0, 1, "B", "A"); testEnum(E1.A, 0, 0, "A", "A", "B"); testEnum(E1.A, 1, 1, "A", "A", "B"); testEnum(E1.A, 2, 3, "A", "A", "B"); testEnum(E1.A, 0, 0); + testEnum(E1.B, 0, 2, "A", "OLD_REMOVED_CONSTANT", "B", E1.class); + testEnum(E1.B, 1, 2, "A", "OLD_REMOVED_CONSTANT", "B", E1.class); + + //null invocation name: + MethodType switchType = MethodType.methodType(int.class, E1.class, int.class); + MethodHandle indy = ((CallSite) BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), null, switchType)).dynamicInvoker(); + assertEquals((int) indy.invoke(E1.A, 0), 0); } public void testEnumsWithConstants() throws Throwable { @@ -197,6 +234,9 @@ enum E { testEnum(E.class, E.A, 0, 0, "A", "B", "C"); testEnum(E.class, E.B, 0, 1, "A", "B", "C"); testEnum(E.class, E.C, 0, 2, "A", "B", "C"); + testEnum(E.class, E.C, 0, 2, "A", "B"); + testEnum(E.class, E.C, 1, 2, "A", "B"); + testEnum(E.class, E.C, 2, 2, "A", "B"); } public void testWrongSwitchTypes() throws Throwable { @@ -279,6 +319,9 @@ public void testNullLabels() throws Throwable { } catch (IllegalArgumentException ex) { //OK } + //null invocationName is OK: + BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), null, switchType, + new Object[] {Object.class}); } private static AtomicBoolean enumInitialized = new AtomicBoolean(); diff --git a/test/jdk/java/net/httpclient/BasicHTTP2Test.java b/test/jdk/java/net/httpclient/BasicHTTP2Test.java index 65bcf7631ea..8233da37c42 100644 --- a/test/jdk/java/net/httpclient/BasicHTTP2Test.java +++ b/test/jdk/java/net/httpclient/BasicHTTP2Test.java @@ -166,7 +166,6 @@ private HttpClient makeNewClient() { .proxy(HttpClient.Builder.NO_PROXY) .executor(executor) .sslContext(sslContext) - .connectTimeout(Duration.ofSeconds(10)) .build(); return TRACKER.track(client); } diff --git a/test/jdk/java/net/httpclient/BasicHTTP3Test.java b/test/jdk/java/net/httpclient/BasicHTTP3Test.java index bd31b932b80..32dd1dea832 100644 --- a/test/jdk/java/net/httpclient/BasicHTTP3Test.java +++ b/test/jdk/java/net/httpclient/BasicHTTP3Test.java @@ -216,7 +216,6 @@ private HttpClient makeNewClient() { .proxy(HttpClient.Builder.NO_PROXY) .executor(executor) .sslContext(sslContext) - .connectTimeout(Duration.ofSeconds(10)) .build(); return TRACKER.track(client); } diff --git a/test/jdk/java/net/httpclient/RedirectTimeoutTest.java b/test/jdk/java/net/httpclient/RedirectTimeoutTest.java index be634398ba2..3e921879fe3 100644 --- a/test/jdk/java/net/httpclient/RedirectTimeoutTest.java +++ b/test/jdk/java/net/httpclient/RedirectTimeoutTest.java @@ -133,7 +133,7 @@ public void test(Version version, URI uri, URI redirectURI) throws InterruptedEx if (version == HTTP_3) { reqBuilder = reqBuilder.version(HTTP_3).setOption(H3_DISCOVERY, HTTP_3_URI_ONLY); } - HttpRequest request = reqBuilder + HttpRequest request = reqBuilder.copy() .GET() .version(version) .timeout(Duration.ofMillis(adjustTimeout(TIMEOUT_MILLIS))) diff --git a/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java b/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java index a67710c485f..14842d401fd 100644 --- a/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java +++ b/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java @@ -33,7 +33,6 @@ import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; import java.nio.charset.StandardCharsets; -import java.time.Duration; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -47,6 +46,7 @@ import java.util.concurrent.atomic.AtomicLong; import javax.net.ssl.SSLContext; +import jdk.test.lib.Utils; import jdk.test.lib.net.SimpleSSLContext; import jdk.httpclient.test.lib.common.HttpServerAdapters; import jdk.httpclient.test.lib.http2.Http2TestServer; @@ -74,8 +74,9 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.Utils * @compile ../ReferenceTracker.java - * @run testng/othervm/timeout=60 -Djdk.internal.httpclient.debug=true + * @run testng/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors * GetHTTP3Test * @summary Basic HTTP/3 GET test @@ -216,7 +217,6 @@ private HttpClient makeNewClient() { .proxy(HttpClient.Builder.NO_PROXY) .executor(executor) .sslContext(sslContext) - .connectTimeout(Duration.ofSeconds(10)) .build(); return TRACKER.track(client); } @@ -348,7 +348,7 @@ public void testAsync(String uri, Version firstRequestVersion, boolean sameClien var tracker = TRACKER.getTracker(client); client = null; System.gc(); - AssertionError error = TRACKER.check(tracker, 1000); + AssertionError error = TRACKER.check(tracker, Utils.adjustTimeout(1000)); if (error != null) throw error; } System.out.println("test: DONE"); @@ -394,7 +394,7 @@ public void testSync(String h3URI) throws Exception { var tracker = TRACKER.getTracker(client); client = null; System.gc(); - AssertionError error = TRACKER.check(tracker, 1000); + AssertionError error = TRACKER.check(tracker, Utils.adjustTimeout(1000)); if (error != null) throw error; } @@ -423,7 +423,7 @@ public void teardown() throws Exception { sharedClient == null ? null : sharedClient.toString(); sharedClient = null; Thread.sleep(100); - AssertionError fail = TRACKER.check(500); + AssertionError fail = TRACKER.check(Utils.adjustTimeout(1000)); try { h3TestServer.stop(); } finally { diff --git a/test/jdk/java/net/httpclient/http3/H3DataLimitsTest.java b/test/jdk/java/net/httpclient/http3/H3DataLimitsTest.java index 0bee94e6e8a..1443c03bf5d 100644 --- a/test/jdk/java/net/httpclient/http3/H3DataLimitsTest.java +++ b/test/jdk/java/net/httpclient/http3/H3DataLimitsTest.java @@ -164,7 +164,6 @@ private HttpClient makeNewClient() { .proxy(HttpClient.Builder.NO_PROXY) .executor(executor) .sslContext(sslContext) - .connectTimeout(Duration.ofSeconds(10)) .build(); return client; } diff --git a/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java b/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java index 10a3a3af8f2..4315fd36de5 100644 --- a/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java +++ b/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java @@ -34,6 +34,7 @@ import jdk.internal.net.quic.QuicVersion; import jdk.test.lib.net.SimpleSSLContext; import jdk.test.lib.net.URIBuilder; +import jdk.test.lib.Utils; import org.testng.IRetryAnalyzer; import org.testng.ITestResult; import org.testng.annotations.AfterClass; @@ -802,7 +803,7 @@ public void testStatelessReset() throws Exception { final HttpResponse response = client.sendAsync( request, BodyHandlers.discarding()) - .get(10, TimeUnit.SECONDS); + .get(Utils.adjustTimeout(10), TimeUnit.SECONDS); fail("Expected the request to fail, got " + response); } catch (Exception e) { final String expectedMsg = "stateless reset from peer"; @@ -943,7 +944,7 @@ private void triggerClose(String... reasons) throws Exception { final HttpResponse response = client.sendAsync( request, BodyHandlers.discarding()) - .get(10, TimeUnit.SECONDS); + .get(Utils.adjustTimeout(10), TimeUnit.SECONDS); fail("Expected the request to fail, got " + response); } catch (ExecutionException e) { System.out.println("Client exception [expected]: " + e); @@ -966,13 +967,13 @@ private void triggerError(CompletableFuture errorCF, Http3Erro final HttpResponse response = client.sendAsync( request, BodyHandlers.discarding()) - .get(10, TimeUnit.SECONDS); + .get(Utils.adjustTimeout(20), TimeUnit.SECONDS); fail("Expected the request to fail, got " + response); } catch (ExecutionException e) { System.out.println("Client exception [expected]: " + e); var cause = e.getCause(); assertTrue(cause instanceof ProtocolException, "Expected ProtocolException"); - TerminationCause terminationCause = errorCF.get(10, TimeUnit.SECONDS); + TerminationCause terminationCause = errorCF.get(Utils.adjustTimeout(10), TimeUnit.SECONDS); System.out.println("Server reason: \"" + terminationCause.getPeerVisibleReason()+'"'); final long actual = terminationCause.getCloseCode(); // expected @@ -989,13 +990,13 @@ private void triggerError(CompletableFuture errorCF, Http3Erro final HttpResponse response = client.sendAsync( request, BodyHandlers.discarding()) - .get(10, TimeUnit.SECONDS); + .get(Utils.adjustTimeout(10), TimeUnit.SECONDS); fail("Expected the request to fail, got " + response); } catch (ExecutionException e) { System.out.println("Client exception [expected]: " + e); var cause = e.getCause(); assertTrue(cause instanceof ProtocolException, "Expected ProtocolException"); - TerminationCause terminationCause = errorCF.get(10, TimeUnit.SECONDS); + TerminationCause terminationCause = errorCF.get(Utils.adjustTimeout(10), TimeUnit.SECONDS); System.out.println("Server reason: \"" + terminationCause.getPeerVisibleReason()+'"'); final long actual = terminationCause.getCloseCode(); // expected @@ -1019,13 +1020,13 @@ private void triggerPushError(CompletableFuture errorCF, Http3 BodyHandlers.discarding(), (initiatingRequest, pushPromiseRequest, acceptor) -> acceptor.apply(BodyHandlers.discarding()) - ).get(10, TimeUnit.SECONDS); + ).get(Utils.adjustTimeout(10), TimeUnit.SECONDS); fail("Expected the request to fail, got " + response); } catch (ExecutionException e) { System.out.println("Client exception [expected]: " + e); var cause = e.getCause(); assertTrue(cause instanceof ProtocolException, "Expected ProtocolException"); - TerminationCause terminationCause = errorCF.get(10, TimeUnit.SECONDS); + TerminationCause terminationCause = errorCF.get(Utils.adjustTimeout(10), TimeUnit.SECONDS); System.out.println("Server reason: \"" + terminationCause.getPeerVisibleReason()+'"'); final long actual = terminationCause.getCloseCode(); // expected diff --git a/test/jdk/java/net/httpclient/http3/H3HeaderSizeLimitTest.java b/test/jdk/java/net/httpclient/http3/H3HeaderSizeLimitTest.java index 7369bb9190e..06e3c2ac521 100644 --- a/test/jdk/java/net/httpclient/http3/H3HeaderSizeLimitTest.java +++ b/test/jdk/java/net/httpclient/http3/H3HeaderSizeLimitTest.java @@ -103,8 +103,6 @@ public void testLargeHeaderSize() throws Exception { final HttpClient client = newClientBuilderForH3() .proxy(HttpClient.Builder.NO_PROXY) .version(Version.HTTP_3) - // the server drops 1 packet out of two! - .connectTimeout(Duration.ofSeconds(Utils.adjustTimeout(10))) .sslContext(sslContext).build(); final URI reqURI = new URI(requestURIBase + "/hello"); final HttpRequest.Builder reqBuilder = HttpRequest.newBuilder(reqURI) diff --git a/test/jdk/java/net/httpclient/http3/H3InsertionsLimitTest.java b/test/jdk/java/net/httpclient/http3/H3InsertionsLimitTest.java index 7ca07a30ab9..19c19561cf9 100644 --- a/test/jdk/java/net/httpclient/http3/H3InsertionsLimitTest.java +++ b/test/jdk/java/net/httpclient/http3/H3InsertionsLimitTest.java @@ -155,8 +155,6 @@ public void multipleTableInsertions() throws Exception { final HttpClient client = newClientBuilderForH3() .proxy(HttpClient.Builder.NO_PROXY) .version(Version.HTTP_3) - // the server drops 1 packet out of two! - .connectTimeout(Duration.ofSeconds(Utils.adjustTimeout(10))) .sslContext(sslContext).build(); final URI reqURI = new URI(requestURIBase + "/insertions"); final HttpRequest.Builder reqBuilder = HttpRequest.newBuilder(reqURI) diff --git a/test/jdk/java/net/httpclient/http3/H3ServerPushTest.java b/test/jdk/java/net/httpclient/http3/H3ServerPushTest.java index 9b4858f50c9..ed5a14d8576 100644 --- a/test/jdk/java/net/httpclient/http3/H3ServerPushTest.java +++ b/test/jdk/java/net/httpclient/http3/H3ServerPushTest.java @@ -78,7 +78,7 @@ * /test/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer * jdk.test.lib.net.SimpleSSLContext - * @run junit H3ServerPushTest + * @run junit/othervm/timeout=240 H3ServerPushTest */ /** diff --git a/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java b/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java index 0e7a57ca699..8bb6515d4ff 100644 --- a/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java +++ b/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java @@ -38,7 +38,6 @@ import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; import java.nio.charset.StandardCharsets; -import java.time.Duration; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -53,6 +52,7 @@ import java.util.stream.Stream; import javax.net.ssl.SSLContext; +import jdk.test.lib.Utils; import jdk.test.lib.net.SimpleSSLContext; import jdk.httpclient.test.lib.common.HttpServerAdapters; import jdk.httpclient.test.lib.http2.Http2TestServer; @@ -79,6 +79,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.Utils * @compile ../ReferenceTracker.java * @run testng/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors @@ -221,7 +222,6 @@ private HttpClient makeNewClient() { .proxy(HttpClient.Builder.NO_PROXY) .executor(executor) .sslContext(sslContext) - .connectTimeout(Duration.ofSeconds(10)) .build(); return TRACKER.track(client); } @@ -375,7 +375,7 @@ public void testAsync(String uri, Version firstRequestVersion, boolean sameClien var tracker = TRACKER.getTracker(client); client = null; System.gc(); - AssertionError error = TRACKER.check(tracker, 1000); + AssertionError error = TRACKER.check(tracker, Utils.adjustTimeout(1000)); if (error != null) throw error; } System.out.println("test: DONE"); @@ -437,7 +437,7 @@ public void testSync(String h3URI) throws Exception { var tracker = TRACKER.getTracker(client); client = null; System.gc(); - AssertionError error = TRACKER.check(tracker, 1000); + AssertionError error = TRACKER.check(tracker, Utils.adjustTimeout(1000)); if (error != null) throw error; } @@ -466,7 +466,7 @@ public void teardown() throws Exception { sharedClient == null ? null : sharedClient.toString(); sharedClient = null; Thread.sleep(100); - AssertionError fail = TRACKER.check(500); + AssertionError fail = TRACKER.check(Utils.adjustTimeout(1000)); try { h3TestServer.stop(); } finally { diff --git a/test/jdk/java/net/spi/URLStreamHandlerProvider/Basic.java b/test/jdk/java/net/spi/URLStreamHandlerProvider/Basic.java index 9f8381a92c8..a98bf8e129e 100644 --- a/test/jdk/java/net/spi/URLStreamHandlerProvider/Basic.java +++ b/test/jdk/java/net/spi/URLStreamHandlerProvider/Basic.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 @@ -77,6 +77,7 @@ public static void main(String[] args) throws Throwable { viaProvider("bert", KNOWN); viaBadProvider("tom", SCE); viaBadProvider("jerry", SCE); + viaCircularProvider("circular", CIRCULAR); } private static String withoutWarning(String in) { @@ -99,6 +100,12 @@ private static String withoutWarning(String in) { throw new RuntimeException("exitValue: "+ r.exitValue + ", output:[" +r.output +"]"); } }; + static final Consumer CIRCULAR = r -> { + if (r.exitValue == 0 || + !r.output.contains("Circular loading of URL stream handler providers detected")) { + throw new RuntimeException("exitValue: " + r.exitValue + ", output:[" + r.output + "]"); + } + }; static void unknownProtocol(String protocol, Consumer resultChecker) { System.out.println("\nTesting " + protocol); @@ -125,6 +132,15 @@ static void viaBadProvider(String protocol, Consumer resultChecker, sysProps); } + static void viaCircularProvider(String protocol, Consumer resultChecker, + String... sysProps) + throws Exception + { + viaProviderWithTemplate(protocol, resultChecker, + TEST_SRC.resolve("circular.provider.template"), + sysProps); + } + static void viaProviderWithTemplate(String protocol, Consumer resultChecker, Path template, String... sysProps) diff --git a/test/jdk/java/net/spi/URLStreamHandlerProvider/circular.provider.template b/test/jdk/java/net/spi/URLStreamHandlerProvider/circular.provider.template new file mode 100644 index 00000000000..b846cc4fec6 --- /dev/null +++ b/test/jdk/java/net/spi/URLStreamHandlerProvider/circular.provider.template @@ -0,0 +1,48 @@ +/* + * 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 $package; + +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.net.spi.URLStreamHandlerProvider; + +public final class Provider extends URLStreamHandlerProvider { + + private static final String PROTOCOL = "$protocol"; + + @Override + public URLStreamHandler createURLStreamHandler(String protocol) { + try { + // Trigger circular lookup + URI.create("bogus://path/to/nothing").toURL(); + } catch (Exception exception) { + throw new RuntimeException(exception); + } + throw new AssertionError("Should not have reached here!"); + } + +} diff --git a/test/jdk/java/nio/channels/DatagramChannel/StressNativeSignal.java b/test/jdk/java/nio/channels/DatagramChannel/StressNativeSignal.java index d6d2f083eca..cc726d19c0d 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/StressNativeSignal.java +++ b/test/jdk/java/nio/channels/DatagramChannel/StressNativeSignal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -36,42 +36,23 @@ import java.util.concurrent.CountDownLatch; public class StressNativeSignal { - private UDPThread udpThread; - private ServerSocketThread serverSocketThread; + private final UDPThread udpThread; + private final ServerSocketThread serverSocketThread; - StressNativeSignal() { + StressNativeSignal() throws IOException { serverSocketThread = initServerSocketThread(); - if (serverSocketThread != null) { - serverSocketThread.start(); - } + serverSocketThread.start(); udpThread = initUDPThread(); - if (udpThread != null) { - udpThread.start(); - } + udpThread.start(); } - private UDPThread initUDPThread() { - UDPThread aUDPThread = null; - try { - aUDPThread = new UDPThread(); - } catch (Exception z) { - System.err.println("failed to create and start a UDPThread"); - z.printStackTrace(); - } - return aUDPThread; + private UDPThread initUDPThread() throws IOException { + return new UDPThread(); } - private ServerSocketThread initServerSocketThread() { - ServerSocketThread aServerSocketThread = null; - try { - aServerSocketThread = new ServerSocketThread(); - - } catch (Exception z) { - System.err.println("failed to create and start a ServerSocketThread"); - z.printStackTrace(); - } - return aServerSocketThread; + private ServerSocketThread initServerSocketThread() throws IOException { + return new ServerSocketThread(); } public static void main(String[] args) throws Throwable { @@ -80,46 +61,39 @@ public static void main(String[] args) throws Throwable { test.shutdown(); } - public void shutdown() { - if ((udpThread != null) && udpThread.isAlive()) { + public void shutdown() throws InterruptedException, IOException { + if (udpThread != null && udpThread.isAlive()) { udpThread.terminate(); - try { - udpThread.join(); - } catch (Exception z) { - z.printStackTrace(System.err); - } + udpThread.join(); + } else { System.out.println("UDPThread test scenario was not run"); } - if ((serverSocketThread != null) && (serverSocketThread.isAlive())) { + if (serverSocketThread != null && serverSocketThread.isAlive()) { serverSocketThread.terminate(); - try { - serverSocketThread.join(); - } catch (Exception z) { - z.printStackTrace(System.err); - } + serverSocketThread.join(); } else { System.out.println("ServerSocketThread test scenario was not run"); } } - public void waitForTestThreadsToStart() { - if ((udpThread != null) && udpThread.isAlive()) { + public void waitForTestThreadsToStart() throws InterruptedException { + if (udpThread != null && udpThread.isAlive()) { udpThread.waitTestThreadStart(); } - if ((serverSocketThread != null) && (serverSocketThread.isAlive())) { + if (serverSocketThread != null && serverSocketThread.isAlive()) { serverSocketThread.waitTestThreadStart(); } } public class ServerSocketThread extends Thread { private volatile boolean shouldTerminate; - private ServerSocket socket; + private final ServerSocket socket; private final CountDownLatch threadStarted = new CountDownLatch(1); - public ServerSocketThread () throws Exception { - socket = new ServerSocket(1122); + public ServerSocketThread() throws IOException { + socket = new ServerSocket(0); } public void run() { @@ -129,7 +103,7 @@ public void run() { Socket client = socket.accept(); client.close(); throw new RuntimeException("Unexpected return from accept call"); - } catch (Exception z) { + } catch (IOException z) { System.err.println("ServerSocketThread: caught exception " + z.getClass().getName()); if (!shouldTerminate) { z.printStackTrace(System.err); @@ -141,7 +115,7 @@ public void terminate() { shouldTerminate = true; try { socket.close(); - } catch (Exception z) { + } catch (IOException z) { z.printStackTrace(System.err); // ignore } @@ -150,7 +124,7 @@ public void terminate() { public void waitTestThreadStart() { try { threadStarted.await(); - } catch (Exception z) { + } catch (InterruptedException z) { z.printStackTrace(System.err); // ignore } @@ -158,15 +132,14 @@ public void waitTestThreadStart() { } public class UDPThread extends Thread { - private DatagramChannel channel; + private final DatagramChannel channel; private volatile boolean shouldTerminate; private final CountDownLatch threadStarted = new CountDownLatch(1); - public UDPThread () throws Exception { - + public UDPThread() throws IOException { channel = DatagramChannel.open(); channel.setOption(StandardSocketOptions.SO_RCVBUF, 6553600); - channel.bind(new InetSocketAddress(19870)); + channel.bind(new InetSocketAddress(0)); } @Override @@ -191,7 +164,7 @@ public void terminate() { shouldTerminate = true; try { channel.close(); - } catch (Exception z) { + } catch (IOException z) { System.err.println("UDPThread: caught exception " + z.getClass().getName()); z.printStackTrace(System.err); // ignore @@ -201,7 +174,7 @@ public void terminate() { public void waitTestThreadStart() { try { threadStarted.await(); - } catch (Exception z) { + } catch (InterruptedException z) { z.printStackTrace(System.err); // ignore } diff --git a/test/jdk/java/nio/charset/Charset/IllegalCharsetName.java b/test/jdk/java/nio/charset/Charset/IllegalCharsetName.java index 266801cf52b..9f2879a3ff0 100644 --- a/test/jdk/java/nio/charset/Charset/IllegalCharsetName.java +++ b/test/jdk/java/nio/charset/Charset/IllegalCharsetName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023, 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 @@ -50,7 +50,7 @@ public void illegalCharsetsTest(String name) { assertThrows(IllegalCharsetNameException.class, () -> Charset.forName(name)); assertThrows(IllegalCharsetNameException.class, - () -> Charset.forName(name)); + () -> Charset.isSupported(name)); } // Charset.forName, Charset.isSupported, and the Charset constructor should @@ -60,7 +60,7 @@ public void emptyCharsetsTest() { assertThrows(IllegalCharsetNameException.class, () -> Charset.forName("")); assertThrows(IllegalCharsetNameException.class, - () -> Charset.forName("")); + () -> Charset.isSupported("")); assertThrows(IllegalCharsetNameException.class, () -> new Charset("", new String[]{}) { @Override diff --git a/test/jdk/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java b/test/jdk/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java index 4de6598a0f4..f40502601d2 100644 --- a/test/jdk/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java +++ b/test/jdk/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java @@ -59,10 +59,13 @@ import java.lang.reflect.*; import java.rmi.registry.*; import sun.rmi.transport.*; +import java.util.concurrent.CountDownLatch; public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak { public CheckLeaseLeak() throws RemoteException { } - public void ping () throws RemoteException { } + public void ping () throws RemoteException { + remoteCallsComplete.countDown(); + } /** * Id to fake the DGC_ID, so we can later get a reference to the @@ -74,6 +77,9 @@ public void ping () throws RemoteException { } private final static int numberPingCalls = 0; private final static int CHECK_INTERVAL = 400; private final static int LEASE_VALUE = 20; + private static final int NO_OF_CLIENTS = ITERATIONS; + private static final int GOOD_LUCK_FACTOR = 2; + private static CountDownLatch remoteCallsComplete = new CountDownLatch(NO_OF_CLIENTS); public static void main (String[] args) { CheckLeaseLeak leakServer = null; @@ -113,8 +119,14 @@ public static void main (String[] args) { jvm.destroy(); } } + try { + remoteCallsComplete.await(); + System.out.println("remoteCallsComplete . . . "); + } catch (InterruptedException intEx) { + System.out.println("remoteCallsComplete.await interrupted . . . "); + } + Thread.sleep(NO_OF_CLIENTS * LEASE_VALUE * GOOD_LUCK_FACTOR); numLeft = getDGCLeaseTableSize(); - Thread.sleep(3000); } catch(Exception e) { TestLibrary.bomb("CheckLeaseLeak Error: ", e); @@ -125,8 +137,8 @@ public static void main (String[] args) { } } - /* numLeft should be 4 - if 11 there is a problem. */ - if (numLeft > 4) { + /* numLeft should not be greater than 2 - if 11 there is a problem. */ + if (numLeft > 2) { TestLibrary.bomb("Too many objects in DGCImpl.leaseTable: "+ numLeft); } else { @@ -204,8 +216,9 @@ private static int getDGCLeaseTableSize () { * objects if the LeaseInfo memory leak is not fixed. */ leaseTable = (Map) f.get(dgcImpl[0]); - - numLeaseInfosLeft = leaseTable.size(); + synchronized (leaseTable) { + numLeaseInfosLeft = leaseTable.size(); + } } catch(Exception e) { TestLibrary.bomb(e); diff --git a/test/jdk/java/text/Collator/RuleBasedCollatorTest.java b/test/jdk/java/text/Collator/RuleBasedCollatorTest.java index 429768b6bf1..cd1e8ca69c0 100644 --- a/test/jdk/java/text/Collator/RuleBasedCollatorTest.java +++ b/test/jdk/java/text/Collator/RuleBasedCollatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, 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 @@ -26,40 +26,45 @@ * @bug 4406815 8222969 8266784 * @summary RuleBasedCollatorTest uses very limited but selected test data * to test basic functionalities provided by RuleBasedCollator. - * @run testng/othervm RuleBasedCollatorTest + * @run junit/othervm RuleBasedCollatorTest */ +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.CollationElementIterator; import java.text.CollationKey; -import java.text.RuleBasedCollator; import java.text.Collator; import java.text.ParseException; +import java.text.RuleBasedCollator; import java.util.Arrays; import java.util.Locale; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.testng.SkipException; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeFalse; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class RuleBasedCollatorTest { - static RuleBasedCollator USC; - static String US_RULES; + private static RuleBasedCollator USC; + private static String US_RULES; - @BeforeClass - public void setup() { + @BeforeAll + void setup() { Collator c = Collator.getInstance(Locale.US); - if (!(c instanceof RuleBasedCollator)) { - throw new SkipException("skip tests."); - } + assumeFalse(!(c instanceof RuleBasedCollator), "skip tests."); USC = (RuleBasedCollator) c; US_RULES = USC.getRules(); } - @DataProvider(name = "rulesData") Object[][] rulesData() { //Basic Tailor String BASIC_TAILOR_RULES = "< b=c<\u00e6;A,a"; @@ -91,15 +96,15 @@ Object[][] rulesData() { }; } - @Test(dataProvider = "rulesData") - public void testRules(String rules, String[] testData, String[] expected) + @ParameterizedTest + @MethodSource("rulesData") + void testRules(String rules, String[] testData, String[] expected) throws ParseException { Arrays.sort(testData, new RuleBasedCollator(rules)); - assertEquals(testData, expected); + assertArrayEquals(expected, testData); } - @DataProvider(name = "FrenchSecondarySort") Object[][] FrenchSecondarySort() { return new Object[][] { { "\u0061\u00e1\u0061", "\u00e1\u0061\u0061", 1 }, @@ -111,8 +116,9 @@ Object[][] FrenchSecondarySort() { { "a", "\u1ea1", -1 } }; } - @Test(dataProvider = "FrenchSecondarySort") - public void testFrenchSecondarySort(String sData, String tData, + @ParameterizedTest + @MethodSource("FrenchSecondarySort") + void testFrenchSecondarySort(String sData, String tData, int expected) throws ParseException { String french_rule = "@"; String rules = US_RULES + french_rule; @@ -121,7 +127,6 @@ public void testFrenchSecondarySort(String sData, String tData, assertEquals(expected, result); } - @DataProvider(name = "ThaiLaoVowelConsonantSwapping") Object[][] ThaiLaoVowelConsonantSwapping() { return new Object[][] {{"\u0e44\u0e01", "\u0e40\u0e2e", -1},//swap {"\u0e2e\u0e40", "\u0e01\u0e44", 1},//no swap @@ -129,8 +134,9 @@ Object[][] ThaiLaoVowelConsonantSwapping() { }; } - @Test(dataProvider = "ThaiLaoVowelConsonantSwapping") - public void testThaiLaoVowelConsonantSwapping(String sData, String tData, + @ParameterizedTest + @MethodSource("ThaiLaoVowelConsonantSwapping") + void testThaiLaoVowelConsonantSwapping(String sData, String tData, int expected) throws ParseException { String thai_rule = "& Z < \u0e01 < \u0e2e <\u0e40 < \u0e44!"; String rules = US_RULES + thai_rule; @@ -140,16 +146,15 @@ public void testThaiLaoVowelConsonantSwapping(String sData, String tData, } @Test - public void testIgnorableCharacter() throws ParseException { + void testIgnorableCharacter() throws ParseException { String rule = "=f new RuleBasedCollator(rule)); } - @Test(expectedExceptions = NullPointerException.class) - public void testNullParseException() throws ParseException{ - new RuleBasedCollator(null); + @Test + void testNullParseException() { + assertThrows(NullPointerException.class, () -> new RuleBasedCollator(null)); } } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/CompactFormatAndParseHelper.java b/test/jdk/java/text/Format/CompactNumberFormat/CompactFormatAndParseHelper.java index 3f3f1932e51..4d410f97b5d 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/CompactFormatAndParseHelper.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/CompactFormatAndParseHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, 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 @@ -24,14 +24,15 @@ import java.text.NumberFormat; import java.text.ParseException; import java.text.ParsePosition; -import static org.testng.Assert.assertEquals; + +import static org.junit.jupiter.api.Assertions.assertEquals; class CompactFormatAndParseHelper { static void testFormat(NumberFormat cnf, Object number, String expected) { String result = cnf.format(number); - assertEquals(result, expected, "Incorrect formatting of the number '" + assertEquals(expected, result, "Incorrect formatting of the number '" + number + "'"); } @@ -46,11 +47,11 @@ static void testParse(NumberFormat cnf, String parseString, } if (returnType != null) { - assertEquals(number.getClass(), returnType, + assertEquals(returnType, number.getClass(), "Incorrect return type for string '" + parseString + "'"); } - assertEquals(number, expected, "Incorrect parsing of the string '" + assertEquals(expected, number, "Incorrect parsing of the string '" + parseString + "'"); } } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestCNFRounding.java b/test/jdk/java/text/Format/CompactNumberFormat/TestCNFRounding.java index b4dddfa1df7..0ba9587a344 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestCNFRounding.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestCNFRounding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 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 @@ -20,21 +20,28 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 * @summary Checks the rounding of formatted number in compact number formatting - * @run testng/othervm TestCNFRounding + * @run junit/othervm TestCNFRounding */ +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.math.RoundingMode; import java.text.NumberFormat; import java.util.List; import java.util.Locale; -import static org.testng.Assert.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestCNFRounding { private static final List MODES = List.of( @@ -46,7 +53,6 @@ public class TestCNFRounding { RoundingMode.CEILING, RoundingMode.FLOOR); - @DataProvider(name = "roundingData") Object[][] roundingData() { return new Object[][]{ // Number, half_even, half_up, half_down, up, down, ceiling, floor @@ -70,7 +76,6 @@ Object[][] roundingData() { {-4500, new String[]{"-4K", "-5K", "-4K", "-5K", "-4K", "-4K", "-5K"}},}; } - @DataProvider(name = "roundingFract") Object[][] roundingFract() { return new Object[][]{ // Number, half_even, half_up, half_down, up, down, ceiling, floor @@ -94,7 +99,6 @@ Object[][] roundingFract() { {-4500, new String[]{"-4.5K", "-4.5K", "-4.5K", "-4.5K", "-4.5K", "-4.5K", "-4.5K"}},}; } - @DataProvider(name = "rounding2Fract") Object[][] rounding2Fract() { return new Object[][]{ // Number, half_even, half_up, half_down @@ -118,37 +122,42 @@ Object[][] rounding2Fract() { {4686, new String[]{"4.69K", "4.69K", "4.69K"}},}; } - @Test(expectedExceptions = NullPointerException.class) - public void testNullMode() { - NumberFormat fmt = NumberFormat - .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); - fmt.setRoundingMode(null); + @Test + void testNullMode() { + assertThrows(NullPointerException.class, () -> { + NumberFormat fmt = NumberFormat + .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); + fmt.setRoundingMode(null); + }); } @Test - public void testDefaultRoundingMode() { + void testDefaultRoundingMode() { NumberFormat fmt = NumberFormat .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); - assertEquals(fmt.getRoundingMode(), RoundingMode.HALF_EVEN, + assertEquals(RoundingMode.HALF_EVEN, fmt.getRoundingMode(), "Default RoundingMode should be " + RoundingMode.HALF_EVEN); } - @Test(dataProvider = "roundingData") - public void testRounding(Object number, String[] expected) { + @ParameterizedTest + @MethodSource("roundingData") + void testRounding(Object number, String[] expected) { for (int index = 0; index < MODES.size(); index++) { testRoundingMode(number, expected[index], 0, MODES.get(index)); } } - @Test(dataProvider = "roundingFract") - public void testRoundingFract(Object number, String[] expected) { + @ParameterizedTest + @MethodSource("roundingFract") + void testRoundingFract(Object number, String[] expected) { for (int index = 0; index < MODES.size(); index++) { testRoundingMode(number, expected[index], 1, MODES.get(index)); } } - @Test(dataProvider = "rounding2Fract") - public void testRounding2Fract(Object number, String[] expected) { + @ParameterizedTest + @MethodSource("rounding2Fract") + void testRounding2Fract(Object number, String[] expected) { List rModes = List.of(RoundingMode.HALF_EVEN, RoundingMode.HALF_UP, RoundingMode.HALF_DOWN); for (int index = 0; index < rModes.size(); index++) { @@ -161,12 +170,12 @@ private void testRoundingMode(Object number, String expected, NumberFormat fmt = NumberFormat .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); fmt.setRoundingMode(rounding); - assertEquals(fmt.getRoundingMode(), rounding, + assertEquals(rounding, fmt.getRoundingMode(), "RoundingMode set is not returned by getRoundingMode"); fmt.setMinimumFractionDigits(fraction); String result = fmt.format(number); - assertEquals(result, expected, "Incorrect formatting of number " + assertEquals(expected, result, "Incorrect formatting of number " + number + " using rounding mode: " + rounding); } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestClone.java b/test/jdk/java/text/Format/CompactNumberFormat/TestClone.java new file mode 100644 index 00000000000..42abc1be2ba --- /dev/null +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestClone.java @@ -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. + */ +/* + * @test + * @bug 8368328 + * @summary Tests if CompactNumberFormat.clone() creates an independent object + * @run junit/othervm --add-opens java.base/java.text=ALL-UNNAMED TestClone + */ + +import java.lang.invoke.MethodHandles; +import java.text.CompactNumberFormat; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.util.Locale; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; + +public class TestClone { + // Concurrently parse numbers using cloned instances as originally + // reported in the bug. This test could produce false negative results, + // depending on the testing environment + @Test + void randomAccessTest() { + var original = + NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); + var threads = IntStream.range(0, 10) + .mapToObj(num -> new Thread(() -> { + var clone = (NumberFormat) original.clone(); + for (int i = 0; i < 1000; i++) { + assertDoesNotThrow(() -> + assertEquals(num, clone.parse(String.valueOf(num)).intValue())); + } + })).toList(); + threads.forEach(Thread::start); + threads.forEach(t -> { + try { + t.join(); + } catch (InterruptedException ie) { + throw new RuntimeException(ie); + } + }); + } + + private static Stream referenceFields() throws ClassNotFoundException { + return Stream.of( + Arguments.of("compactPatterns", String[].class), + Arguments.of("symbols", DecimalFormatSymbols.class), + Arguments.of("decimalFormat", DecimalFormat.class), + Arguments.of("defaultDecimalFormat", DecimalFormat.class), + Arguments.of("digitList", Class.forName("java.text.DigitList")) + ); + } + // Explicitly checks if the cloned object has its own references for + // "compactPatterns", "symbols", "decimalFormat", "defaultDecimalFormat", + // and "digitList" + @ParameterizedTest + @MethodSource("referenceFields") + void whiteBoxTest(String fieldName, Class type) throws Throwable { + var original = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); + var clone = original.clone(); + var lookup = MethodHandles.privateLookupIn(CompactNumberFormat.class, MethodHandles.lookup()); + + assertNotSame(lookup.findGetter(CompactNumberFormat.class, fieldName, type).invoke(original), + lookup.findGetter(CompactNumberFormat.class, fieldName, type).invoke(clone)); + } +} diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java index e9972f62f3e..b81226c00db 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java @@ -25,8 +25,14 @@ * @bug 8177552 8217721 8222756 8295372 8306116 8319990 8338690 8363972 * @summary Checks the functioning of compact number format * @modules jdk.localedata - * @run testng/othervm TestCompactNumber + * @run junit/othervm TestCompactNumber */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.math.BigDecimal; import java.math.BigInteger; import java.text.FieldPosition; @@ -36,10 +42,11 @@ import java.text.ParsePosition; import java.util.Locale; import java.util.stream.Stream; -import static org.testng.Assert.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestCompactNumber { private static final NumberFormat FORMAT_DZ_LONG = NumberFormat @@ -106,7 +113,6 @@ public class TestCompactNumber { FORMAT_PT_LONG_FD4.setMaximumFractionDigits(4); } - @DataProvider(name = "format") Object[][] compactFormatData() { return new Object[][]{ // compact number format instance, number to format, formatted output @@ -378,7 +384,6 @@ Object[][] compactFormatData() { }; } - @DataProvider(name = "parse") Object[][] compactParseData() { return new Object[][]{ // compact number format instance, string to parse, parsed number, return type @@ -491,7 +496,6 @@ Object[][] compactParseData() { }; } - @DataProvider(name = "exceptionParse") Object[][] exceptionParseData() { return new Object[][]{ // compact number instance, string to parse, null (no o/p; must throw exception) @@ -508,7 +512,6 @@ Object[][] exceptionParseData() { }; } - @DataProvider(name = "invalidParse") Object[][] invalidParseData() { return new Object[][]{ // compact number instance, string to parse, parsed number @@ -542,7 +545,6 @@ Object[][] invalidParseData() { }; } - @DataProvider(name = "fieldPosition") Object[][] formatFieldPositionData() { return new Object[][]{ //compact number instance, number to format, field, start position, end position, formatted string @@ -588,7 +590,6 @@ Object[][] formatFieldPositionData() { {FORMAT_SE_SHORT, new BigDecimal("-48982865901234567890.98"), NumberFormat.Field.INTEGER, 1, 9, "\u221248982866\u00a0bn"},}; } - @DataProvider(name = "varParsePosition") Object[][] varParsePosition() { return new Object[][]{ // compact number instance, parse string, parsed number, @@ -616,73 +617,82 @@ Object[][] varParsePosition() { } @Test - public void testInstanceCreation() { + void testInstanceCreation() { Stream.of(NumberFormat.getAvailableLocales()).forEach(l -> NumberFormat .getCompactNumberInstance(l, NumberFormat.Style.SHORT).format(10000)); Stream.of(NumberFormat.getAvailableLocales()).forEach(l -> NumberFormat .getCompactNumberInstance(l, NumberFormat.Style.LONG).format(10000)); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testFormatWithNullParam() { - FORMAT_EN_US_SHORT.format(null); + @Test + void testFormatWithNullParam() { + assertThrows(IllegalArgumentException.class, () -> { + FORMAT_EN_US_SHORT.format(null); + }); } - @Test(dataProvider = "format") - public void testFormat(NumberFormat cnf, Object number, + @ParameterizedTest + @MethodSource("compactFormatData") + void testFormat(NumberFormat cnf, Object number, String expected) { CompactFormatAndParseHelper.testFormat(cnf, number, expected); } - @Test(dataProvider = "parse") - public void testParse(NumberFormat cnf, String parseString, + @ParameterizedTest + @MethodSource("compactParseData") + void testParse(NumberFormat cnf, String parseString, Number expected, Class returnType) throws ParseException { CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, returnType); } - @Test(dataProvider = "parse") - public void testParsePosition(NumberFormat cnf, String parseString, + @ParameterizedTest + @MethodSource("compactParseData") + void testParsePosition(NumberFormat cnf, String parseString, Number expected, Class returnType) throws ParseException { ParsePosition pos = new ParsePosition(0); CompactFormatAndParseHelper.testParse(cnf, parseString, expected, pos, returnType); - assertEquals(pos.getIndex(), parseString.length()); - assertEquals(pos.getErrorIndex(), -1); + assertEquals(parseString.length(), pos.getIndex()); + assertEquals(-1, pos.getErrorIndex()); } - @Test(dataProvider = "varParsePosition") - public void testVarParsePosition(NumberFormat cnf, String parseString, + @ParameterizedTest + @MethodSource("varParsePosition") + void testVarParsePosition(NumberFormat cnf, String parseString, Number expected, int startPosition, int indexPosition, int errPosition) throws ParseException { ParsePosition pos = new ParsePosition(startPosition); CompactFormatAndParseHelper.testParse(cnf, parseString, expected, pos, null); - assertEquals(pos.getIndex(), indexPosition); - assertEquals(pos.getErrorIndex(), errPosition); + assertEquals(indexPosition, pos.getIndex()); + assertEquals(errPosition, pos.getErrorIndex()); } - @Test(dataProvider = "exceptionParse", expectedExceptions = ParseException.class) - public void throwsParseException(NumberFormat cnf, String parseString, - Number expected) throws ParseException { - CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, null); + @ParameterizedTest + @MethodSource("exceptionParseData") + void throwsParseException(NumberFormat cnf, String parseString, + Number expected) { + assertThrows(ParseException.class, () -> CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, null)); } - @Test(dataProvider = "invalidParse") - public void testInvalidParse(NumberFormat cnf, String parseString, + @ParameterizedTest + @MethodSource("invalidParseData") + void testInvalidParse(NumberFormat cnf, String parseString, Number expected) throws ParseException { CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, null); } - @Test(dataProvider = "fieldPosition") - public void testFormatWithFieldPosition(NumberFormat nf, + @ParameterizedTest + @MethodSource("formatFieldPositionData") + void testFormatWithFieldPosition(NumberFormat nf, Object number, Format.Field field, int posStartExpected, int posEndExpected, String expected) { FieldPosition pos = new FieldPosition(field); StringBuffer buf = new StringBuffer(); StringBuffer result = nf.format(number, buf, pos); - assertEquals(result.toString(), expected, "Incorrect formatting of the number '" + assertEquals(expected, result.toString(), "Incorrect formatting of the number '" + number + "'"); - assertEquals(pos.getBeginIndex(), posStartExpected, "Incorrect start position" + assertEquals(posStartExpected, pos.getBeginIndex(), "Incorrect start position" + " while formatting the number '" + number + "', for the field " + field); - assertEquals(pos.getEndIndex(), posEndExpected, "Incorrect end position" + assertEquals(posEndExpected, pos.getEndIndex(), "Incorrect end position" + " while formatting the number '" + number + "', for the field " + field); } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java index 8476b568ba0..1f8f1041e9e 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, 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 @@ -25,9 +25,13 @@ * @bug 8177552 8217254 8251499 8281317 * @summary Checks the validity of compact number patterns specified through * CompactNumberFormat constructor - * @run testng/othervm TestCompactPatternsValidity + * @run junit/othervm TestCompactPatternsValidity */ +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.math.BigDecimal; import java.math.BigInteger; import java.text.CompactNumberFormat; @@ -35,9 +39,10 @@ import java.text.ParseException; import java.util.List; import java.util.Locale; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestCompactPatternsValidity { // Max range 10^4 @@ -74,7 +79,6 @@ public class TestCompactPatternsValidity { private static final String[] COMPACT_PATTERN14 = new String[]{"", "", "", "{one:Kun other:0' 'Kun}"}; // from Somali in CLDR 38 - @DataProvider(name = "invalidPatterns") Object[][] invalidCompactPatterns() { return new Object[][] { // compact patterns @@ -90,7 +94,6 @@ Object[][] invalidCompactPatterns() { }; } - @DataProvider(name = "validPatternsFormat") Object[][] validPatternsFormat() { return new Object[][] { // compact patterns, numbers, expected output @@ -116,7 +119,6 @@ Object[][] validPatternsFormat() { }; } - @DataProvider(name = "validPatternsParse") Object[][] validPatternsParse() { return new Object[][] { // compact patterns, parse string, expected output @@ -136,7 +138,6 @@ Object[][] validPatternsParse() { }; } - @DataProvider(name = "validPatternsFormatWithPluralRules") Object[][] validPatternsFormatWithPluralRules() { return new Object[][] { // compact patterns, plural rules, numbers, expected output @@ -144,7 +145,6 @@ Object[][] validPatternsFormatWithPluralRules() { }; } - @DataProvider(name = "validPatternsParseWithPluralRules") Object[][] validPatternsParseWithPluralRules() { return new Object[][] { // compact patterns, plural rules, parse string, expected output @@ -152,15 +152,18 @@ Object[][] validPatternsParseWithPluralRules() { }; } - @Test(dataProvider = "invalidPatterns", - expectedExceptions = IllegalArgumentException.class) - public void testInvalidCompactPatterns(String[] compactPatterns) { - new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols - .getInstance(Locale.US), compactPatterns); + @ParameterizedTest + @MethodSource("invalidCompactPatterns") + void testInvalidCompactPatterns(String[] compactPatterns) { + assertThrows(IllegalArgumentException.class, () -> { + new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols + .getInstance(Locale.US), compactPatterns); + }); } - @Test(dataProvider = "validPatternsFormat") - public void testValidPatternsFormat(String[] compactPatterns, + @ParameterizedTest + @MethodSource("validPatternsFormat") + void testValidPatternsFormat(String[] compactPatterns, List numbers, List expected) { CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols.getInstance(Locale.US), compactPatterns); @@ -170,8 +173,9 @@ public void testValidPatternsFormat(String[] compactPatterns, } } - @Test(dataProvider = "validPatternsParse") - public void testValidPatternsParse(String[] compactPatterns, + @ParameterizedTest + @MethodSource("validPatternsParse") + void testValidPatternsParse(String[] compactPatterns, List parseString, List numbers) throws ParseException { CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols.getInstance(Locale.US), compactPatterns); @@ -181,8 +185,9 @@ public void testValidPatternsParse(String[] compactPatterns, } } - @Test(dataProvider = "validPatternsFormatWithPluralRules") - public void testValidPatternsFormatWithPluralRules(String[] compactPatterns, String pluralRules, + @ParameterizedTest + @MethodSource("validPatternsFormatWithPluralRules") + void testValidPatternsFormatWithPluralRules(String[] compactPatterns, String pluralRules, List numbers, List expected) { CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols.getInstance(Locale.US), compactPatterns, pluralRules); @@ -192,8 +197,9 @@ public void testValidPatternsFormatWithPluralRules(String[] compactPatterns, Str } } - @Test(dataProvider = "validPatternsParseWithPluralRules") - public void testValidPatternsParsewithPluralRules(String[] compactPatterns, String pluralRules, + @ParameterizedTest + @MethodSource("validPatternsParseWithPluralRules") + void testValidPatternsParsewithPluralRules(String[] compactPatterns, String pluralRules, List parseString, List numbers) throws ParseException { CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols.getInstance(Locale.US), compactPatterns, pluralRules); diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestEquality.java b/test/jdk/java/text/Format/CompactNumberFormat/TestEquality.java index 584f8c2c9bd..2ced18be171 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestEquality.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestEquality.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 @@ -20,25 +20,26 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 8222756 8327640 * @summary Checks the equals and hashCode method of CompactNumberFormat * @modules jdk.localedata - * @run testng/othervm TestEquality - * + * @run junit/othervm TestEquality */ +import org.junit.jupiter.api.Test; + import java.text.CompactNumberFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.util.Locale; -import org.testng.annotations.Test; public class TestEquality { @Test - public void testEquality() { + void testEquality() { CompactNumberFormat cnf1 = (CompactNumberFormat) NumberFormat .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); @@ -160,7 +161,7 @@ private void checkEquals(CompactNumberFormat cnf1, CompactNumberFormat cnf2, } @Test - public void testHashCode() { + void testHashCode() { NumberFormat cnf1 = NumberFormat .getCompactNumberInstance(Locale.JAPAN, NumberFormat.Style.SHORT); NumberFormat cnf2 = NumberFormat @@ -175,7 +176,7 @@ public void testHashCode() { // Test the property of equals and hashCode i.e. two equal object must // always have the same hashCode @Test - public void testEqualsAndHashCode() { + void testEqualsAndHashCode() { NumberFormat cnf1 = NumberFormat .getCompactNumberInstance(Locale.of("hi", "IN"), NumberFormat.Style.SHORT); cnf1.setMinimumIntegerDigits(5); diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestFormatToCharacterIterator.java b/test/jdk/java/text/Format/CompactNumberFormat/TestFormatToCharacterIterator.java index fb18fa256ab..beb6c38aca8 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestFormatToCharacterIterator.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestFormatToCharacterIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, 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 @@ -20,14 +20,20 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 * @summary Checks the functioning of * CompactNumberFormat.formatToCharacterIterator method * @modules jdk.localedata - * @run testng/othervm TestFormatToCharacterIterator + * @run junit/othervm TestFormatToCharacterIterator */ + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.math.BigDecimal; import java.math.BigInteger; import java.text.AttributedCharacterIterator; @@ -36,10 +42,10 @@ import java.text.NumberFormat; import java.util.Locale; import java.util.Set; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestFormatToCharacterIterator { private static final NumberFormat FORMAT_DZ = NumberFormat @@ -54,7 +60,6 @@ public class TestFormatToCharacterIterator { .getCompactNumberInstance(Locale.ENGLISH, NumberFormat.Style.LONG); - @DataProvider(name = "fieldPositions") Object[][] compactFieldPositionData() { return new Object[][]{ // compact format instance, number, resulted string, attributes/fields, attribute positions @@ -149,22 +154,23 @@ Object[][] compactFieldPositionData() { }; } - @Test(dataProvider = "fieldPositions") - public void testFormatToCharacterIterator(NumberFormat fmt, Object number, + @ParameterizedTest + @MethodSource("compactFieldPositionData") + void testFormatToCharacterIterator(NumberFormat fmt, Object number, String expected, Format.Field[] expectedFields, int[] positions) { AttributedCharacterIterator iterator = fmt.formatToCharacterIterator(number); - assertEquals(getText(iterator), expected, "Incorrect formatting of the number '" + assertEquals(expected, getText(iterator), "Incorrect formatting of the number '" + number + "'"); iterator.first(); // Check start and end index of the formatted string - assertEquals(iterator.getBeginIndex(), 0, "Incorrect start index: " + assertEquals(0, iterator.getBeginIndex(), "Incorrect start index: " + iterator.getBeginIndex() + " of the formatted string: " + expected); - assertEquals(iterator.getEndIndex(), expected.length(), "Incorrect end index: " + assertEquals(expected.length(), iterator.getEndIndex(), "Incorrect end index: " + iterator.getEndIndex() + " of the formatted string: " + expected); // Check the attributes returned by the formatToCharacterIterator - assertEquals(iterator.getAllAttributeKeys(), Set.of(expectedFields), + assertEquals(Set.of(expectedFields), iterator.getAllAttributeKeys(), "Attributes do not match while formatting number: " + number); // Check the begin and end index for attributes @@ -173,10 +179,10 @@ public void testFormatToCharacterIterator(NumberFormat fmt, Object number, do { int start = iterator.getRunStart(); int end = iterator.getRunLimit(); - assertEquals(start, positions[currentPosition], + assertEquals(positions[currentPosition], start, "Incorrect start position for the attribute(s): " + iterator.getAttributes().keySet()); - assertEquals(end, positions[currentPosition + 1], + assertEquals(positions[currentPosition + 1], end, "Incorrect end position for the attribute(s): " + iterator.getAttributes().keySet()); currentPosition = currentPosition + 2; diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestMutatingInstance.java b/test/jdk/java/text/Format/CompactNumberFormat/TestMutatingInstance.java index 47b176692fd..4cf5ce12f16 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestMutatingInstance.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestMutatingInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, 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 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 @@ -27,8 +28,14 @@ * formatting parameters. For example, min fraction digits, grouping * size etc. * @modules jdk.localedata - * @run testng/othervm TestMutatingInstance + * @run junit/othervm TestMutatingInstance */ + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.math.BigDecimal; import java.math.BigInteger; import java.text.CompactNumberFormat; @@ -36,10 +43,8 @@ import java.text.NumberFormat; import java.text.ParseException; import java.util.Locale; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestMutatingInstance { private static final NumberFormat FORMAT_FRACTION = NumberFormat @@ -61,8 +66,8 @@ public class TestMutatingInstance { "#,##0.0#", DecimalFormatSymbols.getInstance(Locale.US), new String[]{"", "", "", "", "00K", "", "", "", "", "", "", "", "", "", ""}); - @BeforeTest - public void mutateInstances() { + @BeforeAll + void mutateInstances() { FORMAT_FRACTION.setMinimumFractionDigits(2); FORMAT_GROUPING.setGroupingSize(3); FORMAT_GROUPING.setGroupingUsed(true); @@ -75,7 +80,6 @@ public void mutateInstances() { FORMAT_NO_PATTERNS.setMinimumFractionDigits(2); } - @DataProvider(name = "format") Object[][] compactFormatData() { return new Object[][]{ {FORMAT_FRACTION, 1900, "1.90 thousand"}, @@ -95,7 +99,6 @@ Object[][] compactFormatData() { {FORMAT_NO_PATTERNS, new BigDecimal(12346567890987654.32), "12,346,567,890,987,654"},}; } - @DataProvider(name = "parse") Object[][] compactParseData() { return new Object[][]{ {FORMAT_FRACTION, "190 thousand", 190000L}, @@ -106,14 +109,16 @@ Object[][] compactParseData() { {FORMAT_PARSEINTONLY, "12.345 thousand", 12000L},}; } - @Test(dataProvider = "format") - public void formatCompactNumber(NumberFormat nf, + @ParameterizedTest + @MethodSource("compactFormatData") + void formatCompactNumber(NumberFormat nf, Object number, String expected) { CompactFormatAndParseHelper.testFormat(nf, number, expected); } - @Test(dataProvider = "parse") - public void parseCompactNumber(NumberFormat nf, + @ParameterizedTest + @MethodSource("compactParseData") + void parseCompactNumber(NumberFormat nf, String parseString, Number expected) throws ParseException { CompactFormatAndParseHelper.testParse(nf, parseString, expected, null, null); } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestParseBigDecimal.java b/test/jdk/java/text/Format/CompactNumberFormat/TestParseBigDecimal.java index dc88ce4de4a..422ced9d999 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestParseBigDecimal.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestParseBigDecimal.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 @@ -20,17 +20,19 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 8306116 8319990 * @summary Checks CNF.parse() when parseBigDecimal is set to true * @modules jdk.localedata - * @run testng/othervm TestParseBigDecimal + * @run junit/othervm TestParseBigDecimal */ -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import java.math.BigDecimal; import java.text.CompactNumberFormat; @@ -38,6 +40,7 @@ import java.text.ParseException; import java.util.Locale; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestParseBigDecimal { private static final CompactNumberFormat FORMAT_DZ_LONG = (CompactNumberFormat) NumberFormat @@ -64,8 +67,8 @@ public class TestParseBigDecimal { private static final CompactNumberFormat FORMAT_SE_SHORT = (CompactNumberFormat) NumberFormat .getCompactNumberInstance(Locale.of("se"), NumberFormat.Style.SHORT); - @BeforeTest - public void mutateInstances() { + @BeforeAll + void mutateInstances() { FORMAT_DZ_LONG.setParseBigDecimal(true); FORMAT_EN_US_SHORT.setParseBigDecimal(true); FORMAT_EN_LONG.setParseBigDecimal(true); @@ -76,7 +79,6 @@ public void mutateInstances() { FORMAT_SE_SHORT.setParseBigDecimal(true); } - @DataProvider(name = "parse") Object[][] compactParseData() { return new Object[][]{ // compact number format instance, string to parse, parsed number @@ -165,8 +167,9 @@ Object[][] compactParseData() { {FORMAT_SE_SHORT, "\u221212345679,89\u00a0bn", new BigDecimal("-12345679890000000000.00")},}; } - @Test(dataProvider = "parse") - public void testParse(NumberFormat cnf, String parseString, + @ParameterizedTest + @MethodSource("compactParseData") + void testParse(NumberFormat cnf, String parseString, Number expected) throws ParseException { CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, BigDecimal.class); } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestPlurals.java b/test/jdk/java/text/Format/CompactNumberFormat/TestPlurals.java index bbaaa701d23..b8beb6135dd 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestPlurals.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestPlurals.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 @@ -20,21 +20,27 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8222756 * @summary Tests plurals support in CompactNumberFormat - * @run testng/othervm TestPlurals + * @run junit/othervm TestPlurals */ +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.CompactNumberFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; -import static org.testng.Assert.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestPlurals { private final static DecimalFormatSymbols DFS = DecimalFormatSymbols.getInstance(Locale.ROOT); @@ -45,7 +51,6 @@ public class TestPlurals { private final static String RULE_3 = "one:n%2=0andn/3=2;"; - @DataProvider Object[][] pluralRules() { return new Object[][]{ // rules, number, expected @@ -78,7 +83,6 @@ Object[][] pluralRules() { }; } - @DataProvider Object[][] invalidRules() { return new Object [][] { {"one:a = 1"}, @@ -92,27 +96,34 @@ Object[][] invalidRules() { }; } - @Test(expectedExceptions = NullPointerException.class) - public void testNullPluralRules() { - String[] pattern = {""}; - new CompactNumberFormat("#", DFS, PATTERN, null); + @Test + void testNullPluralRules() { + assertThrows(NullPointerException.class, () -> { + String[] pattern = {""}; + new CompactNumberFormat("#", DFS, PATTERN, null); + }); } - @Test(dataProvider = "pluralRules") - public void testPluralRules(String rules, Number n, String expected) { + @ParameterizedTest + @MethodSource("pluralRules") + void testPluralRules(String rules, Number n, String expected) { var cnp = new CompactNumberFormat("#", DFS, PATTERN, rules); - assertEquals(cnp.format(n), expected); + assertEquals(expected, cnp.format(n)); } - @Test(dataProvider = "invalidRules", expectedExceptions = IllegalArgumentException.class) - public void testInvalidRules(String rules) { - new CompactNumberFormat("#", DFS, PATTERN, rules); + @ParameterizedTest + @MethodSource("invalidRules") + void testInvalidRules(String rules) { + assertThrows(IllegalArgumentException.class, + () -> new CompactNumberFormat("#", DFS, PATTERN, rules)); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testLimitExceedingRules() { - String andCond = " and n = 1"; - String invalid = "one: n = 1" + andCond.repeat(2_048 / andCond.length()); - new CompactNumberFormat("#", DFS, PATTERN, invalid); + @Test + void testLimitExceedingRules() { + assertThrows(IllegalArgumentException.class, () -> { + String andCond = " and n = 1"; + String invalid = "one: n = 1" + andCond.repeat(2_048 / andCond.length()); + new CompactNumberFormat("#", DFS, PATTERN, invalid); + }); } } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestSpecialValues.java b/test/jdk/java/text/Format/CompactNumberFormat/TestSpecialValues.java index e8ac2489faf..9bd0ef73830 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestSpecialValues.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestSpecialValues.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 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 @@ -20,25 +20,29 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 * @summary Checks the formatting and parsing of special values * @modules jdk.localedata - * @run testng/othervm TestSpecialValues + * @run junit/othervm TestSpecialValues */ + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.NumberFormat; import java.text.ParseException; import java.util.Locale; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestSpecialValues { private static final NumberFormat FORMAT = NumberFormat .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); - @DataProvider(name = "formatSpecialValues") Object[][] formatSpecialValues() { return new Object[][]{ // number , formatted ouput @@ -53,7 +57,6 @@ Object[][] formatSpecialValues() { {Long.MAX_VALUE, "9223372T"},}; } - @DataProvider(name = "parseSpecialValues") Object[][] parseSpecialValues() { return new Object[][]{ // parse string, parsed number @@ -65,13 +68,15 @@ Object[][] parseSpecialValues() { {"-\u221E", Double.NEGATIVE_INFINITY},}; } - @Test(dataProvider = "formatSpecialValues") - public void testFormatSpecialValues(Object number, String expected) { + @ParameterizedTest + @MethodSource("formatSpecialValues") + void testFormatSpecialValues(Object number, String expected) { CompactFormatAndParseHelper.testFormat(FORMAT, number, expected); } - @Test(dataProvider = "parseSpecialValues") - public void testParseSpecialValues(String parseString, Number expected) + @ParameterizedTest + @MethodSource("parseSpecialValues") + void testParseSpecialValues(String parseString, Number expected) throws ParseException { CompactFormatAndParseHelper.testParse(FORMAT, parseString, expected, null, null); } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestUExtensionOverride.java b/test/jdk/java/text/Format/CompactNumberFormat/TestUExtensionOverride.java index 099e6978b0b..f77908d84c4 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestUExtensionOverride.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestUExtensionOverride.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, 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 @@ -20,23 +20,27 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 8221432 * @summary Checks the behaviour of Unicode BCP 47 U Extension with * compact number format * @modules jdk.localedata - * @run testng/othervm TestUExtensionOverride + * @run junit/othervm TestUExtensionOverride */ + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.NumberFormat; import java.text.ParseException; import java.util.Locale; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestUExtensionOverride { - @DataProvider(name = "compactFormatData") Object[][] compactFormatData() { return new Object[][]{ // locale, number, formatted string @@ -61,7 +65,6 @@ Object[][] compactFormatData() { "\u0967\u0968\u00a0k"},}; } - @DataProvider(name = "compactParseData") Object[][] compactParseData() { return new Object[][]{ // locale, parse string, parsed number @@ -87,16 +90,18 @@ Object[][] compactParseData() { "\u0967\u0968\u00a0k", 12000L},}; } - @Test(dataProvider = "compactFormatData") - public void testFormat(Locale locale, double num, + @ParameterizedTest + @MethodSource("compactFormatData") + void testFormat(Locale locale, double num, String expected) { NumberFormat cnf = NumberFormat.getCompactNumberInstance(locale, NumberFormat.Style.SHORT); CompactFormatAndParseHelper.testFormat(cnf, num, expected); } - @Test(dataProvider = "compactParseData") - public void testParse(Locale locale, String parseString, + @ParameterizedTest + @MethodSource("compactParseData") + void testParse(Locale locale, String parseString, Number expected) throws ParseException { NumberFormat cnf = NumberFormat.getCompactNumberInstance(locale, NumberFormat.Style.SHORT); diff --git a/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestDeserializeCNF.java b/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestDeserializeCNF.java index 0b4710f0086..563ae307762 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestDeserializeCNF.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestDeserializeCNF.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 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 @@ -28,11 +28,12 @@ * @summary Checks deserialization of compact number format * @library /java/text/testlib * @build TestDeserializeCNF HexDumpReader - * @run testng/othervm TestDeserializeCNF + * @run junit/othervm TestDeserializeCNF */ -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import java.io.IOException; import java.io.InputStream; @@ -41,8 +42,10 @@ import java.text.CompactNumberFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestDeserializeCNF { // This object is serialized in cnf1.ser.txt with HALF_UP @@ -60,8 +63,8 @@ public class TestDeserializeCNF { private static final String FILE_COMPACT_FORMAT1 = "cnf1.ser.txt"; private static final String FILE_COMPACT_FORMAT2 = "cnf2.ser.txt"; - @BeforeTest - public void mutateInstances() { + @BeforeAll + void mutateInstances() { COMPACT_FORMAT1.setRoundingMode(RoundingMode.HALF_UP); COMPACT_FORMAT1.setGroupingSize(3); COMPACT_FORMAT1.setParseBigDecimal(true); @@ -71,18 +74,18 @@ public void mutateInstances() { } @Test - public void testDeserialization() throws IOException, ClassNotFoundException { + void testDeserialization() throws IOException, ClassNotFoundException { try (InputStream istream1 = HexDumpReader.getStreamFromHexDump(FILE_COMPACT_FORMAT1); ObjectInputStream ois1 = new ObjectInputStream(istream1); InputStream istream2 = HexDumpReader.getStreamFromHexDump(FILE_COMPACT_FORMAT2); ObjectInputStream ois2 = new ObjectInputStream(istream2);) { CompactNumberFormat obj1 = (CompactNumberFormat) ois1.readObject(); - assertEquals(obj1, COMPACT_FORMAT1, "Deserialized instance is not" + assertEquals(COMPACT_FORMAT1, obj1, "Deserialized instance is not" + " equal to the instance serialized in " + FILE_COMPACT_FORMAT1); CompactNumberFormat obj2 = (CompactNumberFormat) ois2.readObject(); - assertEquals(obj2, COMPACT_FORMAT2, "Deserialized instance is not" + assertEquals(COMPACT_FORMAT2, obj2, "Deserialized instance is not" + " equal to the instance serialized in " + FILE_COMPACT_FORMAT2); } } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestSerialization.java b/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestSerialization.java index 574e6dc7905..b3a8cbadc76 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestSerialization.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestSerialization.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 @@ -20,16 +20,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 8327640 * @modules jdk.localedata * @summary Checks the serialization feature of CompactNumberFormat - * @run testng/othervm TestSerialization + * @run junit/othervm TestSerialization */ -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -40,8 +42,10 @@ import java.text.CompactNumberFormat; import java.text.NumberFormat; import java.util.Locale; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestSerialization { private static final NumberFormat FORMAT_HI = NumberFormat.getCompactNumberInstance( @@ -57,8 +61,8 @@ public class TestSerialization { private static final NumberFormat FORMAT_KO_KR = NumberFormat.getCompactNumberInstance( Locale.KOREA, NumberFormat.Style.SHORT); - @BeforeTest - public void mutateInstances() { + @BeforeAll + void mutateInstances() { FORMAT_HI.setMinimumFractionDigits(2); FORMAT_HI.setMinimumIntegerDigits(5); @@ -81,7 +85,7 @@ public void mutateInstances() { } @Test - public void testSerialization() throws IOException, ClassNotFoundException { + void testSerialization() throws IOException, ClassNotFoundException { // Serialize serialize("cdf.ser", FORMAT_HI, FORMAT_EN_US, FORMAT_JA_JP, FORMAT_FR_FR, FORMAT_DE_DE, FORMAT_KO_KR); // Deserialize @@ -104,13 +108,13 @@ private static void deserialize(String fileName, NumberFormat... formats) new FileInputStream(fileName))) { for (NumberFormat fmt : formats) { NumberFormat obj = (NumberFormat) os.readObject(); - assertEquals(fmt, obj, "Serialized and deserialized" + assertEquals(obj, fmt, "Serialized and deserialized" + " objects do not match"); long number = 123456789789L; String expected = fmt.format(number); String actual = obj.format(number); - assertEquals(actual, expected, "Serialized and deserialized" + assertEquals(expected, actual, "Serialized and deserialized" + " objects are expected to return same formatted" + " output for number: " + number); } diff --git a/test/jdk/java/text/Format/DateFormat/Bug8193444.java b/test/jdk/java/text/Format/DateFormat/Bug8193444.java index 6c5007bc851..b2fac85dd8a 100644 --- a/test/jdk/java/text/Format/DateFormat/Bug8193444.java +++ b/test/jdk/java/text/Format/DateFormat/Bug8193444.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 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 @@ -20,29 +20,32 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8193444 * @summary Checks SimpleDateFormat.format/parse for the AIOOB exception when * formatting/parsing dates through a pattern string that contains a * sequence of 256 or more non-ASCII unicode characters. - * @run testng/othervm Bug8193444 + * @run junit/othervm Bug8193444 */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class Bug8193444 { private static final String NON_ASCII_CHAR = "\u263A"; - @DataProvider(name = "dateFormat") Object[][] dateFormatData() { return new Object[][]{ // short_length (between 0 and 254) @@ -53,8 +56,9 @@ Object[][] dateFormatData() { {257},}; } - @Test(dataProvider = "dateFormat") - public void testDateFormatAndParse(int length) + @ParameterizedTest + @MethodSource("dateFormatData") + void testDateFormatAndParse(int length) throws ParseException { String pattern = NON_ASCII_CHAR.repeat(length); @@ -66,7 +70,7 @@ public void testDateFormatAndParse(int length) // Since the tested format patterns do not contain any character // representing date/time field, those characters are not interpreted, // they are simply copied into the output string during formatting - assertEquals(result, pattern, "Failed to format the date using" + assertEquals(pattern, result, "Failed to format the date using" + " pattern of length: " + length); // The format pattern used by this SimpleDateFormat diff --git a/test/jdk/java/text/Format/DateFormat/CaseInsensitiveParseTest.java b/test/jdk/java/text/Format/DateFormat/CaseInsensitiveParseTest.java index 2331e36b2f9..51473710dbb 100644 --- a/test/jdk/java/text/Format/DateFormat/CaseInsensitiveParseTest.java +++ b/test/jdk/java/text/Format/DateFormat/CaseInsensitiveParseTest.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 @@ -21,14 +21,18 @@ * questions. */ -/** +/* * @test * @bug 8248434 * @modules jdk.localedata - * @run testng/othervm CaseInsensitiveParseTest * @summary Checks format/parse round trip in case-insensitive manner. + * @run junit/othervm CaseInsensitiveParseTest */ +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -37,36 +41,36 @@ import java.util.Locale; import java.util.stream.Stream; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class CaseInsensitiveParseTest { private final static String PATTERN = "GGGG/yyyy/MMMM/dddd/hhhh/mmmm/ss/aaaa"; private final static Date EPOCH = new Date(0L); - @DataProvider - private Object[][] locales() { + Object[][] locales() { return (Object[][])Arrays.stream(DateFormat.getAvailableLocales()) .map(Stream::of) .map(Stream::toArray) .toArray(Object[][]::new); } - @Test(dataProvider = "locales") - public void testUpperCase(Locale loc) throws ParseException { + @ParameterizedTest + @MethodSource("locales") + void testUpperCase(Locale loc) throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat(PATTERN, loc); String formatted = sdf.format(EPOCH); - assertEquals(sdf.parse(formatted.toUpperCase(Locale.ROOT)), EPOCH, + assertEquals(EPOCH, sdf.parse(formatted.toUpperCase(Locale.ROOT)), "roundtrip failed for string '" + formatted + "', locale: " + loc); } - @Test(dataProvider = "locales") - public void testLowerCase(Locale loc) throws ParseException { + @ParameterizedTest + @MethodSource("locales") + void testLowerCase(Locale loc) throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat(PATTERN, loc); String formatted = sdf.format(EPOCH); - assertEquals(sdf.parse(formatted.toLowerCase(Locale.ROOT)), EPOCH, + assertEquals(EPOCH, sdf.parse(formatted.toLowerCase(Locale.ROOT)), "roundtrip failed for string '" + formatted + "', locale: " + loc); } } diff --git a/test/jdk/java/text/Format/DateFormat/LocaleDateFormats.java b/test/jdk/java/text/Format/DateFormat/LocaleDateFormats.java index f5ebdccb91f..6ddddb2058d 100644 --- a/test/jdk/java/text/Format/DateFormat/LocaleDateFormats.java +++ b/test/jdk/java/text/Format/DateFormat/LocaleDateFormats.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 @@ -21,34 +21,38 @@ * questions. */ -/** +/* * @test * @bug 8080774 8174269 * @modules jdk.localedata - * @run testng LocaleDateFormats * @summary This file contains tests for JRE locales date formats + * @run junit LocaleDateFormats */ +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.DateFormat; import java.util.Calendar; import java.util.Locale; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class LocaleDateFormats { - @Test(dataProvider = "dateFormats") - public void testDateFormat(Locale loc, int style, int year, int month, int date, String expectedString) { + @ParameterizedTest + @MethodSource("dateFormats") + void testDateFormat(Locale loc, int style, int year, int month, int date, String expectedString) { Calendar cal = Calendar.getInstance(loc); cal.set(year, month-1, date); // Create date formatter based on requested style and test locale DateFormat df = DateFormat.getDateInstance(style, loc); // Test the date format - assertEquals(df.format(cal.getTime()), expectedString); + assertEquals(expectedString, df.format(cal.getTime())); } - @DataProvider(name = "dateFormats" ) private Object[][] dateFormats() { return new Object[][] { //8080774 diff --git a/test/jdk/java/text/Format/DateFormat/SimpleDateFormatPatternTest.java b/test/jdk/java/text/Format/DateFormat/SimpleDateFormatPatternTest.java index bcf0022b092..e8ff262e0ab 100644 --- a/test/jdk/java/text/Format/DateFormat/SimpleDateFormatPatternTest.java +++ b/test/jdk/java/text/Format/DateFormat/SimpleDateFormatPatternTest.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 @@ -21,21 +21,25 @@ * questions. */ -/** +/* * @test * @bug 4326988 6990146 8231213 * @summary test SimpleDateFormat, check its pattern in the constructor - * @run testng/othervm SimpleDateFormatPatternTest + * @run junit/othervm SimpleDateFormatPatternTest */ -import java.lang.IllegalArgumentException; + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.DateFormat; import java.text.DateFormatSymbols; import java.text.SimpleDateFormat; import java.util.Locale; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SimpleDateFormatPatternTest { private static String[] validPat = { "yyyy-MM-dd h.mm.ss.a z", @@ -136,90 +140,104 @@ private static Object[][] createPatternObj(String[] pattern){ return objArray; } - @DataProvider(name = "dfAllLocalesObj") Object[][] dfAllLocalesObj() { return dfAllLocalesObj; } - @DataProvider(name = "invalidPatternObj") Object[][] invalidPatternObj() { return invalidPatObj; } - @DataProvider(name = "validPatternObj") Object[][] validPatternObj() { return validPatObj; } //check Constructors for invalid pattern - @Test(dataProvider = "invalidPatternObj", - expectedExceptions = IllegalArgumentException.class) - public void testIllegalArgumentException1(String pattern, Locale loc) + @ParameterizedTest + @MethodSource("invalidPatternObj") + void testIllegalArgumentException1(String pattern, Locale loc) throws IllegalArgumentException { - Locale.setDefault(loc); - new SimpleDateFormat(pattern); + assertThrows(IllegalArgumentException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat(pattern); + }); } - @Test(dataProvider = "invalidPatternObj", - expectedExceptions = IllegalArgumentException.class) - public void testIllegalArgumentException2(String pattern, Locale loc) + @ParameterizedTest + @MethodSource("invalidPatternObj") + void testIllegalArgumentException2(String pattern, Locale loc) throws IllegalArgumentException { - Locale.setDefault(loc); - new SimpleDateFormat(pattern, new DateFormatSymbols()); + assertThrows(IllegalArgumentException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat(pattern, new DateFormatSymbols()); + }); } - @Test(dataProvider = "invalidPatternObj", - expectedExceptions = IllegalArgumentException.class) - public void testIllegalArgumentException3 (String pattern, Locale loc) + @ParameterizedTest + @MethodSource("invalidPatternObj") + void testIllegalArgumentException3 (String pattern, Locale loc) throws IllegalArgumentException { - Locale.setDefault(loc); - new SimpleDateFormat(pattern, Locale.getDefault()); + assertThrows(IllegalArgumentException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat(pattern, Locale.getDefault()); + }); } - @Test(dataProvider = "invalidPatternObj", - expectedExceptions = IllegalArgumentException.class) - public void testIllegalArgumentException4(String pattern, Locale loc) + @ParameterizedTest + @MethodSource("invalidPatternObj") + void testIllegalArgumentException4(String pattern, Locale loc) throws IllegalArgumentException { - Locale.setDefault(loc); - new SimpleDateFormat().applyPattern(pattern); + assertThrows(IllegalArgumentException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat().applyPattern(pattern); + }); } //check Constructors for null pattern - @Test(dataProvider = "dfAllLocalesObj", - expectedExceptions = NullPointerException.class) - public void testNullPointerException1(Locale loc) + @ParameterizedTest + @MethodSource("dfAllLocalesObj") + void testNullPointerException1(Locale loc) throws NullPointerException { - Locale.setDefault(loc); - new SimpleDateFormat(null); + assertThrows(NullPointerException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat(null); + }); } - @Test(dataProvider = "dfAllLocalesObj", - expectedExceptions = NullPointerException.class) - public void testNullPointerException2(Locale loc) + @ParameterizedTest + @MethodSource("dfAllLocalesObj") + void testNullPointerException2(Locale loc) throws NullPointerException { - Locale.setDefault(loc); - new SimpleDateFormat(null, new DateFormatSymbols()); + assertThrows(NullPointerException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat(null, new DateFormatSymbols()); + }); } - @Test(dataProvider = "dfAllLocalesObj", - expectedExceptions = NullPointerException.class) - public void testNullPointerException3(Locale loc) + @ParameterizedTest + @MethodSource("dfAllLocalesObj") + void testNullPointerException3(Locale loc) throws NullPointerException { - Locale.setDefault(loc); - new SimpleDateFormat(null, Locale.getDefault()); + assertThrows(NullPointerException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat(null, Locale.getDefault()); + }); } - @Test(dataProvider = "dfAllLocalesObj", - expectedExceptions = NullPointerException.class) - public void testNullPointerException4(Locale loc) + @ParameterizedTest + @MethodSource("dfAllLocalesObj") + void testNullPointerException4(Locale loc) throws NullPointerException { - Locale.setDefault(loc); - new SimpleDateFormat().applyPattern(null); + assertThrows(NullPointerException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat().applyPattern(null); + }); } - @Test(dataProvider = "validPatternObj") + @ParameterizedTest //check Constructors for valid pattern - public void testValidPattern(String pattern, Locale loc) { + @MethodSource("validPatternObj") + void testValidPattern(String pattern, Locale loc) { Locale.setDefault(loc); new SimpleDateFormat(pattern); new SimpleDateFormat(pattern, new DateFormatSymbols()); diff --git a/test/jdk/java/text/Format/DecimalFormat/CloneTest.java b/test/jdk/java/text/Format/DecimalFormat/CloneTest.java index f11d576a39a..dabdd137f5f 100644 --- a/test/jdk/java/text/Format/DecimalFormat/CloneTest.java +++ b/test/jdk/java/text/Format/DecimalFormat/CloneTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8354522 8358880 + * @bug 8354522 8358880 8367324 * @summary Check for cloning interference * @library /test/lib * @run junit/othervm --add-opens=java.base/java.text=ALL-UNNAMED CloneTest @@ -89,12 +89,6 @@ public void testClone() { Object digits = valFromDigitList(original, "digits"); assertNotSame(digits, valFromDigitList(dfClone, "digits")); - - Object data = valFromDigitList(original, "data"); - if (data != null) { - assertNotSame(data, valFromDigitList(dfClone, "data")); - } - assertEquals(digitListField.get(original), digitListField.get(dfClone)); } catch (ReflectiveOperationException e) { throw new SkippedException("reflective access in white-box test failed", e); diff --git a/test/jdk/java/text/Format/DecimalFormat/SetGroupingSizeTest.java b/test/jdk/java/text/Format/DecimalFormat/SetGroupingSizeTest.java index 07982b453c9..95044341290 100644 --- a/test/jdk/java/text/Format/DecimalFormat/SetGroupingSizeTest.java +++ b/test/jdk/java/text/Format/DecimalFormat/SetGroupingSizeTest.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 @@ -26,28 +26,27 @@ * @bug 8212749 * @summary test whether input value check for * DecimalFormat.setGroupingSize(int) works correctly. - * @run testng/othervm SetGroupingSizeTest + * @run junit/othervm SetGroupingSizeTest */ +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.DecimalFormat; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; -@Test public class SetGroupingSizeTest { - @DataProvider - public static Object[][] validGroupingSizes() { + static Object[][] validGroupingSizes() { return new Object[][] { { 0 }, { Byte.MAX_VALUE }, }; } - @DataProvider - public static Object[][] invalidGroupingSizes() { + static Object[][] invalidGroupingSizes() { return new Object[][] { { Byte.MIN_VALUE - 1 }, { Byte.MIN_VALUE }, @@ -58,17 +57,20 @@ public static Object[][] invalidGroupingSizes() { }; } - @Test(dataProvider = "validGroupingSizes") - public void test_validGroupingSize(int newVal) { + @ParameterizedTest + @MethodSource("validGroupingSizes") + void test_validGroupingSize(int newVal) { DecimalFormat df = new DecimalFormat(); df.setGroupingSize(newVal); - assertEquals(df.getGroupingSize(), newVal); + assertEquals(newVal, df.getGroupingSize()); } - @Test(dataProvider = "invalidGroupingSizes", - expectedExceptions = IllegalArgumentException.class) - public void test_invalidGroupingSize(int newVal) { - DecimalFormat df = new DecimalFormat(); - df.setGroupingSize(newVal); + @ParameterizedTest + @MethodSource("invalidGroupingSizes") + void test_invalidGroupingSize(int newVal) { + assertThrows(IllegalArgumentException.class, () -> { + DecimalFormat df = new DecimalFormat(); + df.setGroupingSize(newVal); + }); } } diff --git a/test/jdk/java/text/Format/NumberFormat/DFSMinusPerCentMill.java b/test/jdk/java/text/Format/NumberFormat/DFSMinusPerCentMill.java index a36eaf5f14f..418802261ff 100644 --- a/test/jdk/java/text/Format/NumberFormat/DFSMinusPerCentMill.java +++ b/test/jdk/java/text/Format/NumberFormat/DFSMinusPerCentMill.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 @@ -21,7 +21,7 @@ * questions. */ -/** +/* * @test * @bug 8220309 8230284 * @library /java/text/testlib @@ -29,17 +29,26 @@ * This test assumes CLDR has numbering systems for "arab" and * "arabext", and their minus/percent representations include * BiDi formatting control characters. - * @run testng/othervm DFSMinusPerCentMill + * @run junit/othervm DFSMinusPerCentMill */ -import java.io.*; -import java.util.*; -import java.text.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.util.Locale; -import static org.testng.Assert.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class DFSMinusPerCentMill { private enum Type { NUMBER, PERCENT, CURRENCY, INTEGER, COMPACT, PERMILL @@ -49,7 +58,6 @@ private enum Type { private static final Locale US_ARABEXT = Locale.forLanguageTag("en-US-u-nu-arabext"); private static final double SRC_NUM = -1234.56; - @DataProvider Object[][] formatData() { return new Object[][] { // Locale, FormatStyle, expected format, expected single char symbol @@ -69,7 +77,6 @@ Object[][] formatData() { }; } - @DataProvider Object[][] charSymbols() { return new Object[][]{ // Locale, percent, per mille, minus sign @@ -78,8 +85,9 @@ Object[][] charSymbols() { }; } - @Test(dataProvider="formatData") - public void testFormatData(Locale l, Type style, String expected) { + @ParameterizedTest + @MethodSource("formatData") + void testFormatData(Locale l, Type style, String expected) { NumberFormat nf = null; switch (style) { case NUMBER: @@ -102,19 +110,20 @@ public void testFormatData(Locale l, Type style, String expected) { break; } - assertEquals(nf.format(SRC_NUM), expected); + assertEquals(expected, nf.format(SRC_NUM)); } - @Test(dataProvider="charSymbols") - public void testCharSymbols(Locale l, char percent, char permill, char minus) { + @ParameterizedTest + @MethodSource("charSymbols") + void testCharSymbols(Locale l, char percent, char permill, char minus) { DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); - assertEquals(dfs.getPercent(), percent); - assertEquals(dfs.getPerMill(), permill); - assertEquals(dfs.getMinusSign(), minus); + assertEquals(percent, dfs.getPercent()); + assertEquals(permill, dfs.getPerMill()); + assertEquals(minus, dfs.getMinusSign()); } @Test - public void testSerialization() throws Exception { + void testSerialization() throws Exception { DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); new ObjectOutputStream(bos).writeObject(dfs); @@ -122,7 +131,7 @@ public void testSerialization() throws Exception { new ByteArrayInputStream(bos.toByteArray()) ).readObject(); - assertEquals(dfs, dfsSerialized); + assertEquals(dfsSerialized, dfs); // set minus/percent/permille dfs.setMinusSign('a'); @@ -134,6 +143,6 @@ public void testSerialization() throws Exception { new ByteArrayInputStream(bos.toByteArray()) ).readObject(); - assertEquals(dfs, dfsSerialized); + assertEquals(dfsSerialized, dfs); } } diff --git a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java index dcc87643b2b..1b3452012cd 100644 --- a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java +++ b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java @@ -29,7 +29,8 @@ * 4098741 4099404 4101481 4106658 4106662 4106664 4108738 4110936 4122840 * 4125885 4134034 4134300 4140009 4141750 4145457 4147295 4147706 4162198 * 4162852 4167494 4170798 4176114 4179818 4212072 4212073 4216742 4217661 - * 4243011 4243108 4330377 4233840 4241880 4833877 8008577 8227313 8174269 + * 4243011 4243108 4330377 4233840 4241880 4833877 6177299 8008577 8227313 + * 8174269 * @summary Regression tests for NumberFormat and associated classes * @library /java/text/testlib * @build HexDumpReader TestUtils @@ -56,10 +57,13 @@ import java.math.BigDecimal; import java.io.*; import java.math.BigInteger; + import sun.util.resources.LocaleData; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; public class NumberRegression { @@ -1847,6 +1851,41 @@ public void test8227313() throws ParseException { ", got: " + parsed); } } + + /** + * 6177299: DecimalFormat w/ multiplier applied may incorrectly return + * a Double as Long.MAX_VALUE. + */ + @Test + void largePosParseTest() { + var df = NumberFormat.getPercentInstance(Locale.ENGLISH); // Default w/ multiplier 100 + // Parsed string after multiplier applied is beyond long range + assertEquals(9.223372036854777E18, + assertDoesNotThrow(() -> df.parse("922,337,203,685,477,700,000%"))); + // Fails before 6177299 fix and returns as long + assertEquals(9.223372036854776E18, + assertDoesNotThrow(() -> df.parse("922,337,203,685,477,600,000%"))); + // Within long range -> Expect to get longs as long as ulp >= 1 + assertEquals((long) 9.223372036854775E18, + assertDoesNotThrow(() -> df.parse("922,337,203,685,477,500,000%"))); + } + + /** + * 6177299: Negative version of above test. + */ + @Test + void largeNegParseTest() { + var df = NumberFormat.getPercentInstance(Locale.ENGLISH); // Default w/ multiplier 100 + // Parsed string after multiplier applied is beyond long range + assertEquals(-9.223372036854777E18, + assertDoesNotThrow(() -> df.parse("-922,337,203,685,477,700,000%"))); + // Fails before 6177299 fix and returns as long + assertEquals(-9.223372036854776E18, + assertDoesNotThrow(() -> df.parse("-922,337,203,685,477,600,000%"))); + // Within long range -> Expect to get longs as long as ulp >= 1 + assertEquals((long) -9.223372036854775E18, + assertDoesNotThrow(() -> df.parse("-922,337,203,685,477,500,000%"))); + } } @SuppressWarnings("serial") diff --git a/test/jdk/java/text/Normalizer/SquareEraCharacterTest.java b/test/jdk/java/text/Normalizer/SquareEraCharacterTest.java index 7367badd811..9b669880fe9 100644 --- a/test/jdk/java/text/Normalizer/SquareEraCharacterTest.java +++ b/test/jdk/java/text/Normalizer/SquareEraCharacterTest.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 @@ -25,20 +25,20 @@ * @test * @bug 8221431 * @summary Tests decomposition of Japanese square era characters. - * @run testng/othervm SquareEraCharacterTest + * @run junit/othervm SquareEraCharacterTest */ -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import java.text.Normalizer; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SquareEraCharacterTest { - @DataProvider Object[][] squareEras() { return new Object[][] { @@ -51,12 +51,10 @@ Object[][] squareEras() { }; } - @Test(dataProvider="squareEras") - public void test_normalize(char squareChar, String expected) { - - assertEquals( - Normalizer.normalize(Character.toString(squareChar), Normalizer.Form.NFKD), - expected, + @ParameterizedTest + @MethodSource("squareEras") + void test_normalize(char squareChar, String expected) { + assertEquals(expected, Normalizer.normalize(Character.toString(squareChar), Normalizer.Form.NFKD), "decomposing " + Character.getName(squareChar) + "."); } } diff --git a/test/jdk/java/util/Locale/CaseFoldLanguageTagTest.java b/test/jdk/java/util/Locale/CaseFoldLanguageTagTest.java index fdee5075229..f3babb7e4c2 100644 --- a/test/jdk/java/util/Locale/CaseFoldLanguageTagTest.java +++ b/test/jdk/java/util/Locale/CaseFoldLanguageTagTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,11 @@ /* * @test - * @bug 8159337 + * @bug 8159337 8368981 * @summary Test Locale.caseFoldLanguageTag(String languageTag) * @run junit CaseFoldLanguageTagTest */ -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -54,24 +53,67 @@ public class CaseFoldLanguageTagTest { @ParameterizedTest @MethodSource("wellFormedTags") - public void wellFormedTags(String tag, String foldedTag) { + void wellFormedTagsTest(String tag, String foldedTag) { assertEquals(foldedTag, Locale.caseFoldLanguageTag(tag), String.format("Folded %s", tag)); } + @ParameterizedTest + @MethodSource("legacyTags") + void legacyTagsTest(String tag) { + var lowerTag = tag.toLowerCase(Locale.ROOT); + var upperTag = tag.toUpperCase(Locale.ROOT); + assertEquals(tag, Locale.caseFoldLanguageTag(lowerTag), + String.format("Folded %s", lowerTag)); + assertEquals(tag, Locale.caseFoldLanguageTag(upperTag), + String.format("Folded %s", upperTag)); + } + @ParameterizedTest @MethodSource("illFormedTags") - public void illFormedTags(String tag) { + void illFormedTagsTest(String tag) { assertThrows(IllformedLocaleException.class, () -> Locale.caseFoldLanguageTag(tag)); } @Test - public void throwNPE() { + void throwNPETest() { assertThrows(NullPointerException.class, () -> Locale.caseFoldLanguageTag(null)); } - private static Stream wellFormedTags() { + // Well-formed legacy tags in expected case + static Stream legacyTags() { + return Stream.of( + "art-lojban", + "cel-gaulish", + "en-GB-oed", + "i-ami", + "i-bnn", + "i-default", + "i-enochian", + "i-hak", + "i-klingon", + "i-lux", + "i-mingo", + "i-navajo", + "i-pwn", + "i-tao", + "i-tay", + "i-tsu", + "no-bok", + "no-nyn", + "sgn-BE-FR", + "sgn-BE-NL", + "sgn-CH-DE", + "zh-guoyu", + "zh-hakka", + "zh-min", + "zh-min-nan", + "zh-xiang" + ); + } + + static Stream wellFormedTags() { return Stream.of( // langtag tests // language @@ -124,16 +166,6 @@ private static Stream wellFormedTags() { Arguments.of("X-A-ABC", "x-a-abc"), // private w/ extended (incl. 1) Arguments.of("X-A-AB-Abcd", "x-a-ab-abcd"), // private w/ extended (incl. 1, 2, 4) - // Legacy tests - // irregular - Arguments.of("I-AMI", "i-ami"), - Arguments.of("EN-gb-OED", "en-GB-oed"), - Arguments.of("SGN-be-fr", "sgn-BE-FR"), - // regular - Arguments.of("NO-BOK", "no-bok"), - Arguments.of("CEL-GAULISH", "cel-gaulish"), - Arguments.of("ZH-MIN-NAN", "zh-min-nan"), - // Special JDK Cases (Variant and x-lvariant) Arguments.of("de-POSIX-x-URP-lvariant-Abc-Def", "de-POSIX-x-urp-lvariant-Abc-Def"), Arguments.of("JA-JPAN-JP-U-CA-JAPANESE-x-RANDOM-lvariant-JP", @@ -150,7 +182,7 @@ private static Stream wellFormedTags() { ); } - private static Stream illFormedTags() { + static Stream illFormedTags() { return Stream.of( // Starts with non-language Arguments.of("xabadadoo-me"), diff --git a/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java b/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java index 93cf0e0165d..16f764c6674 100644 --- a/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java +++ b/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, 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 @@ -28,9 +28,7 @@ * @library /lib/testlibrary/java/util/jar /test/lib * @modules jdk.jartool * jdk.compiler - * jdk.httpserver * @build CreateMultiReleaseTestJars - * jdk.test.lib.net.SimpleHttpServer * jdk.test.lib.compiler.Compiler * jdk.test.lib.util.JarBuilder * @run testng MultiReleaseJarHttpProperties @@ -51,21 +49,28 @@ import java.net.InetSocketAddress; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Path; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; -import jdk.test.lib.net.SimpleHttpServer; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; import jdk.test.lib.net.URIBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class MultiReleaseJarHttpProperties extends MultiReleaseJarProperties { - private SimpleHttpServer server; + private HttpServer server; + private ExecutorService executor; static final String TESTCONTEXT = "/multi-release.jar"; //mapped to local file path @BeforeClass public void initialize() throws Exception { - server = new SimpleHttpServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), TESTCONTEXT, - System.getProperty("user.dir", ".")); + server = SimpleFileServer.createFileServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), + Path.of(System.getProperty("user.dir", ".")), SimpleFileServer.OutputLevel.INFO); + executor = Executors.newCachedThreadPool(); + server.setExecutor(executor); server.start(); super.initialize(); } @@ -73,7 +78,7 @@ public void initialize() throws Exception { @Override protected void initializeClassLoader() throws Exception { URL[] urls = new URL[]{ - URIBuilder.newBuilder().scheme("http").port(server.getPort()).loopback() + URIBuilder.newBuilder().scheme("http").port(server.getAddress().getPort()).loopback() .path(TESTCONTEXT).toURL(), }; cldr = new URLClassLoader(urls); @@ -84,8 +89,10 @@ protected void initializeClassLoader() throws Exception { @AfterClass public void close() throws IOException { // Windows requires server to stop before file is deleted - if (server != null) - server.stop(); + if (server != null) { + server.stop(0); + executor.shutdown(); + } super.close(); } diff --git a/test/jdk/javax/crypto/Cipher/TestEmptyModePadding.java b/test/jdk/javax/crypto/Cipher/TestEmptyModePadding.java index 56e35f2a72a..e7ebe9f4494 100644 --- a/test/jdk/javax/crypto/Cipher/TestEmptyModePadding.java +++ b/test/jdk/javax/crypto/Cipher/TestEmptyModePadding.java @@ -24,7 +24,7 @@ /* * @test - * @bug 8359388 + * @bug 8359388 8368984 * @summary test that the Cipher.getInstance() would reject improper * transformations with empty mode and/or padding. */ @@ -67,6 +67,9 @@ public static void main(String[] args) throws Exception { "PBEWithHmacSHA512/256AndAES_128/CBC/ ", "PBEWithHmacSHA512/256AndAES_128//PKCS5Padding", "PBEWithHmacSHA512/256AndAES_128/ /PKCS5Padding", + // 4 or more components transformations + "PBEWithHmacSHA512///PKCS5Padding", + "AES/GCM/NoPadding///", }; for (String t : testTransformations) { diff --git a/test/jdk/javax/crypto/Cipher/TestGetInstance.java b/test/jdk/javax/crypto/Cipher/TestGetInstance.java index 8d261657498..a135af4d1f8 100644 --- a/test/jdk/javax/crypto/Cipher/TestGetInstance.java +++ b/test/jdk/javax/crypto/Cipher/TestGetInstance.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 @@ -23,9 +23,10 @@ /* * @test - * @bug 4898428 + * @bug 4898428 8368984 * @summary test that the new getInstance() implementation works correctly * @author Andreas Sterbenz + * @library /test/lib * @run main TestGetInstance DES PBEWithMD5AndTripleDES * @run main TestGetInstance AES PBEWithHmacSHA1AndAES_128 */ @@ -35,6 +36,7 @@ import java.util.Locale; import javax.crypto.*; +import jdk.test.lib.Utils; public class TestGetInstance { @@ -48,8 +50,8 @@ public static void main(String[] args) throws Exception { String algo = args[0]; String algoLC = algo.toLowerCase(Locale.ROOT); String pbeAlgo = args[1]; - Provider p = Security.getProvider( - System.getProperty("test.provider.name", "SunJCE")); + String pName = System.getProperty("test.provider.name", "SunJCE"); + Provider p = Security.getProvider(pName); Cipher c; @@ -68,87 +70,55 @@ public static void main(String[] args) throws Exception { c = Cipher.getInstance(algoLC + "/cbc/pkcs5padding", p); same(p, c.getProvider()); - try { - c = Cipher.getInstance(algo + "/XYZ/PKCS5Padding"); - throw new AssertionError(); - } catch (NoSuchAlgorithmException e) { - System.out.println(e); - } - try { - c = Cipher.getInstance(algo + "/XYZ/PKCS5Padding", - System.getProperty("test.provider.name", "SunJCE")); - throw new AssertionError(); - } catch (NoSuchAlgorithmException e) { - System.out.println(e); - } - try { - c = Cipher.getInstance(algo + "/XYZ/PKCS5Padding", p); - throw new AssertionError(); - } catch (NoSuchAlgorithmException e) { - System.out.println(e); - } + // invalid transformations or transformations containing unsupported + // modes which should lead to NSAE + String[] nsaeTransformations = { + (algo + "/XYZ/PKCS5Padding"), + (algo + "/CBC/XYZWithSHA512/224Padding/"), + (algo + "/CBC/XYZWithSHA512/256Padding/"), + (pbeAlgo + "/CBC/XYZWithSHA512/224Padding/"), + (pbeAlgo + "/CBC/XYZWithSHA512/256Padding/"), + "foo", + }; - try { - c = Cipher.getInstance(algo + "/CBC/XYZPadding"); - throw new AssertionError(); - } catch (NoSuchAlgorithmException e) { - System.out.println(e); - } - try { - c = Cipher.getInstance(algo + "/CBC/XYZPadding", - System.getProperty("test.provider.name", "SunJCE")); - throw new AssertionError(); - } catch (NoSuchPaddingException e) { - System.out.println(e); - } - try { - c = Cipher.getInstance(algo + "/CBC/XYZPadding", p); - throw new AssertionError(); - } catch (NoSuchPaddingException e) { - System.out.println(e); + for (String t : nsaeTransformations) { + System.out.println("Testing NSAE on " + t); + Utils.runAndCheckException(() -> Cipher.getInstance(t), + NoSuchAlgorithmException.class); + Utils.runAndCheckException(() -> Cipher.getInstance(t, pName), + NoSuchAlgorithmException.class); + Utils.runAndCheckException(() -> Cipher.getInstance(t, p), + NoSuchAlgorithmException.class); } - try { - c = Cipher.getInstance("foo"); - throw new AssertionError(); - } catch (NoSuchAlgorithmException e) { - System.out.println(e); - } - try { - c = Cipher.getInstance("foo", - System.getProperty("test.provider.name", "SunJCE")); - throw new AssertionError(); - } catch (NoSuchAlgorithmException e) { - System.out.println(e); - } - try { - c = Cipher.getInstance("foo", p); - throw new AssertionError(); - } catch (NoSuchAlgorithmException e) { - System.out.println(e); - } + // transformations containing unsupported paddings for SunJCE provider + // which should lead to NSPE + String[] nspeTransformations = { + (algo + "/CBC/XYZPadding"), + (algo + "/CBC/XYZWithSHA512/224Padding"), + (algo + "/CBC/XYZWithSHA512/256Padding"), + (pbeAlgo + "/CBC/XYZWithSHA512/224Padding"), + (pbeAlgo + "/CBC/XYZWithSHA512/256Padding"), + }; - try { - c = Cipher.getInstance("foo", - System.getProperty("test.provider.name", "SUN")); - throw new AssertionError(); - } catch (NoSuchAlgorithmException e) { - System.out.println(e); - } - try { - c = Cipher.getInstance("foo", Security.getProvider( - System.getProperty("test.provider.name", "SUN"))); - throw new AssertionError(); - } catch (NoSuchAlgorithmException e) { - System.out.println(e); - } - try { - c = Cipher.getInstance("foo", "bar"); - throw new AssertionError(); - } catch (NoSuchProviderException e) { - System.out.println(e); + for (String t : nspeTransformations) { + System.out.println("Testing NSPE on " + t); + Utils.runAndCheckException(() -> Cipher.getInstance(t, pName), + NoSuchPaddingException.class); + Utils.runAndCheckException(() -> Cipher.getInstance(t, p), + NoSuchPaddingException.class); } + // additional misc tests + Utils.runAndCheckException(() -> Cipher.getInstance("foo", + System.getProperty("test.provider.name", "SUN")), + NoSuchAlgorithmException.class); + Utils.runAndCheckException(() -> Cipher.getInstance("foo", + Security.getProvider(System.getProperty("test.provider.name", + "SUN"))), NoSuchAlgorithmException.class); + Utils.runAndCheckException(() -> Cipher.getInstance("foo", "bar"), + NoSuchProviderException.class); + System.out.println("All Tests ok"); } } diff --git a/test/jdk/javax/net/ssl/DTLS/FragmentedFinished.java b/test/jdk/javax/net/ssl/DTLS/FragmentedFinished.java new file mode 100644 index 00000000000..2b6fd16005c --- /dev/null +++ b/test/jdk/javax/net/ssl/DTLS/FragmentedFinished.java @@ -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. + */ + +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. + +/* + * @test + * @bug 8367133 + * @summary Verify that handshake succeeds when Finished message is fragmented + * @modules java.base/sun.security.util + * @library /test/lib + * @build DTLSOverDatagram + * @run main/othervm FragmentedFinished + */ + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import java.net.DatagramPacket; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.List; + +public class FragmentedFinished extends DTLSOverDatagram { + private SSLEngine serverSSLEngine; + public static void main(String[] args) throws Exception { + FragmentedFinished testCase = new FragmentedFinished(); + testCase.runTest(testCase); + } + + @Override + SSLEngine createSSLEngine(boolean isClient) throws Exception { + SSLEngine sslEngine = super.createSSLEngine(isClient); + if (!isClient) { + serverSSLEngine = sslEngine; + } + return sslEngine; + } + + @Override + DatagramPacket createHandshakePacket(byte[] ba, SocketAddress socketAddr) { + if (ba.length < 30) { // detect ChangeCipherSpec + // Reduce the maximumPacketSize to force fragmentation + // of the Finished message + SSLParameters params = serverSSLEngine.getSSLParameters(); + params.setMaximumPacketSize(53); + serverSSLEngine.setSSLParameters(params); + } + + return super.createHandshakePacket(ba, socketAddr); + } +} diff --git a/test/jdk/javax/swing/JEditorPane/TestBrowserBGColor.java b/test/jdk/javax/swing/JEditorPane/TestBrowserBGColor.java index bff0f7c4aaa..9abe286a75d 100644 --- a/test/jdk/javax/swing/JEditorPane/TestBrowserBGColor.java +++ b/test/jdk/javax/swing/JEditorPane/TestBrowserBGColor.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 @@ -23,94 +23,79 @@ /* * @test - * @key headful * @bug 8213781 * @summary Verify webpage background color renders correctly in JEditorPane */ -import java.awt.Toolkit; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.File; import java.io.IOException; -import java.net.MalformedURLException; -import javax.swing.JDialog; +import java.util.Objects; +import java.util.stream.IntStream; + +import javax.imageio.ImageIO; import javax.swing.JEditorPane; -import javax.swing.JFrame; -import javax.swing.JScrollPane; -import javax.swing.SwingUtilities; -import javax.swing.event.HyperlinkEvent; -import javax.swing.event.HyperlinkListener; -import javax.swing.text.html.HTMLFrameHyperlinkEvent; -import javax.swing.text.html.HTMLDocument; -import java.awt.Color; -import java.awt.Insets; -import java.awt.Point; -import java.awt.Robot; +import javax.swing.text.StyleConstants; +import javax.swing.text.View; + +import static java.awt.image.BufferedImage.TYPE_INT_RGB; +import static java.lang.Integer.toHexString; + +public final class TestBrowserBGColor { -public class TestBrowserBGColor extends JFrame implements HyperlinkListener { + private static final String HTML_DOC = + "" + + "" + + "" + + "Title" + + " "; - private static TestBrowserBGColor b; - private static JEditorPane browser; + private static final int SIZE = 300; public static void main(final String[] args) throws Exception { - Robot r = new Robot(); - SwingUtilities.invokeAndWait(() -> { - try { - b = new TestBrowserBGColor(); - } catch (Exception e) { - throw new RuntimeException(e); - } - b.setSize(Toolkit.getDefaultToolkit().getScreenSize()); - b.setVisible(true); - b.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - b.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - b.dispose(); - b = null; - } - }); - }); + JEditorPane browser = new JEditorPane("text/html", HTML_DOC); + browser.setEditable(false); + browser.setSize(SIZE, SIZE); - r.waitForIdle(); - r.delay(500); + BufferedImage image = new BufferedImage(SIZE, SIZE, TYPE_INT_RGB); + Graphics g = image.getGraphics(); + browser.paint(g); + g.dispose(); - SwingUtilities.invokeAndWait(() -> { - Insets insets = browser.getInsets(); - Point loc = browser.getLocationOnScreen(); - Color c = r.getPixelColor( loc.x + insets.left+100, - loc.y + insets.top + 100); - b.dispose(); - if (!c.equals(Color.WHITE)) { - throw new RuntimeException("webpage background color wrong"); - } - }); + Color bgColor = StyleConstants.getBackground( + getBodyView(browser.getUI() + .getRootView(browser)) + .getAttributes()); + if (!bgColor.equals(Color.WHITE)) { + saveImage(image); + throw new RuntimeException("Wrong background color: " + + toHexString(bgColor.getRGB()) + + " vs " + + toHexString(Color.WHITE.getRGB())); + } } + private static View getBodyView(final View view) { + if ("body".equals(view.getElement() + .getName())) { + return view; + } - String htmlDoc = " Title "; - - public TestBrowserBGColor() throws IOException, MalformedURLException { - browser = new JEditorPane("text/html", htmlDoc); - browser.setEditable(false); - browser.addHyperlinkListener(this); - JScrollPane scroll = new JScrollPane(browser); - getContentPane().add(scroll); + return IntStream.range(0, view.getViewCount()) + .mapToObj(view::getView) + .map(TestBrowserBGColor::getBodyView) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); } - public void hyperlinkUpdate(final HyperlinkEvent e) { - if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { - JEditorPane pane = (JEditorPane) e.getSource(); - if (e instanceof HTMLFrameHyperlinkEvent) { - HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e; - HTMLDocument doc = (HTMLDocument) pane.getDocument(); - doc.processHTMLFrameHyperlinkEvent(evt); - } else { - try { - pane.setPage(e.getURL()); - } catch (Throwable t) { - t.printStackTrace(); - } - } + private static void saveImage(BufferedImage image) { + try { + ImageIO.write(image, "png", + new File("html-rendering.png")); + } catch (IOException ignored) { } } } diff --git a/test/jdk/javax/swing/plaf/basic/BasicHTML/bug4248210.java b/test/jdk/javax/swing/plaf/basic/BasicHTML/bug4248210.java index fddfbb28384..54f7744ee90 100644 --- a/test/jdk/javax/swing/plaf/basic/BasicHTML/bug4248210.java +++ b/test/jdk/javax/swing/plaf/basic/BasicHTML/bug4248210.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,7 +71,7 @@ private static void test(UIManager.LookAndFeelInfo laf) { UIManager.getDefaults().put("Label.foreground", labelColor); } - JLabel label = new JLabel("Can You Read This?"); + JLabel label = new JLabel("\u2588 \u2588 \u2588 \u2588"); label.setSize(150, 30); BufferedImage img = paintToImage(label); diff --git a/test/jdk/javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java b/test/jdk/javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java index be9c9457fff..9b689d2fe2c 100644 --- a/test/jdk/javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java +++ b/test/jdk/javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,40 +21,53 @@ * questions. */ /** - * @test 1.4 08/08/05 + * @test * @key headful * @bug 6276188 * @library ../../../../regtesthelpers * @build Util - * @author Romain Guy * @summary Tests PRESSED and MOUSE_OVER and FOCUSED state for buttons with Synth. * @run main/othervm -Dsun.java2d.uiScale=1 bug6276188 */ -import java.awt.*; -import java.awt.image.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.plaf.synth.*; +import java.io.File; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.imageio.ImageIO; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.plaf.synth.SynthLookAndFeel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import java.util.concurrent.CountDownLatch; public class bug6276188 { private static JButton button; - private static Point p; private static JFrame testFrame; // move away from cursor - private final static int OFFSET_X = -20; - private final static int OFFSET_Y = -20; + private final static int OFFSET_X = 20; + private final static int OFFSET_Y = 20; public static void main(String[] args) throws Throwable { + Robot robot = new Robot(); try { - Robot robot = new Robot(); robot.setAutoDelay(100); SynthLookAndFeel lookAndFeel = new SynthLookAndFeel(); lookAndFeel.load(bug6276188.class.getResourceAsStream("bug6276188.xml"), bug6276188.class); UIManager.setLookAndFeel(lookAndFeel); + CountDownLatch latch = new CountDownLatch(1); SwingUtilities.invokeAndWait(new Runnable() { public void run() { @@ -62,6 +75,13 @@ public void run() { testFrame.setLayout(new BorderLayout()); testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); testFrame.add(BorderLayout.CENTER, button = new JButton()); + button.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + System.out.println("Mouse pressed"); + latch.countDown(); + } + }); testFrame.setSize(new Dimension(320, 200)); testFrame.setLocationRelativeTo(null); @@ -72,13 +92,14 @@ public void run() { robot.waitForIdle(); robot.delay(1000); - p = Util.getCenterPoint(button); + Point p = Util.getCenterPoint(button); System.out.println("Button center point: " + p); robot.mouseMove(p.x , p.y); robot.waitForIdle(); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); - robot.waitForIdle(); + latch.await(); + robot.delay(1000); Color color = robot.getPixelColor(p.x - OFFSET_X, p.y - OFFSET_Y); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); @@ -89,7 +110,7 @@ public void run() { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Rectangle screen = new Rectangle(0, 0, (int) screenSize.getWidth(), (int) screenSize.getHeight()); BufferedImage img = robot.createScreenCapture(screen); - javax.imageio.ImageIO.write(img, "png", new java.io.File("image.png")); + ImageIO.write(img, "png", new File("image.png")); throw new RuntimeException("Synth ButtonUI does not handle PRESSED & MOUSE_OVER state"); } } finally { diff --git a/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java b/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java index 0c08099031a..755745394fc 100644 --- a/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java +++ b/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java @@ -408,11 +408,10 @@ private static void checkGetExponent() { for(var testCase : testCases) { float arg = testCase[0]; float expected = testCase[1]; - // Exponents are in-range for Float16 - Float16 result = valueOfExact(getExponent(valueOfExact(arg))); + float result = (float)getExponent(valueOfExact(arg)); - if (Float.compare(expected, result.floatValue()) != 0) { - checkFloat16(result, expected, "getExponent(" + arg + ")"); + if (Float.compare(expected, result) != 0) { + checkFloat16(Float16.valueOf(result), expected, "getExponent(" + arg + ")"); } } return; @@ -444,8 +443,7 @@ private static void checkUlp() { for(var testCase : testCases) { float arg = testCase[0]; float expected = testCase[1]; - // Exponents are in-range for Float16 - Float16 result = ulp(valueOfExact(arg)); + Float16 result = ulp(valueOfExact(arg)); if (Float.compare(expected, result.floatValue()) != 0) { checkFloat16(result, expected, "ulp(" + arg + ")"); diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventInitialWeight.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventInitialWeight.java new file mode 100644 index 00000000000..598efd66a32 --- /dev/null +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventInitialWeight.java @@ -0,0 +1,83 @@ +/* + * 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.event.allocation; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.CountDownLatch; +import java.util.List; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingStream; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Tests that the VM maintains proper initialization state for ObjectAllocationSampleEvent. + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm -XX:+UseTLAB -XX:TLABSize=2k -XX:-ResizeTLAB jdk.jfr.event.allocation.TestObjectAllocationSampleEventInitialWeight + */ +public class TestObjectAllocationSampleEventInitialWeight { + private static final String EVENT_NAME = EventNames.ObjectAllocationSample; + private static final int OBJECT_SIZE = 4 * 1024; + private static final int OBJECTS_TO_ALLOCATE = 16; + private static final int OBJECTS_TO_ALLOCATE_BEFORE_RECORDING = 1024; + private static final long BEFORE_RECORDING_SAMPLE_WEIGHT = OBJECT_SIZE * OBJECTS_TO_ALLOCATE_BEFORE_RECORDING; + + // Make sure allocation isn't dead code eliminated. + public static byte[] tmp; + + public static void main(String... args) throws Exception { + test(); + // Test again to ensure reset logic works correctly for subsequent physical recordings. + test(); + } + + private static void test() throws Exception { + long currentThreadId = Thread.currentThread().threadId(); + allocate(OBJECTS_TO_ALLOCATE_BEFORE_RECORDING); + try (Recording r = new Recording()) { + r.enable(EVENT_NAME); + r.start(); + allocate(OBJECTS_TO_ALLOCATE); + r.stop(); + List events = Events.fromRecording(r); + Events.hasEvents(events); + for (RecordedEvent event : events) { + if (currentThreadId == event.getThread().getJavaThreadId()) { + if (event.getLong("weight") >= BEFORE_RECORDING_SAMPLE_WEIGHT) { + throw new RuntimeException("Sample weight is not below " + BEFORE_RECORDING_SAMPLE_WEIGHT); + } + } + } + } + } + + private static void allocate(int number) throws Exception { + for (int i = 0; i < number; ++i) { + tmp = new byte[OBJECT_SIZE]; + } + } +} diff --git a/test/jdk/jdk/jfr/event/os/TestThreadContextSwitches.java b/test/jdk/jdk/jfr/event/os/TestThreadContextSwitches.java index 7b3dfc79ce9..acfaecdde7d 100644 --- a/test/jdk/jdk/jfr/event/os/TestThreadContextSwitches.java +++ b/test/jdk/jdk/jfr/event/os/TestThreadContextSwitches.java @@ -28,6 +28,7 @@ import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; +import jdk.test.lib.Platform; /** * @test @@ -40,15 +41,25 @@ public class TestThreadContextSwitches { private final static String EVENT_NAME = EventNames.ThreadContextSwitchRate; public static void main(String[] args) throws Throwable { - Recording recording = new Recording(); - recording.enable(EVENT_NAME); - recording.start(); - recording.stop(); - List events = Events.fromRecording(recording); - Events.hasEvents(events); - for (RecordedEvent event : events) { - System.out.println("Event: " + event); - Events.assertField(event, "switchRate").atLeast(0.0f); + while (true) { + try (Recording recording = new Recording()) { + recording.enable(EVENT_NAME); + recording.start(); + recording.stop(); + List events = Events.fromRecording(recording); + if (!events.isEmpty()) { + for (RecordedEvent event : events) { + System.out.println("Event: " + event); + Events.assertField(event, "switchRate").atLeast(0.0f); + } + return; + } + // Thread context switch rate is unreliable on Windows because + // the way processes are identified with performance counters. + if (!Platform.isWindows()) { + Events.hasEvents(events); + } + } } } } diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java index 1ea96e3bad3..819329aabf5 100644 --- a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleQueueAutoSizes.java @@ -24,6 +24,7 @@ package jdk.jfr.event.profiling; import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.Comparator; import java.util.stream.Collectors; @@ -41,8 +42,15 @@ /* * Tests the sample queues increase in size as needed, when loss is recorded. + * + * The test starts CPU time sampling with a short interval (1ms), disabling + * out-of-stack sample processing for the duration of the test. + * It now runs in native for one second, to cause queue overflows, + * then it comes back into Java to trigger the queue walking. + * Repeats the cycle 5 times and verifies that the loss decreases from the first + * to the last iteration. * @test - * @requires vm.hasJFR & os.family == "linux" & vm.debug + * @requires vm.hasJFR & os.family == "linux" & vm.debug & vm.flagless * @library /test/lib * @modules jdk.jfr/jdk.jfr.internal * @build jdk.test.whitebox.WhiteBox @@ -54,15 +62,13 @@ public class TestCPUTimeSampleQueueAutoSizes { private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); - private static final String BURST_THREAD_NAME = "Burst-Thread-1"; - - static volatile boolean alive = true; - record LossEvent(long relativeTimeMillis, long lostSamples) {} /** A data collection from the CPUTimeSampleLost events for the burst thread */ static class LossEventCollection { private final List events = new ArrayList<>(); + private final List sampleEventsInTimeBox = new ArrayList<>(); + private final List timeBoxEnds = new ArrayList<>(); public synchronized void addEvent(LossEvent event) { events.add(event); @@ -74,81 +80,100 @@ public synchronized List getSortedEvents() { .collect(Collectors.toList()); } - public List getEventsPerInterval(long widthMillis, long stopTimeMillis) { + public synchronized List getEventsPerTimeBox() { List ret = new ArrayList<>(); - for (long start = 0; start < stopTimeMillis; start += widthMillis) { - long actualStart = Math.min(start, stopTimeMillis - widthMillis); + AtomicLong previousEnd = new AtomicLong(0); + for (Long timeBoxEnd : timeBoxEnds) { long lostSamples = events.stream() - .filter(e -> e.relativeTimeMillis >= actualStart && e.relativeTimeMillis < actualStart + widthMillis) + .filter(e -> e.relativeTimeMillis >= previousEnd.get() && e.relativeTimeMillis <= timeBoxEnd) .mapToLong(e -> e.lostSamples) .sum(); - ret.add(new LossEvent(actualStart, lostSamples)); + ret.add(new LossEvent(previousEnd.get(), lostSamples)); + previousEnd.set(timeBoxEnd); } return ret; } + public synchronized void addTimeBoxEnd(long timeBoxEnd, long sampleEvents) { + timeBoxEnds.add(timeBoxEnd); + sampleEventsInTimeBox.add(sampleEvents); + } + + public synchronized void print() { + System.out.println("Loss event information:"); + for (int i = 0; i < timeBoxEnds.size(); i++) { + System.out.println(" Time box end: " + timeBoxEnds.get(i) + ", sample events: " + sampleEventsInTimeBox.get(i)); + } + for (LossEvent e : events) { + System.out.println(" Lost samples event: " + e.lostSamples + " at " + e.relativeTimeMillis); + } + for (LossEvent e : getEventsPerTimeBox()) { + System.out.println(" Lost samples in time box ending at " + e.relativeTimeMillis + ": " + e.lostSamples); + } + } } public static void main(String[] args) throws Exception { try (RecordingStream rs = new RecordingStream()) { // setup recording - AtomicLong firstSampleTimeMillis = new AtomicLong(0); - AtomicLong lastSampleTimeMillis = new AtomicLong(0); + long burstThreadId = Thread.currentThread().threadId(); + final long startTimeMillis = Instant.now().toEpochMilli(); LossEventCollection lossEvents = new LossEventCollection(); + AtomicLong sampleEventCountInTimeBox = new AtomicLong(0); rs.enable(EventNames.CPUTimeSample).with("throttle", "1ms"); - rs.onEvent(EventNames.CPUTimeSample, e -> { - if (firstSampleTimeMillis.get() == 0 && e.getThread("eventThread").getJavaName().equals(BURST_THREAD_NAME)) { - firstSampleTimeMillis.set(e.getStartTime().toEpochMilli()); - } - if (e.getThread("eventThread").getJavaName().equals(BURST_THREAD_NAME)) { - lastSampleTimeMillis.set(e.getStartTime().toEpochMilli()); - } - }); rs.enable(EventNames.CPUTimeSamplesLost); rs.onEvent(EventNames.CPUTimeSamplesLost, e -> { - if (e.getThread("eventThread").getJavaName().equals(BURST_THREAD_NAME)) { + if (e.getThread("eventThread").getJavaThreadId() == burstThreadId) { long eventTime = e.getStartTime().toEpochMilli(); - long relativeTime = firstSampleTimeMillis.get() > 0 ? (eventTime - firstSampleTimeMillis.get()) : eventTime; - System.out.println("Lost samples: " + e.getLong("lostSamples") + " at " + relativeTime); + long relativeTime = eventTime - startTimeMillis; + System.out.println("Lost samples: " + e.getLong("lostSamples") + " at " + relativeTime + " start time " + startTimeMillis); lossEvents.addEvent(new LossEvent(relativeTime, e.getLong("lostSamples"))); } }); - WHITE_BOX.cpuSamplerSetOutOfStackWalking(false); + rs.onEvent(EventNames.CPUTimeSample, e -> { + if (e.getThread("eventThread").getJavaThreadId() == burstThreadId) { + sampleEventCountInTimeBox.incrementAndGet(); + } + }); rs.startAsync(); - // this thread runs all along - Thread burstThread = new Thread(() -> WHITE_BOX.busyWait(11000)); - burstThread.setName(BURST_THREAD_NAME); - burstThread.start(); - // now we toggle out-of-stack-walking off, wait 1 second and then turn it on for 500ms a few times + // we disable the out-of-stack walking so that the queue fills up and overflows + // while we are in native code + disableOutOfStackWalking(); + + for (int i = 0; i < 5; i++) { - boolean supported = WHITE_BOX.cpuSamplerSetOutOfStackWalking(false); - if (!supported) { - System.out.println("Out-of-stack-walking not supported, skipping test"); - Asserts.assertFalse(true); - return; - } - Thread.sleep(700); - long iterations = WHITE_BOX.cpuSamplerOutOfStackWalkingIterations(); - WHITE_BOX.cpuSamplerSetOutOfStackWalking(true); - Thread.sleep(300); - while (WHITE_BOX.cpuSamplerOutOfStackWalkingIterations() == iterations) { - Thread.sleep(50); // just to make sure the stack walking really ran - } + // run in native for one second + WHITE_BOX.busyWaitCPUTime(1000); + // going out-of-native at the end of the previous call should have triggered + // the safepoint handler, thereby also triggering the stack walking and creation + // of the loss event + WHITE_BOX.forceSafepoint(); // just to be sure + lossEvents.addTimeBoxEnd(Instant.now().toEpochMilli() - startTimeMillis, sampleEventCountInTimeBox.get()); + sampleEventCountInTimeBox.set(0); } + + rs.stop(); rs.close(); - checkThatLossDecreased(lossEvents, lastSampleTimeMillis.get() - firstSampleTimeMillis.get()); + + enableOutOfStackWalking(); + + checkThatLossDecreased(lossEvents); } } - static void checkThatLossDecreased(LossEventCollection lossEvents, long lastSampleTimeMillis) { - List intervalLosses = lossEvents.getEventsPerInterval(1000, lastSampleTimeMillis); - for (LossEvent interval : intervalLosses) { - System.out.println("Lost samples in interval " + interval.relativeTimeMillis + ": " + interval.lostSamples); - } - // check that there are at least 3 intervals - Asserts.assertTrue(intervalLosses.size() > 2); - // check that the second to last interval has far fewer lost samples than the first - Asserts.assertTrue(intervalLosses.get(intervalLosses.size() - 2).lostSamples < - intervalLosses.get(0).lostSamples / 2); + static void disableOutOfStackWalking() { + Asserts.assertTrue(WHITE_BOX.cpuSamplerSetOutOfStackWalking(false), "Out-of-stack-walking not supported"); + } + + static void enableOutOfStackWalking() { + WHITE_BOX.cpuSamplerSetOutOfStackWalking(true); + } + + static void checkThatLossDecreased(LossEventCollection lossEvents) { + lossEvents.print(); + List timeBoxedLosses = lossEvents.getEventsPerTimeBox(); + // check that the last time box has far fewer lost samples than the first + Asserts.assertTrue(timeBoxedLosses.get(timeBoxedLosses.size() - 1).lostSamples <= + timeBoxedLosses.get(0).lostSamples / 2); } } diff --git a/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java b/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java index 92298eaece0..96e251aa077 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java @@ -245,28 +245,6 @@ private static void testSettingConfiguration(String configurationName) throws Ex System.out.println("Testing configuration " + configurationName); Configuration c = Configuration.getConfiguration(configurationName); Map settingValues = c.getSettings(); - // Don't want to add these settings to the jfc-files we ship since they - // are not useful to configure. They are however needed to make the test - // pass. - settingValues.put(EventNames.ActiveSetting + "#stackTrace", "false"); - settingValues.put(EventNames.ActiveSetting + "#threshold", "0 ns"); - settingValues.put(EventNames.ActiveRecording + "#stackTrace", "false"); - settingValues.put(EventNames.ActiveRecording + "#threshold", "0 ns"); - settingValues.put(EventNames.InitialSecurityProperty + "#threshold", "0 ns"); - settingValues.put(EventNames.JavaExceptionThrow + "#threshold", "0 ns"); - settingValues.put(EventNames.JavaErrorThrow + "#threshold", "0 ns"); - settingValues.put(EventNames.SecurityProperty + "#threshold", "0 ns"); - settingValues.put(EventNames.TLSHandshake + "#threshold", "0 ns"); - settingValues.put(EventNames.X509Certificate + "#threshold", "0 ns"); - settingValues.put(EventNames.X509Validation + "#threshold", "0 ns"); - settingValues.put(EventNames.ProcessStart + "#threshold", "0 ns"); - settingValues.put(EventNames.Deserialization + "#threshold", "0 ns"); - settingValues.put(EventNames.VirtualThreadStart + "#threshold", "0 ns"); - settingValues.put(EventNames.VirtualThreadEnd + "#stackTrace", "false"); - settingValues.put(EventNames.VirtualThreadEnd + "#threshold", "0 ns"); - settingValues.put(EventNames.VirtualThreadSubmitFailed + "#threshold", "0 ns"); - settingValues.put(EventNames.SecurityProviderService + "#threshold", "0 ns"); - try (Recording recording = new Recording(c)) { Map eventTypes = new HashMap<>(); for (EventType et : FlightRecorder.getFlightRecorder().getEventTypes()) { @@ -279,7 +257,11 @@ private static void testSettingConfiguration(String configurationName) throws Ex String settingName = type.getName() + "#" + s.getName(); String value = settingValues.get(settingName); if (value == null) { - throw new Exception("Could not find setting with name " + settingName); + String message = "Could not find setting with name " + settingName + "."; + if (settingName.equals("duration") || settingName.equals("stackTrace")) { + message += " Use @RemoveFields(\"" + settingName + "\") to drop the field."; + } + throw new Exception(message); } // Prefer to have ms unit in jfc file if (value.equals("0 ms")) { diff --git a/test/jdk/jdk/jfr/jcmd/TestJcmdView.java b/test/jdk/jdk/jfr/jcmd/TestJcmdView.java index 92e5c950f9b..206d6c7bc8f 100644 --- a/test/jdk/jdk/jfr/jcmd/TestJcmdView.java +++ b/test/jdk/jdk/jfr/jcmd/TestJcmdView.java @@ -163,7 +163,7 @@ private static void testTableView() throws Throwable { // Verify verbose heading output.shouldContain("(longestPause)"); // Verify row contents - output.shouldContain("Old Garbage Collection"); + output.shouldContain("G1"); // Verify verbose query output.shouldContain("SELECT"); } diff --git a/test/jdk/jdk/jfr/tool/TestPrintContextual.java b/test/jdk/jdk/jfr/tool/TestPrintContextual.java index 15486148b9c..e6df9c7c729 100644 --- a/test/jdk/jdk/jfr/tool/TestPrintContextual.java +++ b/test/jdk/jdk/jfr/tool/TestPrintContextual.java @@ -25,6 +25,7 @@ import java.nio.file.Files; import java.nio.file.Path; +import java.time.Instant; import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; @@ -264,7 +265,8 @@ private static void testDeepContext() throws Exception { } } - private static void span(int depth) { + private static void span(int depth) throws InterruptedException { + awaitUniqueTimestamp(); SpanEvent span = new SpanEvent(); span.name = "span"; span.spanId = depth; @@ -277,6 +279,13 @@ private static void span(int depth) { span.commit(); } + private static void awaitUniqueTimestamp() throws InterruptedException { + Instant timestamp = Instant.now(); + while (timestamp.equals(Instant.now())) { + Thread.sleep(1); + } + } + // Tests that context values are only inhjected into events in the same thread. private static void testThreadedContext() throws Exception { try (Recording r = new Recording()) { diff --git a/test/jdk/jdk/jfr/tool/TestView.java b/test/jdk/jdk/jfr/tool/TestView.java index 89c45c3e068..38174859b51 100644 --- a/test/jdk/jdk/jfr/tool/TestView.java +++ b/test/jdk/jdk/jfr/tool/TestView.java @@ -84,7 +84,7 @@ private static void testTableView(String recording) throws Throwable { // Verify verbose heading output.shouldContain("(longestPause)"); // Verify row contents - output.shouldContain("Old Garbage Collection"); + output.shouldContain("G1"); // Verify verbose query output.shouldContain("SELECT"); } diff --git a/test/jdk/sun/awt/font/TestDevTransform.java b/test/jdk/sun/awt/font/TestDevTransform.java index 2783401c0f2..39d4255f154 100644 --- a/test/jdk/sun/awt/font/TestDevTransform.java +++ b/test/jdk/sun/awt/font/TestDevTransform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,31 @@ */ /* - * @test + * @test id=dialog_double * @bug 4269775 8341535 * @summary Check that different text rendering APIs agree + * @run main/othervm TestDevTransform DIALOG DOUBLE + */ + +/* + * @test id=dialog_float + * @bug 4269775 8341535 + * @summary Check that different text rendering APIs agree + * @run main/othervm TestDevTransform DIALOG FLOAT + */ + +/* + * @test id=monospaced_double + * @bug 4269775 8341535 + * @summary Check that different text rendering APIs agree + * @run main/othervm TestDevTransform MONOSPACED DOUBLE + */ + +/* + * @test id=monospaced_float + * @bug 4269775 8341535 + * @summary Check that different text rendering APIs agree + * @run main/othervm TestDevTransform MONOSPACED FLOAT */ /** @@ -66,6 +88,8 @@ public class TestDevTransform { static String test = "This is only a test"; static double angle = Math.PI / 6.0; // Rotate 30 degrees static final int W = 400, H = 400; + static boolean useDialog; + static boolean useDouble; static void draw(Graphics2D g2d, TextLayout layout, float x, float y, float scalex) { @@ -101,9 +125,19 @@ static void init(Graphics2D g2d) { g2d.setColor(Color.white); g2d.fillRect(0, 0, W, H); g2d.setColor(Color.black); - g2d.scale(1.481f, 1.481); // Convert to 108 dpi + if (useDouble) { + g2d.scale(1.481, 1.481); // Convert to 108 dpi + } else { + g2d.scale(1.481f, 1.481f); // Convert to 108 dpi + } g2d.addRenderingHints(hints); - Font font = new Font(Font.DIALOG, Font.PLAIN, 12); + String name; + if (useDialog) { + name = Font.DIALOG; + } else { + name = Font.MONOSPACED; + } + Font font = new Font(name, Font.PLAIN, 12); g2d.setFont(font); } @@ -135,6 +169,12 @@ static void compare(BufferedImage bi1, String name1, BufferedImage bi2, String n } public static void main(String args[]) throws Exception { + if (args[0].equals("DIALOG")) { + useDialog = true; + } + if (args[1].equals("DOUBLE")) { + useDouble = true; + } BufferedImage tl_Image = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); { diff --git a/test/jdk/sun/invoke/util/BytecodeDescriptorTest.java b/test/jdk/sun/invoke/util/BytecodeDescriptorTest.java new file mode 100644 index 00000000000..fa99c20e644 --- /dev/null +++ b/test/jdk/sun/invoke/util/BytecodeDescriptorTest.java @@ -0,0 +1,128 @@ +/* + * 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 8356022 + * @summary Tests for sun.invoke.util.BytecodeDescriptor + * @library /test/lib + * @modules java.base/sun.invoke.util + * @run junit BytecodeDescriptorTest + */ + +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.util.List; +import java.util.Map; + +import jdk.test.lib.ByteCodeLoader; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import sun.invoke.util.BytecodeDescriptor; + +import static org.junit.jupiter.api.Assertions.*; + +class BytecodeDescriptorTest { + + private static final String FOO_NAME = "dummy.Foo"; + private static final String BAR_NAME = "dummy.Bar"; + private static final String FOO_DESC = "L" + FOO_NAME.replace('.', '/') + ";"; + private static final String BAR_DESC = "L" + BAR_NAME.replace('.', '/') + ";"; + private static final String DOES_NOT_EXIST_DESC = "Ldoes/not/Exist;"; + static Class foo1, foo2, bar1; + static ClassLoader cl1, cl2; + + @BeforeAll + static void setup() throws Throwable { + var fooBytes = ClassFile.of().build(ClassDesc.of(FOO_NAME), _ -> {}); + var barBytes = ClassFile.of().build(ClassDesc.of(BAR_NAME), _ -> {}); + cl1 = new ByteCodeLoader(Map.of(FOO_NAME, fooBytes, BAR_NAME, barBytes), ClassLoader.getSystemClassLoader()); + foo1 = cl1.loadClass(FOO_NAME); + bar1 = cl1.loadClass(BAR_NAME); + foo2 = ByteCodeLoader.load(FOO_NAME, fooBytes); + cl2 = foo2.getClassLoader(); + + // Sanity + assertNotSame(foo1, foo2); + assertNotSame(cl1, cl2); + assertSame(cl1, foo1.getClassLoader()); + assertSame(cl1, bar1.getClassLoader()); + assertNotSame(cl1, foo2.getClassLoader()); + assertEquals(FOO_DESC, foo1.descriptorString()); + assertEquals(FOO_DESC, foo2.descriptorString()); + assertEquals(BAR_DESC, bar1.descriptorString()); + } + + @Test + void testParseClass() throws ReflectiveOperationException { + assertSame(void.class, BytecodeDescriptor.parseClass("V", null), "void"); + assertSame(int.class, BytecodeDescriptor.parseClass("I", null), "primitive"); + assertSame(long[][].class, BytecodeDescriptor.parseClass("[[J", null), "array"); + assertSame(Object.class, BytecodeDescriptor.parseClass("Ljava/lang/Object;", null), "class or interface"); + assertThrows(IllegalArgumentException.class, () -> BytecodeDescriptor.parseClass("java/lang/Object", null), "internal name"); + assertThrows(IllegalArgumentException.class, () -> BytecodeDescriptor.parseClass("[V", null), "bad array"); + assertSame(Class.forName("[".repeat(255) + "I"), BytecodeDescriptor.parseClass("[".repeat(255) + "I", null), "good array"); + assertThrows(IllegalArgumentException.class, () -> BytecodeDescriptor.parseClass("[".repeat(256) + "I", null), "bad array"); + + assertSame(foo2, BytecodeDescriptor.parseClass(FOO_DESC, cl2), "class loader"); + assertThrows(TypeNotPresentException.class, () -> BytecodeDescriptor.parseClass(DOES_NOT_EXIST_DESC, null), "not existent"); + assertThrows(TypeNotPresentException.class, () -> BytecodeDescriptor.parseClass(BAR_DESC, cl2), "cross loader"); + } + + @Test + void testParseMethod() { + assertEquals(List.of(void.class), + BytecodeDescriptor.parseMethod("()V", null), + "no-arg"); + assertEquals(List.of(int.class, Object.class, long[].class, void.class), + BytecodeDescriptor.parseMethod("(ILjava/lang/Object;[J)V", null), + "sanity"); + assertThrows(IllegalArgumentException.class, + () -> BytecodeDescriptor.parseMethod("()", null), + "no return"); + assertThrows(IllegalArgumentException.class, + () -> BytecodeDescriptor.parseMethod("(V)V", null), + "bad arg"); + var voidInMsgIAE = assertThrows(IllegalArgumentException.class, + () -> BytecodeDescriptor.parseMethod("([V)I", null), + "bad arg"); + assertTrue(voidInMsgIAE.getMessage().contains("[V"), () -> "missing [V type in: '%s'".formatted(voidInMsgIAE.getMessage())); + assertThrows(IllegalArgumentException.class, + () -> BytecodeDescriptor.parseClass("([".repeat(256) + "I)J", null), + "bad arg"); + + assertEquals(List.of(foo1, bar1), + BytecodeDescriptor.parseMethod("(" + FOO_DESC + ")" + BAR_DESC, cl1), + "class loader"); + assertThrows(TypeNotPresentException.class, + () -> BytecodeDescriptor.parseMethod("(" + FOO_DESC + ")" + BAR_DESC, cl2), + "no bar"); + assertThrows(TypeNotPresentException.class, + () -> BytecodeDescriptor.parseMethod("(" + FOO_DESC + "V)V", null), + "first encounter TNPE"); + assertThrows(IllegalArgumentException.class, + () -> BytecodeDescriptor.parseMethod("(V" + FOO_DESC + ")V", null), + "first encounter IAE"); + } + +} diff --git a/test/jdk/sun/java2d/OpenGL/DrawBitmaskImage.java b/test/jdk/sun/java2d/OpenGL/DrawBitmaskImage.java new file mode 100644 index 00000000000..d2730593b5b --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/DrawBitmaskImage.java @@ -0,0 +1,173 @@ +/* + * 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 + * 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 6248561 6264014 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that bitmask image copies work properly with the + * OGL pipeline when a SrcOver composite with extra alpha is involved. + * @run main/othervm -Dsun.java2d.opengl=True DrawBitmaskImage + * @run main/othervm DrawBitmaskImage + */ + +/* + * @test + * @bug 6248561 6264014 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that bitmask image copies work properly with the + * OGL pipeline when a SrcOver composite with extra alpha is involved. + * @run main/othervm -Dsun.java2d.opengl=True DrawBitmaskImage + * @run main/othervm DrawBitmaskImage + */ + +import java.awt.AlphaComposite; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Transparency; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; +import java.io.File; +import javax.imageio.ImageIO; + +public class DrawBitmaskImage extends Panel { + + static final int TESTW = 200, TESTH = 200; + private static volatile DrawBitmaskImage test; + private static volatile Frame frame; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + g2d.setColor(Color.black); + g2d.fillRect(0, 0, getWidth(), getHeight()); + g2d.setComposite(AlphaComposite.SrcOver.derive(0.50f)); + + BufferedImage img = getGraphicsConfiguration().createCompatibleImage(50, 50, + Transparency.BITMASK); + Graphics2D gimg = img.createGraphics(); + gimg.setComposite(AlphaComposite.Src); + gimg.setColor(new Color(0, 0, 0, 0)); + gimg.fillRect(0, 0, 50, 50); + gimg.setColor(Color.red); + gimg.fillRect(10, 10, 30, 30); + gimg.dispose(); + + + g2d.drawImage(img, 10, 10, null); + + // draw a second time to ensure that the cached copy is used + g2d.drawImage(img, 80, 10, null); + } + + public Dimension getPreferredSize() { + return new Dimension(TESTW, TESTH); + } + + static void createUI() { + test = new DrawBitmaskImage(); + frame = new Frame("OpenGL DrawBitmaskImage Test"); + Panel p = new Panel(); + p.add(test); + frame.add(p); + frame.setSize(TESTW+100, TESTH+100); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(DrawBitmaskImage::createUI); + + robot.waitForIdle(); + robot.delay(2000); + + BufferedImage capture = null; + try { + GraphicsConfiguration gc = frame.getGraphicsConfiguration(); + if (gc.getColorModel() instanceof IndexColorModel) { + System.out.println("IndexColorModel detected: " + + "test considered PASSED"); + return; + } + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, TESTW, TESTH); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Test background color + int pixel = capture.getRGB(5, 10); + if (pixel != 0xff000000) { + saveImage(capture); + throw new RuntimeException("Failed: Incorrect color for " + + "background (actual=" + + Integer.toHexString(pixel) + ")"); + } + + // Test pixels (allow for small error in the actual red value) + pixel = capture.getRGB(25, 25); + System.out.println("pixel1 is " + Integer.toHexString(pixel)); + + if ((pixel < 0xff7e0000) || (pixel > 0xff900000)) { + saveImage(capture); + throw new RuntimeException("Failed: Incorrect color for " + + "first pixel (actual=" + + Integer.toHexString(pixel) + ")"); + } + + pixel = capture.getRGB(95, 25); + System.out.println("pixel2 is " + Integer.toHexString(pixel)); + if ((pixel < 0xff7e0000) || (pixel > 0xff900000)) { + saveImage(capture); + throw new RuntimeException("Failed: Incorrect color for " + + "second pixel (actual=" + + Integer.toHexString(pixel) + ")"); + } + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/DrawBufImgOp.java b/test/jdk/sun/java2d/OpenGL/DrawBufImgOp.java new file mode 100644 index 00000000000..5d60eb7e792 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/DrawBufImgOp.java @@ -0,0 +1,514 @@ +/* + * 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 + * 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 6514990 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that calling + * Graphics2D.drawImage(BufferedImage, BufferedImageOp, x, y) to an + * OpenGL-accelerated destination produces the same results when performed + * in software via BufferedImageOp.filter(). + * @run main/othervm -Dsun.java2d.opengl=True DrawBufImgOp -ignore + */ + +/* + * @test + * @bug 6514990 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that calling + * Graphics2D.drawImage(BufferedImage, BufferedImageOp, x, y) to an + * OpenGL-accelerated destination produces the same results when performed + * in software via BufferedImageOp.filter(). + * @run main/othervm -Dsun.java2d.opengl=True DrawBufImgOp -ignore + */ + +import java.awt.AlphaComposite; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.awt.image.ByteLookupTable; +import java.awt.image.ColorModel; +import java.awt.image.ConvolveOp; +import java.awt.image.IndexColorModel; +import java.awt.image.Kernel; +import java.awt.image.LookupOp; +import java.awt.image.RescaleOp; +import java.awt.image.ShortLookupTable; +import java.awt.image.VolatileImage; +import java.io.File; +import javax.imageio.ImageIO; + +/** + * REMIND: This testcase was originally intended to automatically compare + * the results of the software BufferedImageOp implementations against + * the OGL-accelerated codepaths. However, there are just too many open + * bugs in the mediaLib-based codepaths (see below), which means that + * creating the reference image may cause crashes or exceptions, + * and even if we work around those cases using the "-ignore" flag, + * the visual results of the reference image are often buggy as well + * (so the comparison will fail even though the OGL results are correct). + * Therefore, for now we will run the testcase with the "-ignore" flag + * but without the "-compare" flag, so at least it will be checking for + * any exceptions/crashes in the OGL code. When we fix all of the + * outstanding bugs with the software codepaths, we can remove the + * "-ignore" flag and maybe even restore the "-compare" flag. In the + * meantime, it also functions well as a manual testcase (with either + * the "-show" or "-dump" options). + */ +public class DrawBufImgOp extends Canvas { + + private static final int TESTW = 600; + private static final int TESTH = 500; + + private static volatile DrawBufImgOp test; + private static volatile Frame frame; + + /* + * If true, skips tests that are known to trigger bugs (which in + * turn may cause crashes, exceptions, or other artifacts). + */ + private static boolean ignore; + + // Test both pow2 and non-pow2 sized images + private static final int[] srcSizes = { 32, 17 }; + private static final int[] srcTypes = { + BufferedImage.TYPE_INT_RGB, + BufferedImage.TYPE_INT_ARGB, + BufferedImage.TYPE_INT_ARGB_PRE, + BufferedImage.TYPE_INT_BGR, + BufferedImage.TYPE_3BYTE_BGR, + BufferedImage.TYPE_4BYTE_ABGR, + BufferedImage.TYPE_USHORT_565_RGB, + BufferedImage.TYPE_BYTE_GRAY, + BufferedImage.TYPE_USHORT_GRAY, + }; + + private static final RescaleOp + rescale1band, rescale3band, rescale4band; + private static final LookupOp + lookup1bandbyte, lookup3bandbyte, lookup4bandbyte; + private static final LookupOp + lookup1bandshort, lookup3bandshort, lookup4bandshort; + private static final ConvolveOp + convolve3x3zero, convolve5x5zero, convolve7x7zero; + private static final ConvolveOp + convolve3x3noop, convolve5x5noop, convolve7x7noop; + + static { + rescale1band = new RescaleOp(0.5f, 10.0f, null); + rescale3band = new RescaleOp( + new float[] { 0.6f, 0.4f, 0.6f }, + new float[] { 10.0f, -3.0f, 5.0f }, + null); + rescale4band = new RescaleOp( + new float[] { 0.6f, 0.4f, 0.6f, 0.9f }, + new float[] { -1.0f, 5.0f, 3.0f, 1.0f }, + null); + + // REMIND: we should probably test non-zero offsets, but that + // would require massaging the source image data to avoid going + // outside the lookup table array bounds + int offset = 0; + { + byte invert[] = new byte[256]; + byte halved[] = new byte[256]; + for (int j = 0; j < 256 ; j++) { + invert[j] = (byte) (255-j); + halved[j] = (byte) (j / 2); + } + ByteLookupTable lut1 = new ByteLookupTable(offset, invert); + lookup1bandbyte = new LookupOp(lut1, null); + ByteLookupTable lut3 = + new ByteLookupTable(offset, + new byte[][] {invert, halved, invert}); + lookup3bandbyte = new LookupOp(lut3, null); + ByteLookupTable lut4 = + new ByteLookupTable(offset, + new byte[][] {invert, halved, invert, halved}); + lookup4bandbyte = new LookupOp(lut4, null); + } + + { + short invert[] = new short[256]; + short halved[] = new short[256]; + for (int j = 0; j < 256 ; j++) { + invert[j] = (short) ((255-j) * 255); + halved[j] = (short) ((j / 2) * 255); + } + ShortLookupTable lut1 = new ShortLookupTable(offset, invert); + lookup1bandshort = new LookupOp(lut1, null); + ShortLookupTable lut3 = + new ShortLookupTable(offset, + new short[][] {invert, halved, invert}); + lookup3bandshort = new LookupOp(lut3, null); + ShortLookupTable lut4 = + new ShortLookupTable(offset, + new short[][] {invert, halved, invert, halved}); + lookup4bandshort = new LookupOp(lut4, null); + } + + // 3x3 blur + float[] data3 = { + 0.1f, 0.1f, 0.1f, + 0.1f, 0.2f, 0.1f, + 0.1f, 0.1f, 0.1f, + }; + Kernel k3 = new Kernel(3, 3, data3); + + // 5x5 edge + float[] data5 = { + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, 24.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, + }; + Kernel k5 = new Kernel(5, 5, data5); + + // 7x7 blur + float[] data7 = { + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, + }; + Kernel k7 = new Kernel(7, 7, data7); + + convolve3x3zero = new ConvolveOp(k3, ConvolveOp.EDGE_ZERO_FILL, null); + convolve5x5zero = new ConvolveOp(k5, ConvolveOp.EDGE_ZERO_FILL, null); + convolve7x7zero = new ConvolveOp(k7, ConvolveOp.EDGE_ZERO_FILL, null); + + convolve3x3noop = new ConvolveOp(k3, ConvolveOp.EDGE_NO_OP, null); + convolve5x5noop = new ConvolveOp(k5, ConvolveOp.EDGE_NO_OP, null); + convolve7x7noop = new ConvolveOp(k7, ConvolveOp.EDGE_NO_OP, null); + } + + public void paint(Graphics g) { + + VolatileImage vimg = createVolatileImage(TESTW, TESTH); + vimg.validate(getGraphicsConfiguration()); + + Graphics2D g2d = vimg.createGraphics(); + renderTest(g2d); + g2d.dispose(); + + g.drawImage(vimg, 0, 0, null); + } + + /* + * foreach source image size (once with pow2, once with non-pow2) + * + * foreach BufferedImage type + * + * RescaleOp (1 band) + * RescaleOp (3 bands, if src has 3 bands) + * RescaleOp (4 bands, if src has 4 bands) + * + * foreach LookupTable type (once with ByteLUT, once with ShortLUT) + * LookupOp (1 band) + * LookupOp (3 bands, if src has 3 bands) + * LookupOp (4 bands, if src has 4 bands) + * + * foreach edge condition (once with ZERO_FILL, once with EDGE_NO_OP) + * ConvolveOp (3x3) + * ConvolveOp (5x5) + * ConvolveOp (7x7) + */ + private void renderTest(Graphics2D g2d) { + g2d.setColor(Color.white); + g2d.fillRect(0, 0, TESTW, TESTH); + + int yorig = 2; + int xinc = 34; + int yinc = srcSizes[0] + srcSizes[1] + 2 + 2; + + for (int srcType : srcTypes) { + int y = yorig; + + for (int srcSize : srcSizes) { + int x = 2; + System.out.printf("type=%d size=%d\n", srcType, srcSize); + + BufferedImage srcImg = makeSourceImage(srcSize, srcType); + ColorModel srcCM = srcImg.getColorModel(); + + // RescaleOp + g2d.drawImage(srcImg, rescale1band, x, y); + x += xinc; + // REMIND: 3-band RescaleOp.filter() throws IAE for images + // that contain an alpha channel (bug to be filed) + if (srcCM.getNumColorComponents() == 3 && + !(ignore && srcCM.hasAlpha())) + { + g2d.drawImage(srcImg, rescale3band, x, y); + } + x += xinc; + if (srcCM.getNumComponents() == 4) { + g2d.drawImage(srcImg, rescale4band, x, y); + } + x += xinc; + + // LookupOp + // REMIND: Our LUTs are only 256 elements long, so won't + // currently work with USHORT_GRAY data + if (srcType != BufferedImage.TYPE_USHORT_GRAY) { + g2d.drawImage(srcImg, lookup1bandbyte, x, y); + x += xinc; + if (srcCM.getNumColorComponents() == 3) { + g2d.drawImage(srcImg, lookup3bandbyte, x, y); + } + x += xinc; + if (srcCM.getNumComponents() == 4) { + g2d.drawImage(srcImg, lookup4bandbyte, x, y); + } + x += xinc; + + // REMIND: LookupOp.createCompatibleDestImage() throws + // IAE for 3BYTE_BGR/4BYTE_ABGR (bug to be filed) + if (!(ignore && + (srcType == BufferedImage.TYPE_3BYTE_BGR || + srcType == BufferedImage.TYPE_4BYTE_ABGR))) + { + g2d.drawImage(srcImg, lookup1bandshort, x, y); + x += xinc; + // REMIND: 3-band LookupOp.filter() throws IAE for + // images that contain an alpha channel + // (bug to be filed) + if (srcCM.getNumColorComponents() == 3 && + !(ignore && srcCM.hasAlpha())) + { + g2d.drawImage(srcImg, lookup3bandshort, x, y); + } + x += xinc; + if (srcCM.getNumComponents() == 4) { + g2d.drawImage(srcImg, lookup4bandshort, x, y); + } + x += xinc; + } else { + x += 3*xinc; + } + } else { + x += 6*xinc; + } + + // ConvolveOp + // REMIND: ConvolveOp.filter() throws ImagingOpException + // for 3BYTE_BGR (see 4957775) + if (srcType != BufferedImage.TYPE_3BYTE_BGR) { + g2d.drawImage(srcImg, convolve3x3zero, x, y); + x += xinc; + g2d.drawImage(srcImg, convolve5x5zero, x, y); + x += xinc; + g2d.drawImage(srcImg, convolve7x7zero, x, y); + x += xinc; + + g2d.drawImage(srcImg, convolve3x3noop, x, y); + x += xinc; + g2d.drawImage(srcImg, convolve5x5noop, x, y); + x += xinc; + g2d.drawImage(srcImg, convolve7x7noop, x, y); + x += xinc; + } else { + x += 6*xinc; + } + + y += srcSize + 2; + } + + yorig += yinc; + } + } + + private BufferedImage makeSourceImage(int size, int type) { + int s2 = size/2; + BufferedImage img = new BufferedImage(size, size, type); + Graphics2D g2d = img.createGraphics(); + g2d.setComposite(AlphaComposite.Src); + g2d.setColor(Color.orange); + g2d.fillRect(0, 0, size, size); + g2d.setColor(Color.red); + g2d.fillRect(0, 0, s2, s2); + g2d.setColor(Color.green); + g2d.fillRect(s2, 0, s2, s2); + g2d.setColor(Color.blue); + g2d.fillRect(0, s2, s2, s2); + g2d.setColor(new Color(255, 255, 0, 128)); + g2d.fillRect(s2, s2, s2, s2); + g2d.setColor(Color.pink); + g2d.fillOval(s2-3, s2-3, 6, 6); + g2d.dispose(); + return img; + } + + public BufferedImage makeReferenceImage() { + BufferedImage img = new BufferedImage(TESTW, TESTH, + BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = img.createGraphics(); + renderTest(g2d); + g2d.dispose(); + return img; + } + + public Dimension getPreferredSize() { + return new Dimension(TESTW, TESTH); + } + + private static void compareImages(BufferedImage refImg, + BufferedImage testImg, + int tolerance) + { + int x1 = 0; + int y1 = 0; + int x2 = refImg.getWidth(); + int y2 = refImg.getHeight(); + + for (int y = y1; y < y2; y++) { + for (int x = x1; x < x2; x++) { + Color expected = new Color(refImg.getRGB(x, y)); + Color actual = new Color(testImg.getRGB(x, y)); + if (!isSameColor(expected, actual, tolerance)) { + saveImage("referenceimage", refImg); + saveImage("testimage", testImg); + throw new RuntimeException("Test failed at x="+x+" y="+y+ + " (expected="+expected+ + " actual="+actual+ + ")"); + } + } + } + } + + private static boolean isSameColor(Color c1, Color c2, int e) { + int r1 = c1.getRed(); + int g1 = c1.getGreen(); + int b1 = c1.getBlue(); + int r2 = c2.getRed(); + int g2 = c2.getGreen(); + int b2 = c2.getBlue(); + int rmin = Math.max(r2-e, 0); + int gmin = Math.max(g2-e, 0); + int bmin = Math.max(b2-e, 0); + int rmax = Math.min(r2+e, 255); + int gmax = Math.min(g2+e, 255); + int bmax = Math.min(b2+e, 255); + if (r1 >= rmin && r1 <= rmax && + g1 >= gmin && g1 <= gmax && + b1 >= bmin && b1 <= bmax) + { + return true; + } + return false; + } + + + static void createUI() { + test = new DrawBufImgOp(); + Panel panel = new Panel(); + panel.add(test); + frame = new Frame("OpenGL DrawBufImgOp Test"); + frame.add(panel); + frame.setSize(TESTW+100, TESTH+100); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + + boolean show = false; + boolean dump = false; + boolean compare = false; + + for (String arg : args) { + if (arg.equals("-show")) { + show = true; + } else if (arg.equals("-dump")) { + dump = true; + } else if (arg.equals("-compare")) { + compare = true; + } else if (arg.equals("-ignore")) { + ignore = true; + } + } + + Robot robot = new Robot(); + + EventQueue.invokeAndWait(DrawBufImgOp::createUI); + + robot.waitForIdle(); + robot.delay(2000); + + BufferedImage capture = null; + try { + GraphicsConfiguration gc = frame.getGraphicsConfiguration(); + if (gc.getColorModel() instanceof IndexColorModel) { + System.out.println("IndexColorModel detected: " + + "test considered PASSED"); + return; + } + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, TESTW, TESTH); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Compare the images (allow for +/- 1 bit differences in color comps) + if (dump || compare) { + BufferedImage ref = test.makeReferenceImage(); + if (dump) { + saveImage("DrawBufImgOp_ref", ref); + saveImage("DrawBufImgOp_cap", capture); + } + if (compare) { + test.compareImages(ref, capture, 1); + } + } + } + + static void saveImage(String name, BufferedImage img) { + try { + File file = new File(name + ".png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/DrawImageBg.java b/test/jdk/sun/java2d/OpenGL/DrawImageBg.java new file mode 100644 index 00000000000..7fc38d91b06 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/DrawImageBg.java @@ -0,0 +1,145 @@ +/* + * 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 + * 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 4993274 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that managed image copies and transforms work properly + * with the OGL pipeline when a background color is specified. + * @run main/othervm -Dsun.java2d.opengl=True DrawImageBg + * @run main/othervm DrawImageBg + */ + +/* + * @test + * @bug 4993274 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that managed image copies and transforms work properly + * with the OGL pipeline when a background color is specified. + * @run main/othervm -Dsun.java2d.opengl=True DrawImageBg + * @run main/othervm DrawImageBg + */ + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Transparency; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class DrawImageBg extends Panel { + + static volatile Frame frame; + static volatile DrawImageBg test; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + g2d.setColor(Color.black); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + BufferedImage img = getGraphicsConfiguration().createCompatibleImage(50, 50, + Transparency.BITMASK); + Graphics2D gimg = img.createGraphics(); + gimg.setComposite(AlphaComposite.Src); + gimg.setColor(new Color(0, 0, 0, 0)); + gimg.fillRect(0, 0, 50, 50); + gimg.setColor(Color.red); + gimg.fillRect(10, 10, 30, 30); + gimg.dispose(); + + g2d.drawImage(img, 10, 10, Color.blue, null); + + // draw a second time to ensure that the cached copy is used + g2d.drawImage(img, 80, 10, Color.blue, null); + } + + static void createUI() { + frame = new Frame("OpenGL DrawImageBg Test"); + test = new DrawImageBg(); + frame.add(test); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + + BufferedImage capture = null; + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(DrawImageBg::createUI); + robot.waitForIdle(); + robot.delay(3000); + + // Grab the screen region + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x+80, pt1.y, 80, 80); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + if (capture == null) { + throw new RuntimeException("Screen capture is null"); + } + + // Test inner and outer pixels + int pixel1 = capture.getRGB(5, 10); + if (pixel1 != 0xff0000ff) { + saveImage(capture); + throw new RuntimeException(getMsg("outer", pixel1)); + } + int pixel2 = capture.getRGB(25, 25); + if (pixel2 != 0xffff0000) { + saveImage(capture); + throw new RuntimeException(getMsg("inner", pixel2)); + } + } + + static String getMsg(String r, int p1) { + return "Failed: Incorrect color for " + r + " pixel: got " + Integer.toHexString(p1); + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/LargeOps.java b/test/jdk/sun/java2d/OpenGL/LargeOps.java new file mode 100644 index 00000000000..ace60b7a3c4 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/LargeOps.java @@ -0,0 +1,138 @@ +/* + * 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 + * 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 6219284 6358147 6274813 6578452 + * @key headful + * @summary Verifies that OGLRenderer.drawPoly(), + * OGLTextRenderer.drawGlyphList(), and OGLMaskFill work properly when the + * operation parameters exceed the capacity of the render queue. With the + * single-threaded OpenGL pipeline, there are some operations that require + * a separate buffer to be spawned if the parameters cannot fit entirely on + * the standard buffer. This test exercises this special case. + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.lcdshader=true LargeOps + */ + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Robot; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class LargeOps extends Canvas { + + private static final int NUM_POINTS = 8000; + private int[] xPoints, yPoints; + private String str; + + public LargeOps() { + xPoints = new int[NUM_POINTS]; + yPoints = new int[NUM_POINTS]; + for (int i = 0; i < NUM_POINTS; i++) { + xPoints[i] = (i % 2 == 0) ? 10 : 400; + yPoints[i] = (i % 2 == 1) ? i+3 : i; + } + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < NUM_POINTS; i+=11) { + sb.append("ThisIsATest"); + } + str = sb.toString(); + } + + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D)g; + g2d.setColor(Color.white); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + // draw large polyline + g2d.setColor(Color.green); + g2d.drawPolyline(xPoints, yPoints, NUM_POINTS); + + // draw long string + g2d.setColor(Color.blue); + g2d.drawString(str, 10, 100); + + // draw long string with larger pt size + Font font = g2d.getFont(); + g2d.setFont(font.deriveFont(40.0f)); + g2d.drawString(str, 10, 150); + + // do the same with LCD hints enabled + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); + g2d.setFont(font); + g2d.drawString(str, 10, 200); + g2d.setFont(font.deriveFont(43.0f)); + g2d.drawString(str, 10, 250); + + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR); + g2d.setFont(font); + g2d.drawString(str, 10, 300); + g2d.setFont(font.deriveFont(37.0f)); + g2d.drawString(str, 10, 350); + } + + static volatile Frame frame; + static volatile LargeOps test; + + static void createUI() { + frame = new Frame("OpenGL LargeOps Test"); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + frame.dispose(); + } + }); + test = new LargeOps(); + frame.add(test); + frame.setSize(600, 600); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + EventQueue.invokeAndWait(LargeOps::createUI); + robot.waitForIdle(); + robot.delay(6000); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/OpaqueDest.java b/test/jdk/sun/java2d/OpenGL/OpaqueDest.java new file mode 100644 index 00000000000..50896316109 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/OpaqueDest.java @@ -0,0 +1,180 @@ +/* + * 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 + * 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 6277977 6319663 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that blending operations do not inadvertantly leave + * non-opaque alpha values in the framebuffer. Note that this test is + * intended to run on GraphicsConfigs that support a stored alpha channel + * (to verify the bug at hand), but it is also a useful for testing the + * compositing results on any configuration. + * @run main/othervm -Dsun.java2d.opengl=True OpaqueDest + * @run main/othervm OpaqueDest + */ + +/* + * @test + * @bug 6277977 6319663 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that blending operations do not inadvertantly leave + * non-opaque alpha values in the framebuffer. Note that this test is + * intended to run on GraphicsConfigs that support a stored alpha channel + * (to verify the bug at hand), but it is also a useful for testing the + * compositing results on any configuration. + * @run main/othervm -Dsun.java2d.opengl=True OpaqueDest + * @run main/othervm OpaqueDest + */ + +import java.awt.AlphaComposite; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; +import java.io.File; +import javax.imageio.ImageIO; + +public class OpaqueDest extends Canvas { + + private static volatile Frame frame; + private static volatile OpaqueDest test; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + + g2d.setColor(Color.red); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + // This will clear the rectangle to black + g2d.setComposite(AlphaComposite.Clear); + g2d.fillRect(10, 10, 80, 80); + + // If everything is working properly, then this will fill the + // rectangle with red again. Before this bug was fixed, the previous + // Clear operation would leave zero values in the destination's + // alpha channel (if present), and therefore a SrcIn operation + // would result in all-black. + g2d.setComposite(AlphaComposite.SrcIn); + g2d.fillRect(10, 10, 80, 80); + } + + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } + + static void createUI() { + test = new OpaqueDest(); + frame = new Frame("OpenGL OpaqueDest Test"); + Panel p = new Panel(); + p.add(test); + frame.add(p); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(OpaqueDest::createUI); + + robot.waitForIdle(); + robot.delay(2000); + + BufferedImage capture = null; + try { + GraphicsConfiguration gc = frame.getGraphicsConfiguration(); + if (gc.getColorModel() instanceof IndexColorModel) { + System.out.println("IndexColorModel detected: " + + "test considered PASSED"); + return; + } + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 100, 100); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + + // Test all pixels (every one should be red) + for (int y = 0; y < 100; y++) { + for (int x = 0; x < 100; x++) { + int actual = capture.getRGB(x, y); + int expected = 0xffff0000; + if (!similar(actual, expected)) { + saveImage(capture); + throw new RuntimeException("Test failed at x="+x+" y="+y+ + " (expected="+ + Integer.toHexString(expected) + + " actual="+ + Integer.toHexString(actual) + + ")"); + } + } + } + } + + static boolean similar(int p1, int p2) { + int a1 = (p1 >> 24) & 0xff; + int r1 = (p1 >> 16) & 0xff; + int g1 = (p1 >> 8) & 0xff; + int b1 = p1 & 0xff; + int a2 = (p2 >> 24) & 0xff; + int r2 = (p2 >> 16) & 0xff; + int g2 = (p2 >> 8) & 0xff; + int b2 = p2 & 0xff; + + int allowedDiff = 0x01; // tiny rounding error allowed. + return + (Math.abs(a1 - a2) <= allowedDiff) && + (Math.abs(r1 - r2) <= allowedDiff) && + (Math.abs(g1 - g2) <= allowedDiff) && + (Math.abs(b1 - b2) <= allowedDiff); + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/ScaleParamsOOB.java b/test/jdk/sun/java2d/OpenGL/ScaleParamsOOB.java new file mode 100644 index 00000000000..b3d866cfd75 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/ScaleParamsOOB.java @@ -0,0 +1,198 @@ +/* + * 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 + * 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 5104584 8237244 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that scaling an image works properly when the + * source parameters are outside the source bounds. + * @run main/othervm -Dsun.java2d.opengl=True ScaleParamsOOB + * @run main/othervm ScaleParamsOOB + */ + +/* + * @test + * @bug 5104584 8237244 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that scaling an image works properly when the + * source parameters are outside the source bounds. + * @run main/othervm -Dsun.java2d.opengl=True ScaleParamsOOB + * @run main/othervm ScaleParamsOOB + */ + + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class ScaleParamsOOB extends Panel { + + private static final int TOLERANCE = 12; + + private static volatile ScaleParamsOOB test; + private static volatile Frame frame; + + private BufferedImage img; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + g2d.setColor(Color.black); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + BufferedImage img = getGraphicsConfiguration().createCompatibleImage(40, 40); + Graphics2D gimg = img.createGraphics(); + gimg.setColor(Color.red); + gimg.fillRect(0, 0, 40, 40); + gimg.dispose(); + + // first time will be a sw->surface blit + g2d.drawImage(img, + 10, 10, 90, 90, + -60, -60, 100, 100, + null); + + // second time will be a texture->surface blit + g2d.drawImage(img, + 110, 10, 190, 90, + -60, -60, 100, 100, + null); + } + + public Dimension getPreferredSize() { + return new Dimension(300, 200); + } + + private static void testRegion(BufferedImage bi, + Rectangle wholeRegion, + Rectangle affectedRegion) + { + int x1 = wholeRegion.x; + int y1 = wholeRegion.y; + int x2 = x1 + wholeRegion.width; + int y2 = y1 + wholeRegion.height; + + for (int y = y1; y < y2; y++) { + for (int x = x1; x < x2; x++) { + int actual = bi.getRGB(x, y); + int expected = 0; + if (affectedRegion.contains(x, y)) { + expected = Color.red.getRGB(); + } else { + expected = Color.black.getRGB(); + } + int alpha = (actual >> 24) & 0xFF; + int red = (actual >> 16) & 0xFF; + int green = (actual >> 8) & 0xFF; + int blue = (actual) & 0xFF; + + int standardAlpha = (expected >> 24) & 0xFF; + int standardRed = (expected >> 16) & 0xFF; + int standardGreen = (expected >> 8) & 0xFF; + int standardBlue = (expected) & 0xFF; + + if ((Math.abs(alpha - standardAlpha) > TOLERANCE) || + (Math.abs(red - standardRed) > TOLERANCE) || + (Math.abs(green - standardGreen) > TOLERANCE) || + (Math.abs(blue - standardBlue) > TOLERANCE)) { + saveImage(bi); + throw new RuntimeException("Test failed at x="+x+" y="+y+ + " (expected="+ + Integer.toHexString(expected) + + " actual="+ + Integer.toHexString(actual) + + ")"); + } + } + } + } + + private static void createAndShowGUI() { + test = new ScaleParamsOOB(); + frame = new Frame("OpenGL ScaleParamsOOB Test"); + frame.setAlwaysOnTop(true); + frame.add(test); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(() -> createAndShowGUI()); + + robot.waitForIdle(); + robot.delay(2000); + + // Grab the screen region + BufferedImage capture = null; + try { + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 200, 200); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Test background color + int pixel = capture.getRGB(5, 5); + if (pixel != 0xff000000) { + saveImage(capture); + throw new RuntimeException("Failed: Incorrect color for " + + "background: " + Integer.toHexString(pixel)); + } + + // Test pixels + testRegion(capture, + new Rectangle(5, 5, 90, 90), + new Rectangle(40, 40, 20, 20)); + testRegion(capture, + new Rectangle(105, 5, 90, 90), + new Rectangle(140, 40, 20, 20)); + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/ShapeClip.java b/test/jdk/sun/java2d/OpenGL/ShapeClip.java new file mode 100644 index 00000000000..f50b7aff5a6 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/ShapeClip.java @@ -0,0 +1,140 @@ +/* + * 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 + * 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 5002133 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that the OpenGL pipeline does not affect the color + * buffer when setting up a complex (shape) clip region. The test fails if + * the circular clip region is filled with a green color (the green region + * should not be visible at all). + * @run main/othervm -Dsun.java2d.opengl=True ShapeClip + * @run main/othervm ShapeClip + */ + +/* + * @test + * @bug 5002133 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that the OpenGL pipeline does not affect the color + * buffer when setting up a complex (shape) clip region. The test fails if + * the circular clip region is filled with a green color (the green region + * should not be visible at all). + * @run main/othervm -Dsun.java2d.opengl=True ShapeClip + * @run main/othervm ShapeClip + */ + +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.geom.Ellipse2D; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class ShapeClip extends Panel { + + private static volatile Frame frame; + private static volatile ShapeClip test; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + + int width = getWidth(); + int height = getHeight(); + + g2d.setColor(Color.black); + g2d.fillRect(0, 0, width, height); + + g2d.setColor(Color.green); + g2d.fillRect(0, 0, 1, 1); + g2d.setClip(new Ellipse2D.Double(10, 10, 100, 100)); + g2d.setColor(Color.blue); + g2d.fillRect(30, 30, 20, 20); + } + + static void createUI() { + test = new ShapeClip(); + frame = new Frame("OpenGL ShapeClip Test"); + frame.add(test); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(ShapeClip::createUI); + + robot.waitForIdle(); + robot.delay(2000); + + // Grab the screen region + BufferedImage capture = null; + try { + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 80, 80); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Test blue rectangle + int pixel1 = capture.getRGB(40, 40); + if (pixel1 != 0xff0000ff) { + saveImage(capture); + throw new RuntimeException("Failed: Incorrect color for " + + "rectangle " + Integer.toHexString(pixel1)); + } + + // Test clip region (should be same color as background) + int pixel2 = capture.getRGB(60, 40); + if (pixel2 != 0xff000000) { + saveImage(capture); + throw new RuntimeException("Failed: Incorrect color for " + + "clip region " + Integer.toHexString(pixel2)); + } + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/SrcMaskOps.java b/test/jdk/sun/java2d/OpenGL/SrcMaskOps.java new file mode 100644 index 00000000000..9908cffdefb --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/SrcMaskOps.java @@ -0,0 +1,188 @@ +/* + * 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 + * 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 4942939 4970674 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that OGLMaskFill, OGLMaskBlit, and OGLTextRenderer + * operations work properly for non-SrcOver composites. + * @run main/othervm -Dsun.java2d.opengl=True SrcMaskOps + * @run main/othervm SrcMaskOps + */ + +/* + * @test + * @bug 4942939 4970674 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that OGLMaskFill, OGLMaskBlit, and OGLTextRenderer + * operations work properly for non-SrcOver composites. + * @run main/othervm -Dsun.java2d.opengl=True SrcMaskOps + * @run main/othervm SrcMaskOps + */ + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.Frame; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class SrcMaskOps extends Panel { + + static volatile Frame frame; + static volatile SrcMaskOps test; + + static final int SRX = 50; + static final int SRY = 50; + static final int GPX = 90; + static final int GPY = 50; + static final int DTX = 120; + static final int DTY = 70; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + + g2d.setColor(Color.white); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setComposite(AlphaComposite.Src); + + g2d.setColor(Color.blue); + g2d.drawRect(SRX, SRY, 20, 20); + + g2d.setPaint(new GradientPaint(0.0f, 0.0f, Color.red, + 100.0f, 100.f, Color.red, true)); + g2d.drawRect(GPX, GPY, 20, 20); + + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + + g2d.setColor(Color.red); + Font font = new Font(Font.DIALOG, Font.PLAIN, 20); + g2d.setFont(font); + g2d.drawString("HELLO", DTX, DTY); + } + + static void createUI() { + frame = new Frame("OpenGL SrcMaskOps Test"); + test = new SrcMaskOps(); + frame.add(test); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + + Robot robot = new Robot(); + BufferedImage capture = null; + try { + EventQueue.invokeAndWait(SrcMaskOps::createUI); + robot.waitForIdle(); + robot.delay(3000); + + // Grab the screen region + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 300, 300); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Test solid rectangle + int pixel1, pixel2; + pixel1 = capture.getRGB(SRX, SRY); + pixel2 = capture.getRGB(SRX+2, SRY+2); + if (!similar(pixel1, 0xff0000ff) || !similar(pixel2, 0xffffffff)) { + saveImage(capture); + throw new RuntimeException(getMsg("solid rectangle", pixel1, pixel2)); + } + + // Test GradientPaint rectangle + pixel1 = capture.getRGB(GPX, GPY); + pixel2 = capture.getRGB(GPX+2, GPY+2); + if (!similar(pixel1, 0xffff0000) || !similar(pixel2, 0xffffffff)) { + saveImage(capture); + throw new RuntimeException(getMsg("GradientPaint rectangle", pixel1, pixel2)); + } + + // Test solid text + pixel1 = capture.getRGB(DTX+2, DTY-5); + pixel2 = capture.getRGB(DTX+5, DTY-5); + if (!similar(pixel1, 0xffff0000) || !similar(pixel2, 0xffffffff)) { + saveImage(capture); + throw new RuntimeException(getMsg("solid text", pixel1, pixel2)); + } + + } + + static boolean similar(int p1, int p2) { + int a1 = (p1 >> 24) & 0xff; + int r1 = (p1 >> 16) & 0xff; + int g1 = (p1 >> 8) & 0xff; + int b1 = p1 & 0xff; + int a2 = (p2 >> 24) & 0xff; + int r2 = (p2 >> 16) & 0xff; + int g2 = (p2 >> 8) & 0xff; + int b2 = p2 & 0xff; + + int allowedDiff = 0x10; + return + (Math.abs(a1 - a2) <= allowedDiff) && + (Math.abs(r1 - r2) <= allowedDiff) && + (Math.abs(g1 - g2) <= allowedDiff) && + (Math.abs(b1 - b2) <= allowedDiff); + } + + static String getMsg(String r, int p1, int p2) { + return "Failed: Incorrect color[s] for " + r + " got " + + Integer.toHexString(p1) + " and " + Integer.toHexString(p2); + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/java2d/OpenGL/VolatileSubRegion.java b/test/jdk/sun/java2d/OpenGL/VolatileSubRegion.java new file mode 100644 index 00000000000..7ec350bc958 --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/VolatileSubRegion.java @@ -0,0 +1,166 @@ +/* + * 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 + * 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 6244071 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that copying a subregion from a VolatileImage works + * properly with the OGL pipeline. + * @run main/othervm VolatileSubRegion + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=true VolatileSubRegion + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=false VolatileSubRegion + */ + +/* + * @test + * @bug 6244071 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that copying a subregion from a VolatileImage works + * properly with the OGL pipeline. + * @run main/othervm VolatileSubRegion + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=true VolatileSubRegion + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=false VolatileSubRegion + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; +import java.awt.image.VolatileImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class VolatileSubRegion extends Panel { + + private VolatileImage img; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + + if (img == null) { + img = createVolatileImage(200, 200); + Graphics2D goff = img.createGraphics(); + goff.setColor(Color.green); + goff.fillRect(50, 0, 100, 50); + goff.setColor(Color.blue); + goff.fillRect(0, 0, 200, 200); + goff.setColor(Color.red); + goff.fillRect(50, 50, 100, 100); + goff.setColor(Color.yellow); + goff.fillRect(50, 150, 100, 50); + goff.dispose(); + } + + g2d.setColor(Color.white); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + g2d.drawImage(img, + 50, 50, 200, 200, + 50, 50, 200, 200, + null); + + } + + + private static volatile VolatileSubRegion test; + private static volatile Frame frame; + + static void createUI() { + test = new VolatileSubRegion(); + frame = new Frame("OpenGL VolatileSubRegion Test"); + frame.add(test); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(VolatileSubRegion::createUI); + + robot.waitForIdle(); + robot.delay(2000); + + BufferedImage capture = null; + try { + GraphicsConfiguration gc = frame.getGraphicsConfiguration(); + if (gc.getColorModel() instanceof IndexColorModel) { + System.out.println("IndexColorModel detected: " + + "test considered PASSED"); + return; + } + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 200, 200); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Test pixels + int pixel1 = capture.getRGB(49, 50); + if (pixel1 != 0xffffffff) { + saveImage(capture); + throw new RuntimeException(getMsg("background pixel", pixel1)); + } + int pixel2 = capture.getRGB(50, 50); + if (pixel2 != 0xffff0000) { + saveImage(capture); + throw new RuntimeException(getMsg("red region", pixel2)); + } + int pixel3 = capture.getRGB(50, 150); + if (pixel3 != 0xffffff00) { + saveImage(capture); + throw new RuntimeException(getMsg("yellow region", pixel3)); + } + } + + static String getMsg(String r, int p1) { + return "Failed: Incorrect color for " + r + " : got " + Integer.toHexString(p1); + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/test/jdk/sun/java2d/OpenGL/XformVolatile.java b/test/jdk/sun/java2d/OpenGL/XformVolatile.java new file mode 100644 index 00000000000..44e7c7ee8ba --- /dev/null +++ b/test/jdk/sun/java2d/OpenGL/XformVolatile.java @@ -0,0 +1,146 @@ +/* + * 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 + * 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 4970836 + * @key headful + * @requires (os.family != "mac") + * @summary Verifies that transformed VolatileImage copies work properly with + * the OGL pipeline. + * @run main/othervm XformVolatile + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=true XformVolatile + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=false XformVolatile + */ + +/* + * @test + * @bug 4970836 + * @key headful + * @requires (os.family == "mac") + * @summary Verifies that transformed VolatileImage copies work properly with + * the OGL pipeline. + * @run main/othervm XformVolatile + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=true XformVolatile + * @run main/othervm -Dsun.java2d.opengl=True -Dsun.java2d.opengl.fbobject=false XformVolatile + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class XformVolatile extends Panel { + + private static volatile Frame frame; + private static volatile XformVolatile test; + private volatile VolatileImage img; + + public void paint(Graphics g) { + + Graphics2D g2d = (Graphics2D)g; + + if (img == null) { + img = createVolatileImage(200, 200); + Graphics2D goff = img.createGraphics(); + goff.setColor(Color.blue); + goff.fillRect(0, 0, 200, 200); + goff.setColor(Color.red); + goff.fillPolygon(new int[] {10, 100, 190}, + new int[] {190, 10, 190}, 3); + goff.dispose(); + } + + g2d.setColor(Color.black); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + g2d.rotate(Math.toRadians(3.0)); + g2d.drawImage(img, 0, 0, null); + } + + static void createUI() { + test = new XformVolatile(); + frame = new Frame("OpenGL XformVolatile Test"); + frame.add(test); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + + Robot robot = new Robot(); + + EventQueue.invokeAndWait(XformVolatile::createUI); + + robot.waitForIdle(); + robot.delay(2000); + + // Grab the screen region + BufferedImage capture = null; + try { + Point pt1 = test.getLocationOnScreen(); + Rectangle rect = new Rectangle(pt1.x, pt1.y, 200, 200); + capture = robot.createScreenCapture(rect); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + // Test inner and outer pixels + int pixel1 = capture.getRGB(5, 175); + if (pixel1 != 0xff0000ff) { + saveImage(capture); + throw new RuntimeException(getMsg("inner", pixel1)); + } + int pixel2 = capture.getRGB(5, 188); + if (pixel2 != 0xffff0000) { + saveImage(capture); + throw new RuntimeException(getMsg("inner", pixel2)); + } + } + + static String getMsg(String r, int p1) { + return "Failed: Incorrect color for " + r + " pixel: got " + Integer.toHexString(p1); + } + + static void saveImage(BufferedImage img) { + try { + File file = new File("capture.png"); + ImageIO.write(img, "png", file); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java b/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java index 2d5ba81194f..f113e7d3fcd 100644 --- a/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java +++ b/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, 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 @@ -27,10 +27,8 @@ * @summary Test that URL connections to multi-release jars can be runtime versioned * @library /lib/testlibrary/java/util/jar /test/lib * @modules jdk.compiler - * jdk.httpserver * jdk.jartool * @build CreateMultiReleaseTestJars - * jdk.test.lib.net.SimpleHttpServer * jdk.test.lib.util.JarBuilder * jdk.test.lib.compiler.Compiler * @run testng MultiReleaseJarURLConnection @@ -51,11 +49,15 @@ import java.net.URLClassLoader; import java.net.URLConnection; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.Enumeration; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.jar.JarFile; -import jdk.test.lib.net.SimpleHttpServer; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; import jdk.test.lib.net.URIBuilder; import org.testng.Assert; import org.testng.annotations.AfterClass; @@ -68,8 +70,8 @@ public class MultiReleaseJarURLConnection { String unversioned = userdir + "/unversioned.jar"; String unsigned = userdir + "/multi-release.jar"; String signed = userdir + "/signed-multi-release.jar"; - static final String TESTCONTEXT = "/multi-release.jar"; - SimpleHttpServer server; + HttpServer server; + ExecutorService executor; @BeforeClass public void initialize() throws Exception { @@ -78,7 +80,10 @@ public void initialize() throws Exception { creator.buildUnversionedJar(); creator.buildMultiReleaseJar(); creator.buildSignedMultiReleaseJar(); - server = new SimpleHttpServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), TESTCONTEXT, System.getProperty("user.dir", ".")); + server = SimpleFileServer.createFileServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), + Path.of(System.getProperty("user.dir", ".")), SimpleFileServer.OutputLevel.INFO); + executor = Executors.newCachedThreadPool(); + server.setExecutor(executor); server.start(); } @@ -86,7 +91,9 @@ public void initialize() throws Exception { public void close() throws IOException { // Windows requires server to stop before file is deleted if (server != null) - server.stop(); + server.stop(0); + executor.shutdown(); + Files.delete(Paths.get(unversioned)); Files.delete(Paths.get(unsigned)); Files.delete(Paths.get(signed)); @@ -176,8 +183,8 @@ public Object[][] createResourceData() throws Exception { {"unsigned", new URL("jar:file:" + unsigned + "!/")}, {"signed", new URL("jar:file:" + signed + "!/")}, // external jar received via http protocol - {"http", toHttpJarURL(server.getPort(), "/multi-release.jar", "!/")}, - {"http", URIBuilder.newBuilder().scheme("http").port(server.getPort()) + {"http", toHttpJarURL(server.getAddress().getPort(), "/multi-release.jar", "!/")}, + {"http", URIBuilder.newBuilder().scheme("http").port(server.getAddress().getPort()) .loopback().path("/multi-release.jar").toURL()}, }; } diff --git a/test/jdk/sun/nio/cs/mapping/CoderTest.java b/test/jdk/sun/nio/cs/mapping/CoderTest.java index 05913a40535..2f766736743 100644 --- a/test/jdk/sun/nio/cs/mapping/CoderTest.java +++ b/test/jdk/sun/nio/cs/mapping/CoderTest.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 @@ -22,7 +22,7 @@ */ /* @test - @bug 4691554 6221056 6380723 6404504 6419565 6529796 8301119 + @bug 4691554 6221056 6380723 6404504 6419565 6529796 8301119 8368845 @summary Test the supported New I/O coders @modules jdk.charsets @run main CoderTest diff --git a/test/jdk/sun/nio/cs/mapping/ConverterTest.java b/test/jdk/sun/nio/cs/mapping/ConverterTest.java index be8df03230c..8d33670b0a5 100644 --- a/test/jdk/sun/nio/cs/mapping/ConverterTest.java +++ b/test/jdk/sun/nio/cs/mapping/ConverterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,8 @@ * @summary test Bug 4199484 * @modules jdk.charsets * @run main ConverterTest - * @bug 4199484 4199599 4199601 4199602 4159519 4201529 4199604 4201532 4947038 6217210 + * @bug 4199484 4199599 4199601 4199602 4159519 4201529 4199604 4201532 4947038 + * 6217210 8368845 */ import java.util.*; diff --git a/test/jdk/sun/nio/cs/mapping/Cp930.b2c b/test/jdk/sun/nio/cs/mapping/Cp930.b2c index 67cc93fd628..3cd45375e2d 100644 --- a/test/jdk/sun/nio/cs/mapping/Cp930.b2c +++ b/test/jdk/sun/nio/cs/mapping/Cp930.b2c @@ -340,7 +340,7 @@ F9 0039 0E425D0F FF09 0E425E0F FF1B 0E425F0F FFE2 -0E42600F 2212 +0E42600F FF0D 0E42610F FF0F 0E426A0F FFE4 0E426B0F FF0C diff --git a/test/jdk/sun/nio/cs/mapping/TestConv.java b/test/jdk/sun/nio/cs/mapping/TestConv.java index 2f4ea424f6c..3bd0b15a7d3 100644 --- a/test/jdk/sun/nio/cs/mapping/TestConv.java +++ b/test/jdk/sun/nio/cs/mapping/TestConv.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* @test - @bug 4179153 4652234 6529796 + @bug 4179153 4652234 6529796 8368845 @summary Read code mapping table and check code conversion @modules jdk.charsets */ diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index 56127f86792..8454f3ac463 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -779,7 +779,12 @@ private static Path fetchNssLib(String osId, Path libraryName) throws IOExceptio } private static Path fetchNssLib(Class clazz, Path libraryName) throws IOException { - Path p = ArtifactResolver.fetchOne(clazz); + Path p; + try { + p = ArtifactResolver.fetchOne(clazz); + } catch (IOException exc) { + throw new SkippedException("Could not find NSS", exc); + } return findNSSLibrary(p, libraryName); } diff --git a/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java b/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java index 81a8c8eac9f..e75bcc44767 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java +++ b/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8014618 + * @bug 8014618 8368694 * @summary Need to strip leading zeros in TlsPremasterSecret of DHKeyAgreement * @library /test/lib .. * @author Pasi Eronen @@ -87,6 +87,26 @@ public void main(Provider p) throws Exception { throw new Exception("First byte is not zero as expected"); } + // generate generic shared secret + aliceKeyAgree.init(alicePrivKey); + aliceKeyAgree.doPhase(bobPubKey, true); + byte[] genericSecret = + aliceKeyAgree.generateSecret("Generic").getEncoded(); + System.out.println("generic secret:\n" + HEX.formatHex(genericSecret)); + + // verify that leading zero is present + if (genericSecret.length != 128) { + throw new Exception("Unexpected generic secret length"); + } + if (genericSecret[0] != 0) { + throw new Exception("First byte is not zero as expected"); + } + for (int i = 0; i < genericSecret.length; i++) { + if (genericSecret[i] != sharedSecret[i]) { + throw new Exception("Shared secrets differ"); + } + } + // now, test TLS premaster secret aliceKeyAgree.init(alicePrivKey); aliceKeyAgree.doPhase(bobPubKey, true); diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java b/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java similarity index 93% rename from test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java rename to test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java index c0af4d71498..c227e99d12b 100644 --- a/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java +++ b/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java @@ -24,16 +24,18 @@ /* * @test - * @bug 8029661 8325164 8368073 + * @bug 8029661 8325164 8368073 8368514 8368520 * @summary Test TLS 1.2 and TLS 1.3 * @modules java.base/sun.security.internal.spec * java.base/sun.security.util * java.base/com.sun.crypto.provider * @library /test/lib ../.. * @run main/othervm/timeout=120 -Djdk.tls.client.protocols=TLSv1.2 - * -Djdk.tls.useExtendedMasterSecret=false FipsModeTLS12 - * @comment SunPKCS11 does not support (TLS1.2) SunTlsExtendedMasterSecret yet - * @run main/othervm/timeout=120 -Djdk.tls.client.protocols=TLSv1.3 FipsModeTLS12 + * -Djdk.tls.useExtendedMasterSecret=false + * -Djdk.tls.client.enableSessionTicketExtension=false FipsModeTLS + * @comment SunPKCS11 does not support (TLS1.2) SunTlsExtendedMasterSecret yet. + * Stateless resumption doesn't currently work with NSS-FIPS, see JDK-8368669 + * @run main/othervm/timeout=120 -Djdk.tls.client.protocols=TLSv1.3 FipsModeTLS */ import java.io.File; @@ -73,7 +75,7 @@ import sun.security.internal.spec.TlsPrfParameterSpec; import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; -public final class FipsModeTLS12 extends SecmodTest { +public final class FipsModeTLS extends SecmodTest { private static final boolean enableDebug = true; @@ -86,6 +88,9 @@ public final class FipsModeTLS12 extends SecmodTest { private static PublicKey publicKey; public static void main(String[] args) throws Exception { + // reduce the limit to trigger a key update later + Security.setProperty("jdk.tls.keyLimits", + "AES/GCM/NoPadding KeyUpdate 10000"); try { initialize(); } catch (Exception e) { @@ -101,8 +106,9 @@ public static void main(String[] args) throws Exception { // Test against JCE testTlsAuthenticationCodeGeneration(); - // Self-integrity test (complete TLS 1.2 communication) - new testTLS12SunPKCS11Communication().run(); + // Self-integrity test (complete TLS communication) + testTLSSunPKCS11Communication.initSslContext(); + testTLSSunPKCS11Communication.run(); System.out.println("Test PASS - OK"); } else { @@ -269,15 +275,18 @@ private static void testTlsAuthenticationCodeGeneration() } } - private static class testTLS12SunPKCS11Communication { + private static class testTLSSunPKCS11Communication { public static void run() throws Exception { SSLEngine[][] enginesToTest = getSSLEnginesToTest(); - + boolean firstSession = true; for (SSLEngine[] engineToTest : enginesToTest) { SSLEngine clientSSLEngine = engineToTest[0]; SSLEngine serverSSLEngine = engineToTest[1]; - + // The first connection needs to do a full handshake. + // Verify that subsequent handshakes use resumption. + clientSSLEngine.setEnableSessionCreation(firstSession); + firstSession = false; // SSLEngine code based on RedhandshakeFinished.java boolean dataDone = false; @@ -299,10 +308,11 @@ public static void run() throws Exception { cTOs = ByteBuffer.allocateDirect(netBufferMax); sTOc = ByteBuffer.allocateDirect(netBufferMax); + // big enough to trigger a key update clientOut = ByteBuffer.wrap( - "Hi Server, I'm Client".getBytes()); + "a".repeat(16000).getBytes()); serverOut = ByteBuffer.wrap( - "Hello Client, I'm Server".getBytes()); + "b".repeat(16000).getBytes()); SSLEngineResult clientResult; SSLEngineResult serverResult; @@ -400,14 +410,6 @@ private static SSLEngine[][] getSSLEnginesToTest() throws Exception { static private SSLEngine createSSLEngine(boolean client) throws Exception { SSLEngine ssle; - KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX", "SunJSSE"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX", "SunJSSE"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLS", "SunJSSE"); - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); ssle = sslCtx.createSSLEngine("localhost", 443); ssle.setUseClientMode(client); SSLParameters sslParameters = ssle.getSSLParameters(); @@ -431,6 +433,18 @@ static private SSLEngine createSSLEngine(boolean client) return ssle; } + + private static SSLContext sslCtx; + private static void initSslContext() throws Exception { + KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX", "SunJSSE"); + kmf.init(ks, passphrase); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX", "SunJSSE"); + tmf.init(ts); + + sslCtx = SSLContext.getInstance("TLS", "SunJSSE"); + sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + } } private static void initialize() throws Exception { diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/cert8.db b/test/jdk/sun/security/pkcs11/tls/fips/cert8.db similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/cert8.db rename to test/jdk/sun/security/pkcs11/tls/fips/cert8.db diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/cert9.db b/test/jdk/sun/security/pkcs11/tls/fips/cert9.db similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/cert9.db rename to test/jdk/sun/security/pkcs11/tls/fips/cert9.db diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/key3.db b/test/jdk/sun/security/pkcs11/tls/fips/key3.db similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/key3.db rename to test/jdk/sun/security/pkcs11/tls/fips/key3.db diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/key4.db b/test/jdk/sun/security/pkcs11/tls/fips/key4.db similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/key4.db rename to test/jdk/sun/security/pkcs11/tls/fips/key4.db diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/keystore b/test/jdk/sun/security/pkcs11/tls/fips/keystore similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/keystore rename to test/jdk/sun/security/pkcs11/tls/fips/keystore diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/nss.cfg b/test/jdk/sun/security/pkcs11/tls/fips/nss.cfg similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/nss.cfg rename to test/jdk/sun/security/pkcs11/tls/fips/nss.cfg diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/pkcs11.txt b/test/jdk/sun/security/pkcs11/tls/fips/pkcs11.txt similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/pkcs11.txt rename to test/jdk/sun/security/pkcs11/tls/fips/pkcs11.txt diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/secmod.db b/test/jdk/sun/security/pkcs11/tls/fips/secmod.db similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/secmod.db rename to test/jdk/sun/security/pkcs11/tls/fips/secmod.db diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineEmptyFragments.java b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineEmptyFragments.java index f2aa8041b9a..837e607c009 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineEmptyFragments.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineEmptyFragments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,7 +103,7 @@ private void testAlertPacketNotHandshaking() throws Exception { try { unwrap(serverEngine, alert, serverIn); throw new RuntimeException("Expected exception was not thrown."); - } catch (SSLHandshakeException exc) { + } catch (SSLProtocolException exc) { log("Got the exception I wanted."); } } @@ -133,7 +133,7 @@ private void testAlertPacketMidHandshake() throws Exception { unwrap(serverEngine, alert, serverIn); log("Server unwrap was successful when it should have failed."); throw new RuntimeException("Expected exception was not thrown."); - } catch (SSLHandshakeException exc) { + } catch (SSLProtocolException exc) { log("Got the exception I wanted."); } } diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketEmptyFragments.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketEmptyFragments.java index dec93c1c199..de0ef43924d 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketEmptyFragments.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketEmptyFragments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -351,9 +351,9 @@ public static void main(String [] args) throws Exception { tests.executeTest( tests::testEmptyHandshakeRecord, SSLProtocolException.class); tests.executeTest( - tests::testEmptyAlertNotHandshaking, SSLHandshakeException.class); + tests::testEmptyAlertNotHandshaking, SSLProtocolException.class); tests.executeTest( - tests::testEmptyAlertDuringHandshake, SSLHandshakeException.class); + tests::testEmptyAlertDuringHandshake, SSLProtocolException.class); tests.executeTest( tests::testEmptyChangeCipherSpecMessage, SSLProtocolException.class); @@ -361,6 +361,6 @@ public static void main(String [] args) throws Exception { tests.executeTest( tests::testEmptyHandshakeRecord, SSLProtocolException.class); tests.executeTest( - tests::testEmptyAlertNotHandshaking, SSLHandshakeException.class); + tests::testEmptyAlertNotHandshaking, SSLProtocolException.class); } } diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForClientTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForClientTLS12.java new file mode 100644 index 00000000000..7d16e07e7b1 --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForClientTLS12.java @@ -0,0 +1,87 @@ +/* + * 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 8365820 + * @summary Apply certificate scope constraints to algorithms in + * "signature_algorithms" extension when + * "signature_algorithms_cert" extension is not being sent. + * This test covers the client side for TLSv1.2. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableCertSignAlgsExtForClientTLS12 + */ + +import static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertFalse; + +import java.security.Security; +import java.util.List; + +// Test disabled signature_algorithms_cert extension on the client side +// for TLSv1.2. +public class DisableCertSignAlgsExtForClientTLS12 extends + DisableSignatureSchemePerScopeTLS12 { + + protected DisableCertSignAlgsExtForClientTLS12() + throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + Security.setProperty( + "jdk.tls.disabledAlgorithms", DISABLED_CONSTRAINTS); + // Disable signature_algorithms_cert extension for the client. + System.setProperty("jdk.tls.client.disableExtensions", + "signature_algorithms_cert"); + new DisableCertSignAlgsExtForClientTLS12().run(); + } + + @Override + protected void checkClientHello() throws Exception { + // --- Check signature_algorithms extension --- + + // Get signature_algorithms extension signature schemes. + List sigAlgsSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_EXT); + + // signature_algorithms extension MUST NOT contain disabled + // handshake signature scheme. + assertFalse(sigAlgsSS.contains(HANDSHAKE_DISABLED_SIG), + "Signature Scheme " + HANDSHAKE_DISABLED_SIG + + " present in ClientHello's signature_algorithms extension"); + + // signature_algorithms extension MUST NOT contain disabled + // certificate signature scheme. + assertFalse(sigAlgsSS.contains(CERTIFICATE_DISABLED_SIG), + "Signature Scheme " + CERTIFICATE_DISABLED_SIG + + " present in ClientHello's signature_algorithms extension"); + + // signature_algorithms_cert extension MUST NOT be present. + assertEquals(getSigSchemesCliHello(extractHandshakeMsg( + cTOs, TLS_HS_CLI_HELLO), SIG_ALGS_CERT_EXT).size(), 0, + "signature_algorithms_cert extension present in ClientHello"); + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForClientTLS13.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForClientTLS13.java new file mode 100644 index 00000000000..5f594cd2cdf --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForClientTLS13.java @@ -0,0 +1,89 @@ +/* + * 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 8365820 + * @summary Apply certificate scope constraints to algorithms in + * "signature_algorithms" extension when + * "signature_algorithms_cert" extension is not being sent. + * This test covers the client side for TLSv1.3. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableCertSignAlgsExtForClientTLS13 + */ + +import static jdk.test.lib.Asserts.assertFalse; + +import java.security.Security; +import java.util.List; + +// Test disabled signature_algorithms_cert extension on the client side +// for TLSv1.3. +public class DisableCertSignAlgsExtForClientTLS13 extends + DisableCertSignAlgsExtForClientTLS12 { + + protected DisableCertSignAlgsExtForClientTLS13() + throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + Security.setProperty( + "jdk.tls.disabledAlgorithms", DISABLED_CONSTRAINTS); + // Disable signature_algorithms_cert extension for the client. + System.setProperty("jdk.tls.client.disableExtensions", + "signature_algorithms_cert"); + new DisableCertSignAlgsExtForClientTLS13().run(); + } + + @Override + protected String getProtocol() { + return "TLSv1.3"; + } + + @Override + protected void checkClientHello() throws Exception { + super.checkClientHello(); + + // Get signature_algorithms extension signature schemes. + List sigAlgsSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_EXT); + + // These signature schemes MOST NOT be present in signature_algorithms + // extension. + TLS13_CERT_ONLY.forEach(ss -> + assertFalse(sigAlgsSS.contains(ss), "Signature Scheme " + ss + + " present in ClientHello's" + + " signature_algorithms extension")); + } + + // TLSv1.3 sends CertificateRequest signature schemes in + // signature_algorithms and signature_algorithms_cert extensions. Same as + // ClientHello, but they are encrypted. So we skip CertificateRequest + // signature schemes verification for TLSv1.3. + @Override + protected void checkCertificateRequest() { + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForServerTLS13.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForServerTLS13.java new file mode 100644 index 00000000000..4c93e4fc240 --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForServerTLS13.java @@ -0,0 +1,281 @@ +/* + * 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 static jdk.test.lib.Asserts.assertTrue; +import static jdk.test.lib.Utils.runAndCheckException; + +import java.io.IOException; +import java.math.BigInteger; +import java.net.SocketException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.TrustManagerFactory; +import jdk.test.lib.security.CertificateBuilder; +import sun.security.x509.AuthorityKeyIdentifierExtension; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNames; +import sun.security.x509.KeyIdentifier; +import sun.security.x509.SerialNumber; +import sun.security.x509.X500Name; + +/* + * @test + * @bug 8365820 + * @summary Apply certificate scope constraints to algorithms in + * "signature_algorithms" extension when + * "signature_algorithms_cert" extension is not being sent. + * This test covers the server side for TLSv1.3. + * @modules java.base/sun.security.x509 + * java.base/sun.security.util + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableCertSignAlgsExtForServerTLS13 true + * @run main/othervm DisableCertSignAlgsExtForServerTLS13 false + */ + +/* + * Test disabled signature_algorithms_cert extension on the server side. + * + * CertificateRequest's extensions are encrypted in TLSv1.3. So we can't verify + * the content of the CertificateRequest's signature_algorithms extension + * directly like we do it for extensions in ClientHello message. + * Instead, we run a TLS handshake and check that certificate scope + * constraints are being applied to algorithms in "signature_algorithms" + * extension when "signature_algorithms_cert" extension is not being sent. + * + * Note that for TLSv1.2 disabling "signature_algorithms_cert" extension + * doesn't change anything for the signatures schemes list contained in + * CertificateRequest message. The TLSv1.2 CertificateRequest message + * doesn't contain extensions and includes the signatures schemes list + * directly (which is also an intersection of signature schemes allowed + * for handshake signatures and for the certificate signatures). + * This functionality is being tested by "DisableSignatureSchemePerScopeTLS12". + */ + +public class DisableCertSignAlgsExtForServerTLS13 extends SSLSocketTemplate { + + private static final String KEY_ALGORITHM = "RSA"; + private static final String SERVER_CERT_SIG_ALG = "RSASSA-PSS"; + // SHA256withRSA signature algorithm is not allowed for handshake + // signatures in TLSv1.3, but it's allowed for certificate + // signatures. This is regardless of jdk.tls.disabledAlgorithms + // configuration. We use this difference to construct our test. + private static final String CLIENT_CERT_SIG_ALG = "SHA256withRSA"; + private static final String TRUSTED_CERT_SIG_ALG = "RSASSA-PSS"; + + private final String protocol; + private X509Certificate trustedCert; + private X509Certificate serverCert; + private X509Certificate clientCert; + private KeyPair serverKeys; + private KeyPair clientKeys; + + protected DisableCertSignAlgsExtForServerTLS13( + String protocol) throws Exception { + super(); + this.protocol = protocol; + setupCertificates(); + } + + public static void main(String[] args) throws Exception { + if (args.length != 1) { + throw new RuntimeException("Wrong number of arguments"); + } + + boolean disabled = Boolean.parseBoolean(args[0]); + + // Disable signature_algorithms_cert extension on the server side. + if (disabled) { + System.setProperty("jdk.tls.server.disableExtensions", + "signature_algorithms_cert"); + } + + // Should always run fine on TLSv1.2 because SHA256withRSA signature + // algorithm is allowed for both handshake and certificates signatures + // in TLSv1.2. + new DisableCertSignAlgsExtForServerTLS13("TLSv1.2").run(); + + var tls13Test = new DisableCertSignAlgsExtForServerTLS13("TLSv1.3"); + + if (disabled) { + // Fails with "signature_algorithms_cert" extension disabled + // because in such case we use an intersection of signature + // schemes allowed for handshake signatures and for the certificate + // signatures for "signature_algorithms" extension. + runAndCheckException( + tls13Test::run, + localEx -> { + Throwable remoteEx = localEx.getSuppressed()[0]; + + for (Throwable ex : + new Throwable[]{localEx, remoteEx}) { + assertTrue((ex instanceof SSLHandshakeException + && ex.getMessage() + .contains("(certificate_required)") + // Sometimes we can get SocketException + // instead, depends on network setup. + || ex instanceof SocketException)); + } + }); + } else { + // Runs fine with "signature_algorithms_cert" extension present. + tls13Test.run(); + } + } + + @Override + protected void configureServerSocket(SSLServerSocket sslServerSocket) { + // Require a conforming certificate for the client. + SSLParameters sslParameters = sslServerSocket.getSSLParameters(); + sslParameters.setNeedClientAuth(true); + sslServerSocket.setSSLParameters(sslParameters); + } + + @Override + public SSLContext createServerSSLContext() throws Exception { + return getSSLContext( + trustedCert, serverCert, serverKeys.getPrivate(), protocol); + } + + @Override + public SSLContext createClientSSLContext() throws Exception { + return getSSLContext( + trustedCert, clientCert, clientKeys.getPrivate(), protocol); + } + + private static SSLContext getSSLContext( + X509Certificate trustedCertificate, X509Certificate keyCertificate, + PrivateKey privateKey, String protocol) + throws Exception { + + // create a key store + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + + // import the trusted cert + ks.setCertificateEntry("TLS Signer", trustedCertificate); + + // generate certificate chain + Certificate[] chain = new Certificate[2]; + chain[0] = keyCertificate; + chain[1] = trustedCertificate; + + // import the key entry. + final char[] passphrase = "passphrase".toCharArray(); + ks.setKeyEntry("Whatever", privateKey, passphrase, chain); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(ks); + + // create SSL context + SSLContext ctx = SSLContext.getInstance(protocol); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, passphrase); + + ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + return ctx; + } + + // Certificate-building helper methods. + + private void setupCertificates() throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance( + KEY_ALGORITHM); + KeyPair caKeys = kpg.generateKeyPair(); + this.serverKeys = kpg.generateKeyPair(); + this.clientKeys = kpg.generateKeyPair(); + + this.trustedCert = createTrustedCert(caKeys); + + this.serverCert = customCertificateBuilder( + "O=Some-Org, L=Some-City, ST=Some-State, C=US", + serverKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(false, false, -1) + .build(trustedCert, caKeys.getPrivate(), SERVER_CERT_SIG_ALG); + + this.clientCert = customCertificateBuilder( + "CN=localhost, OU=SSL-Client, O=Some-Org, L=Some-City, ST=Some-State, C=US", + clientKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(false, false, -1) + .build(trustedCert, caKeys.getPrivate(), CLIENT_CERT_SIG_ALG); + } + + private static X509Certificate createTrustedCert(KeyPair caKeys) + throws Exception { + SecureRandom random = new SecureRandom(); + + KeyIdentifier kid = new KeyIdentifier(caKeys.getPublic()); + GeneralNames gns = new GeneralNames(); + GeneralName name = new GeneralName(new X500Name( + "O=Some-Org, L=Some-City, ST=Some-State, C=US")); + gns.add(name); + BigInteger serialNumber = BigInteger.valueOf( + random.nextLong(1000000) + 1); + return customCertificateBuilder( + "O=Some-Org, L=Some-City, ST=Some-State, C=US", + caKeys.getPublic(), caKeys.getPublic()) + .setSerialNumber(serialNumber) + .addExtension(new AuthorityKeyIdentifierExtension(kid, gns, + new SerialNumber(serialNumber))) + .addBasicConstraintsExt(true, true, -1) + .build(null, caKeys.getPrivate(), TRUSTED_CERT_SIG_ALG); + } + + private static CertificateBuilder customCertificateBuilder( + String subjectName, PublicKey publicKey, PublicKey caKey) + throws CertificateException, IOException { + SecureRandom random = new SecureRandom(); + + CertificateBuilder builder = new CertificateBuilder() + .setSubjectName(subjectName) + .setPublicKey(publicKey) + .setNotBefore( + Date.from(Instant.now().minus(1, ChronoUnit.HOURS))) + .setNotAfter(Date.from(Instant.now().plus(1, ChronoUnit.HOURS))) + .setSerialNumber( + BigInteger.valueOf(random.nextLong(1000000) + 1)) + .addSubjectKeyIdExt(publicKey) + .addAuthorityKeyIdExt(caKey); + builder.addKeyUsageExt( + new boolean[]{true, true, true, true, true, true}); + + return builder; + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java index e2ee9f0889a..29a50dccefe 100644 --- a/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8349583 + * @bug 8349583 8365820 * @summary Add mechanism to disable signature schemes based on their TLS scope. * This test only covers TLS 1.2. * @library /javax/net/ssl/templates @@ -53,6 +53,17 @@ public class DisableSignatureSchemePerScopeTLS12 extends HANDSHAKE_DISABLED_SIG + " usage HandShakesignature, " + CERTIFICATE_DISABLED_SIG + " usage certificateSignature"; + // Signature schemes not supported in TLSv1.3 for the handshake + // regardless of jdk.tls.disabledAlgorithms configuration. + // In TLSv1.2 these are supported for both: handshake and certificate. + protected static final List TLS13_CERT_ONLY = List.of( + "ecdsa_sha1", + "rsa_pkcs1_sha1", + "rsa_pkcs1_sha256", + "rsa_pkcs1_sha384", + "rsa_pkcs1_sha512" + ); + protected DisableSignatureSchemePerScopeTLS12() throws Exception { super(); } @@ -120,13 +131,13 @@ protected void checkClientHello() throws Exception { assertTrue(sigAlgsCertSS.contains(HANDSHAKE_DISABLED_SIG), "Signature Scheme " + HANDSHAKE_DISABLED_SIG + " isn't present in ClientHello's" - + " signature_algorithms extension"); + + " signature_algorithms_cert extension"); // signature_algorithms_cert extension MUST NOT contain disabled // certificate signature scheme. assertFalse(sigAlgsCertSS.contains(CERTIFICATE_DISABLED_SIG), "Signature Scheme " + CERTIFICATE_DISABLED_SIG - + " present in ClientHello's signature_algorithms extension"); + + " present in ClientHello's signature_algorithms_cert extension"); } protected void checkCertificateRequest() throws Exception { diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java index 5d5d445cb45..6f5d88052ff 100644 --- a/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8349583 + * @bug 8349583 8365820 * @summary Add mechanism to disable signature schemes based on their TLS scope. * This test only covers TLS 1.3. * @library /javax/net/ssl/templates @@ -41,15 +41,6 @@ public class DisableSignatureSchemePerScopeTLS13 extends DisableSignatureSchemePerScopeTLS12 { - // Signature schemes not supported in TLSv1.3 only for the handshake. - // This is regardless of jdk.tls.disabledAlgorithms configuration. - List NOT_SUPPORTED_FOR_HANDSHAKE = List.of( - "rsa_pkcs1_sha1", - "rsa_pkcs1_sha256", - "rsa_pkcs1_sha384", - "rsa_pkcs1_sha512" - ); - protected DisableSignatureSchemePerScopeTLS13() throws Exception { super(); } @@ -74,23 +65,24 @@ protected void checkClientHello() throws Exception { extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), SIG_ALGS_EXT); - // Should not be present in signature_algorithms extension. - NOT_SUPPORTED_FOR_HANDSHAKE.forEach(ss -> - assertFalse(sigAlgsSS.contains(ss), - "Signature Scheme " + ss - + " present in ClientHello's signature_algorithms extension")); + // These signature schemes MOST NOT be present in signature_algorithms + // extension. + TLS13_CERT_ONLY.forEach(ss -> + assertFalse(sigAlgsSS.contains(ss), "Signature Scheme " + ss + + " present in ClientHello's" + + " signature_algorithms extension")); // Get signature_algorithms_cert extension signature schemes. List sigAlgsCertSS = getSigSchemesCliHello( extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), SIG_ALGS_CERT_EXT); - // Should be present in signature_algorithms_cert extension. - NOT_SUPPORTED_FOR_HANDSHAKE.forEach(ss -> - assertTrue(sigAlgsCertSS.contains(ss), - "Signature Scheme " + ss + // These signature schemes MUST be present in + // signature_algorithms_cert extension. + TLS13_CERT_ONLY.forEach(ss -> + assertTrue(sigAlgsCertSS.contains(ss), "Signature Scheme " + ss + " isn't present in ClientHello's" - + " signature_algorithms extension")); + + " signature_algorithms_cert extension")); } // TLSv1.3 sends CertificateRequest signature schemes in diff --git a/test/jdk/sun/security/tools/keytool/i18n.java b/test/jdk/sun/security/tools/keytool/i18n.java index 6eac0239eee..ab9da8b1d3e 100644 --- a/test/jdk/sun/security/tools/keytool/i18n.java +++ b/test/jdk/sun/security/tools/keytool/i18n.java @@ -63,11 +63,21 @@ import jdk.test.lib.UIBuilder; -import javax.swing.*; +import javax.swing.JDialog; +import javax.swing.SwingUtilities; +import javax.swing.JTextArea; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JFrame; +import java.awt.FlowLayout; +import java.awt.BorderLayout; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.Locale; +import static javax.swing.BorderFactory.createEmptyBorder; + public class i18n { private static final String[][] TABLE = new String[][]{ {"-help", "All the output in this test should be in ${LANG}. " @@ -234,11 +244,12 @@ public class i18n { "Output in ${LANG}. Check keytool error: java.lang" + ".IllegalArgumentException: if -protected is " + "specified, then -storepass, -keypass, and -new " - + "must not be specified."}, + + "must not be specified."} }; private static String TEST_SRC = System.getProperty("test.src"); private static int TIMEOUT_MS = 120000; private volatile boolean failed = false; + private volatile String failureReason = ""; private volatile boolean aborted = false; private Thread currentThread = null; @@ -330,6 +341,7 @@ public boolean validate(String command, String instruction, String message) { if (failed) { System.out.println(command + ": TEST FAILED"); + System.out.println("REASON: " + failureReason); System.out.println(message); } else { System.out.println(command + ": TEST PASSED"); @@ -348,6 +360,7 @@ public void pass() { public void fail() { failed = true; + failureReason = requestFailDescription(); currentThread.interrupt(); } @@ -355,4 +368,33 @@ public void abort() { aborted = true; currentThread.interrupt(); } + + /** + * Opens a prompt to enter a failure reason to be filled by the tester + */ + public static String requestFailDescription() { + + final JDialog dialogWindow = new JDialog(new JFrame(), "Failure Description", true); + final JTextArea reasonTextArea = new JTextArea(5, 20); + + final JButton okButton = new JButton("OK"); + okButton.addActionListener(_ -> dialogWindow.setVisible(false)); + + final JPanel okayBtnPanel = new JPanel( + new FlowLayout(FlowLayout.CENTER, 4, 0)); + okayBtnPanel.setBorder(createEmptyBorder(4, 0, 0, 0)); + okayBtnPanel.add(okButton); + + final JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(new JScrollPane(reasonTextArea), BorderLayout.CENTER); + mainPanel.add(okayBtnPanel, BorderLayout.SOUTH); + + dialogWindow.add(mainPanel); + dialogWindow.pack(); + dialogWindow.setVisible(true); + + dialogWindow.dispose(); + + return reasonTextArea.getText(); + } } diff --git a/test/jdk/tools/jpackage/TEST.properties b/test/jdk/tools/jpackage/TEST.properties index 58a82a9444b..7c799e4d320 100644 --- a/test/jdk/tools/jpackage/TEST.properties +++ b/test/jdk/tools/jpackage/TEST.properties @@ -22,5 +22,6 @@ modules = \ jdk.jpackage/jdk.jpackage.internal:+open \ jdk.jpackage/jdk.jpackage.internal.util \ jdk.jpackage/jdk.jpackage.internal.util.function \ + jdk.jpackage/jdk.jpackage.internal.resources \ java.base/jdk.internal.util \ jdk.jlink/jdk.tools.jlink.internal diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 49f565e27e9..6aacc261fb6 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -1085,7 +1085,9 @@ public static enum AppLayoutAssert { }), MAIN_LAUNCHER_FILES(cmd -> { if (!cmd.isRuntime()) { - new LauncherVerifier(cmd).verify(cmd, LauncherVerifier.Action.VERIFY_INSTALLED); + new LauncherVerifier(cmd).verify(cmd, + LauncherVerifier.Action.VERIFY_INSTALLED, + LauncherVerifier.Action.VERIFY_MAC_ENTITLEMENTS); } }), MAIN_JAR_FILE(cmd -> { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java index 42821822894..e1cd37fe8b4 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java @@ -311,7 +311,7 @@ private static void verifyMacDaemonPlistFile(JPackageCommand cmd, var servicePlist = MacHelper.readPList(servicePlistFile); - var args = servicePlist.queryArrayValue("ProgramArguments"); + var args = servicePlist.queryStringArrayValue("ProgramArguments"); TKit.assertEquals(1, args.size(), "Check number of array elements in 'ProgramArguments' property in the property file"); TKit.assertEquals(installedLauncherPath.toString(), args.get(0), diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java index b3ed030c69d..7bf01fdde05 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java @@ -37,9 +37,14 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; +import javax.xml.parsers.ParserConfigurationException; +import jdk.jpackage.internal.resources.ResourceLocator; +import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.internal.util.function.ThrowingBiConsumer; +import jdk.jpackage.internal.util.function.ThrowingSupplier; import jdk.jpackage.test.AdditionalLauncher.PropertyFile; import jdk.jpackage.test.LauncherShortcut.StartupDirectory; +import org.xml.sax.SAXException; public final class LauncherVerifier { @@ -82,6 +87,11 @@ public enum Action { verifier.verifyInAppImageFile(cmd); } }), + VERIFY_MAC_ENTITLEMENTS((verifier, cmd) -> { + if (TKit.isOSX() && MacHelper.appImageSigned(cmd)) { + verifier.verifyMacEntitlements(cmd); + } + }), EXECUTE_LAUNCHER(LauncherVerifier::executeLauncher), ; @@ -96,7 +106,7 @@ private void apply(LauncherVerifier verifier, JPackageCommand cmd) { private final BiConsumer action; static final List VERIFY_APP_IMAGE = List.of( - VERIFY_ICON, VERIFY_DESCRIPTION, VERIFY_INSTALLED, VERIFY_APP_IMAGE_FILE + VERIFY_ICON, VERIFY_DESCRIPTION, VERIFY_INSTALLED, VERIFY_APP_IMAGE_FILE, VERIFY_MAC_ENTITLEMENTS ); static final List VERIFY_DEFAULTS = Stream.concat( @@ -323,6 +333,24 @@ private void verifyInAppImageFile(JPackageCommand cmd) { } } + private void verifyMacEntitlements(JPackageCommand cmd) throws ParserConfigurationException, SAXException, IOException { + Path launcherPath = cmd.appLauncherPath(name); + var entitlements = MacSignVerify.findEntitlements(launcherPath); + + TKit.assertTrue(entitlements.isPresent(), String.format("Check [%s] launcher is signed with entitlements", name)); + + Map expected; + if (cmd.hasArgument("--mac-entitlements")) { + expected = new PListReader(Files.readAllBytes(Path.of(cmd.getArgumentValue("--mac-entitlements")))).toMap(true); + } else if (cmd.hasArgument("--mac-app-store")) { + expected = DefaultEntitlements.APP_STORE; + } else { + expected = DefaultEntitlements.STANDARD; + } + + TKit.assertEquals(expected, entitlements.orElseThrow().toMap(true), String.format("Check [%s] launcher is signed with expected entitlements", name)); + } + private void executeLauncher(JPackageCommand cmd) throws IOException { Path launcherPath = cmd.appLauncherPath(name); @@ -362,6 +390,20 @@ private static Optional iconInResourceDir(JPackageCommand cmd, String laun }); } + + private static final class DefaultEntitlements { + private static Map loadFromResources(String resourceName) { + return ThrowingSupplier.toSupplier(() -> { + var bytes = ResourceLocator.class.getResourceAsStream("entitlements.plist").readAllBytes(); + return new PListReader(bytes).toMap(true); + }).get(); + } + + static final Map STANDARD = loadFromResources("entitlements.plist"); + static final Map APP_STORE = loadFromResources("sandbox.plist"); + } + + private final String name; private final Optional> javaOptions; private final Optional> arguments; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index f4feb3e2fde..37e395e1a3e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -32,6 +32,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -74,9 +75,23 @@ public static void withExplodedDmg(JPackageCommand cmd, Path mountPoint = null; try { - var plist = readPList(attachExecutor.getOutput()); - mountPoint = Path.of(plist.queryValue("mount-point")); + // One of "dict" items of "system-entities" array property should contain "mount-point" string property. + mountPoint = readPList(attachExecutor.getOutput()).queryArrayValue("system-entities", false).map(PListReader.class::cast).map(dict -> { + try { + return dict.queryValue("mount-point"); + } catch (NoSuchElementException ex) { + return (String)null; + } + }).filter(Objects::nonNull).map(Path::of).findFirst().orElseThrow(); + } finally { + if (mountPoint == null) { + TKit.trace("Unexpected plist file missing `system-entities` array:"); + attachExecutor.getOutput().forEach(TKit::trace); + TKit.trace("Done"); + } + } + try { // code here used to copy just or .app // We now have option to include arbitrary content, so we copy // everything in the mounted image. diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java index 432433b4fd0..ae27e292bf6 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java @@ -56,6 +56,17 @@ public static void assertAdhocSigned(Path path) { String.format("Check [%s] signed with adhoc signature", path)); } + public static Optional findEntitlements(Path path) { + final var exec = Executor.of("/usr/bin/codesign", "-d", "--entitlements", "-", "--xml", path.toString()).saveOutput().dumpOutput(); + final var result = exec.execute(); + var xml = result.stdout().getOutput(); + if (xml.isEmpty()) { + return Optional.empty(); + } else { + return Optional.of(MacHelper.readPList(xml)); + } + } + public static void assertUnsigned(Path path) { TKit.assertTrue(findSpctlSignOrigin(SpctlType.EXEC, path).isEmpty(), String.format("Check [%s] unsigned", path)); diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java index c0acea5e3e7..b3660383e47 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java @@ -23,33 +23,141 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.DottedVersion; -import jdk.jpackage.internal.model.ConfigException; -import java.nio.file.Path; -import jdk.internal.util.OperatingSystem; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.DottedVersion; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.ValueSource; public class ToolValidatorTest { - @Test - public void testAvailable() { - assertNull(new ToolValidator(TOOL_JAVA).validate()); + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testAvailable(boolean checkExistsOnly) { + assertNull(new ToolValidator(TOOL_JAVA).checkExistsOnly(checkExistsOnly).validate()); } @Test - public void testNotAvailable() { - assertValidationFailure(new ToolValidator(TOOL_UNKNOWN).validate(), true); + public void testAvailable_setCommandLine() { + // java doesn't recognize "--foo" command line option, but the validation will + // still pass as there is no minimal version specified and the validator ignores + // the exit code + assertNull(new ToolValidator(TOOL_JAVA).setCommandLine("--foo").validate()); + } + + enum TestAvailableMode { + NO_VERSION(null), + TOO_OLD("0.9"), + EQUALS("1.0"), + NEWER("1.1"); + + TestAvailableMode(String parsedVersion) { + this.parsedVersion = parsedVersion; + } + + final String parsedVersion; + } + + @ParameterizedTest + @EnumSource(TestAvailableMode.class) + public void testAvailable(TestAvailableMode mode) { + var minVer = TestAvailableMode.EQUALS.parsedVersion; + var err = new ToolValidator(TOOL_JAVA).setVersionParser(lines -> { + return mode.parsedVersion; + }).setMinimalVersion(DottedVersion.greedy(minVer)).validate(); + + if (Set.of(TestAvailableMode.NO_VERSION, TestAvailableMode.TOO_OLD).contains(mode)) { + var expectedMessage = I18N.format("error.tool-old-version", TOOL_JAVA, minVer); + var expectedAdvice = I18N.format("error.tool-old-version.advice", TOOL_JAVA, minVer); + + assertEquals(expectedMessage, err.getMessage()); + assertEquals(expectedAdvice, err.getAdvice()); + } else { + assertNull(err); + } + } + + @ParameterizedTest + @EnumSource(TestAvailableMode.class) + public void testAvailable_setToolOldVersionErrorHandler(TestAvailableMode mode) { + var handler = new ToolOldVersionErrorHandler(); + var minVer = TestAvailableMode.EQUALS.parsedVersion; + var err = new ToolValidator(TOOL_JAVA).setVersionParser(lines -> { + return mode.parsedVersion; + }).setMinimalVersion(DottedVersion.greedy(minVer)).setToolOldVersionErrorHandler(handler).validate(); + + if (Set.of(TestAvailableMode.NO_VERSION, TestAvailableMode.TOO_OLD).contains(mode)) { + assertSame(ToolOldVersionErrorHandler.ERR, err); + handler.verifyCalled(Path.of(TOOL_JAVA), mode.parsedVersion); + } else { + assertNull(err); + handler.verifyNotCalled(); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testNotAvailable(boolean checkExistsOnly, @TempDir Path dir) { + var err = new ToolValidator(dir.resolve("foo")).checkExistsOnly(checkExistsOnly).validate(); + if (checkExistsOnly) { + assertValidationFailure(err, false); + } else { + assertValidationFailureNoAdvice(err, !checkExistsOnly); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testToolIsDirectory(boolean checkExistsOnly, @TempDir Path dir) { + var err = new ToolValidator(dir).checkExistsOnly(checkExistsOnly).validate(); + assertValidationFailureNoAdvice(err, !checkExistsOnly); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testNotAvailable_setToolNotFoundErrorHandler(boolean checkExistsOnly, @TempDir Path dir) { + var handler = new ToolNotFoundErrorHandler(); + var err = new ToolValidator(dir.resolve("foo")).checkExistsOnly(checkExistsOnly) + .setToolNotFoundErrorHandler(handler) + .validate(); + if (checkExistsOnly) { + handler.verifyCalled(dir.resolve("foo")); + assertSame(ToolNotFoundErrorHandler.ERR, err); + } else { + handler.verifyNotCalled(); + assertValidationFailureNoAdvice(err, !checkExistsOnly); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testToolIsDirectory_setToolNotFoundErrorHandler(boolean checkExistsOnly, @TempDir Path dir) { + var handler = new ToolNotFoundErrorHandler(); + var err = new ToolValidator(dir).checkExistsOnly(checkExistsOnly).validate(); + handler.verifyNotCalled(); + assertValidationFailureNoAdvice(err, !checkExistsOnly); } @Test public void testVersionParserUsage() { // Without minimal version configured, version parser should not be used new ToolValidator(TOOL_JAVA).setVersionParser(unused -> { - throw new RuntimeException(); + throw new AssertionError(); }).validate(); // Minimal version is 1, actual is 10. Should be OK. @@ -81,9 +189,68 @@ private static void assertValidationFailure(ConfigException v, boolean withCause } } + private static void assertValidationFailureNoAdvice(ConfigException v, boolean withCause) { + assertNotNull(v); + assertNotEquals("", v.getMessage().strip()); + assertNull(v.getAdvice()); + if (withCause) { + assertNotNull(v.getCause()); + } else { + assertNull(v.getCause()); + } + } + + + private static final class ToolNotFoundErrorHandler implements Function { + + @Override + public ConfigException apply(Path tool) { + assertNotNull(tool); + this.tool = tool; + return ERR; + } + + void verifyCalled(Path expectedTool) { + assertEquals(Objects.requireNonNull(expectedTool), tool); + } + + void verifyNotCalled() { + assertNull(tool); + } + + private Path tool; + + static final ConfigException ERR = new ConfigException("no tool", "install the tool"); + } + + + private static final class ToolOldVersionErrorHandler implements BiFunction { + + @Override + public ConfigException apply(Path tool, String parsedVersion) { + assertNotNull(tool); + this.tool = tool; + this.parsedVersion = parsedVersion; + return ERR; + } + + void verifyCalled(Path expectedTool, String expectedParsedVersion) { + assertEquals(Objects.requireNonNull(expectedTool), tool); + assertEquals(expectedParsedVersion, parsedVersion); + } + + void verifyNotCalled() { + assertNull(tool); + } + + private Path tool; + private String parsedVersion; + + static final ConfigException ERR = new ConfigException("tool too old", "install the newer version"); + } + + private static final String TOOL_JAVA; - private static final String TOOL_UNKNOWN = Path.of(System.getProperty( - "java.home"), "bin").toString(); static { String fname = "java"; diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java index d766505cf14..fe7d0c63870 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java @@ -32,14 +32,18 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; +import java.util.stream.Stream; import javax.xml.parsers.ParserConfigurationException; +import jdk.jpackage.internal.util.PListReader.Raw; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.EnumSource.Mode; import org.junit.jupiter.params.provider.MethodSource; import org.w3c.dom.Node; import org.xml.sax.InputSource; @@ -51,7 +55,23 @@ public class PListReaderTest { enum QueryType { STRING(PListReader::queryValue), BOOLEAN(PListReader::queryBoolValue), - STRING_ARRAY(PListReader::queryArrayValue); + DICT((plistReader, keyName) -> { + return plistReader.queryDictValue(keyName).toMap(true); + }), + STRING_ARRAY(PListReader::queryStringArrayValue), + RAW_ARRAY((plistReader, keyName) -> { + return plistReader.queryArrayValue(keyName, false).toList(); + }), + RAW_ARRAY_RECURSIVE((plistReader, keyName) -> { + return plistReader.queryArrayValue(keyName, true).toList(); + }), + TO_MAP((plistReader, _) -> { + return plistReader.toMap(false); + }), + TO_MAP_RECURSIVE((plistReader, _) -> { + return plistReader.toMap(true); + }), + ; QueryType(BiFunction queryMethod) { this.queryMethod = Objects.requireNonNull(queryMethod); @@ -65,10 +85,10 @@ T queryValue(PListReader pListReader, String keyName) { private final BiFunction queryMethod; } - public record QueryValueTestSpec(QueryType queryType, String keyName, Optional expectedValue, + public record TestSpec(QueryType queryType, Optional keyName, Optional expectedValue, Optional> expectedException, String... xml) { - public QueryValueTestSpec { + public TestSpec { Objects.requireNonNull(queryType); Objects.requireNonNull(keyName); Objects.requireNonNull(expectedValue); @@ -77,6 +97,14 @@ public record QueryValueTestSpec(QueryType queryType, String keyName, Optional {} + default -> { + throw new IllegalArgumentException(); + } + } + } } static final class Builder { @@ -91,7 +119,7 @@ Builder keyName(String v) { return this; } - Builder expectedValue(Object v) { + Builder expect(Object v) { expectedValue = v; if (v instanceof String) { queryType(QueryType.STRING); @@ -99,11 +127,13 @@ Builder expectedValue(Object v) { queryType(QueryType.BOOLEAN); } else if (v instanceof List) { queryType(QueryType.STRING_ARRAY); + } else if (v instanceof Map) { + queryType(QueryType.DICT); } return this; } - Builder expectedException(Class v) { + Builder expectException(Class v) { expectedException = v; return this; } @@ -113,8 +143,11 @@ Builder xml(String... v) { return this; } - QueryValueTestSpec create() { - return new QueryValueTestSpec(queryType, keyName, Optional.ofNullable(expectedValue), + TestSpec create() { + return new TestSpec( + queryType, + Optional.ofNullable(keyName), + Optional.ofNullable(expectedValue), validatedExpectedException(), xml); } @@ -137,12 +170,12 @@ void test() { final var plistReader = new PListReader(createXml(xml)); expectedValue.ifPresent(v -> { - final var actualValue = queryType.queryValue(plistReader, keyName); + final var actualValue = queryType.queryValue(plistReader, keyName.orElse(null)); assertEquals(v, actualValue); }); expectedException.ifPresent(v -> { - assertThrows(v, () -> queryType.queryValue(plistReader, keyName)); + assertThrows(v, () -> queryType.queryValue(plistReader, keyName.orElse(null))); }); } @@ -150,7 +183,9 @@ void test() { public String toString() { final var sb = new StringBuilder(); sb.append(queryType); - sb.append("; key=").append(keyName); + if (keyName != null) { + sb.append("; key=").append(keyName); + } expectedValue.ifPresent(v -> { sb.append("; expected="); sb.append(v); @@ -166,13 +201,13 @@ public String toString() { } @ParameterizedTest - @EnumSource(QueryType.class) + @EnumSource(mode = Mode.MATCH_NONE, names = {"TO_MAP.*"}) public void testNoSuchElement(QueryType queryType) { testSpec(queryType).create().test(); } @ParameterizedTest - @EnumSource(QueryType.class) + @EnumSource(mode = Mode.MATCH_NONE, names = {"TO_MAP.*"}) public void testWrongValueType(QueryType queryType) { final var builder = testSpec(queryType).xml( "string-key", @@ -182,33 +217,56 @@ public void testWrongValueType(QueryType queryType) { "boolean-false-key", "", "array-key", - "b"); + "b", + "dict-key", + "nested-dict-key345"); - List testSpecs = new ArrayList<>(); + List testSpecs = new ArrayList<>(); switch (queryType) { case STRING -> { testSpecs.add(builder.keyName("boolean-true-key").create()); testSpecs.add(builder.keyName("boolean-false-key").create()); testSpecs.add(builder.keyName("array-key").create()); + testSpecs.add(builder.keyName("dict-key").create()); } case BOOLEAN -> { testSpecs.add(builder.keyName("string-key").create()); testSpecs.add(builder.keyName("array-key").create()); + testSpecs.add(builder.keyName("dict-key").create()); } - case STRING_ARRAY -> { + case STRING_ARRAY, RAW_ARRAY, RAW_ARRAY_RECURSIVE -> { testSpecs.add(builder.keyName("string-key").create()); testSpecs.add(builder.keyName("boolean-true-key").create()); testSpecs.add(builder.keyName("boolean-false-key").create()); + testSpecs.add(builder.keyName("dict-key").create()); + } + case DICT -> { + testSpecs.add(builder.keyName("string-key").create()); + testSpecs.add(builder.keyName("boolean-true-key").create()); + testSpecs.add(builder.keyName("boolean-false-key").create()); + testSpecs.add(builder.keyName("array-key").create()); + } + case TO_MAP, TO_MAP_RECURSIVE -> { + throw new UnsupportedOperationException(); } } - testSpecs.forEach(QueryValueTestSpec::test); + testSpecs.forEach(TestSpec::test); + + builder.keyName(null).expect(Map.of( + "string-key", new Raw("a", Raw.Type.STRING), + "boolean-true-key", new Raw(Boolean.TRUE.toString(), Raw.Type.BOOLEAN), + "boolean-false-key", new Raw(Boolean.FALSE.toString(), Raw.Type.BOOLEAN), + "array-key", List.of(new Raw("b", Raw.Type.STRING)), + "dict-key", Map.of("nested-dict-key", new Raw("345", Raw.Type.INTEGER)) + )).queryType(QueryType.TO_MAP_RECURSIVE).create().test(); + } @ParameterizedTest @MethodSource - public void testQueryValue(QueryValueTestSpec testSpec) { + public void test(TestSpec testSpec) { testSpec.test(); } @@ -219,28 +277,190 @@ public void testByteArrayCtor() throws ParserConfigurationException, SAXExceptio assertEquals("A", actualValue); } - private static List testQueryValue() { - return List.of( - testSpec().expectedValue("A").xml("fooA").create(), - testSpec().expectedValue("").xml("foo").create(), - testSpec().xml("foo").create(), - testSpec().expectedValue(Boolean.TRUE).xml("foo").create(), - testSpec().expectedValue(Boolean.FALSE).xml("foo").create(), - testSpec(QueryType.BOOLEAN).xml("foo").create(), - testSpec(QueryType.BOOLEAN).xml("foo").create(), - testSpec().expectedValue(List.of("foo", "bar")).xml("foofoobar").create(), - testSpec().expectedValue(List.of()).xml("foo").create(), - testSpec(QueryType.STRING_ARRAY).xml("foo").create(), - testSpec().expectedValue("A").xml("fooAB").create(), - testSpec().expectedValue("A").xml("fooAfooB").create() + @Test + public void test_toMap() { + + var builder = testSpec(); + + builder.xml( + "AppName", + "Hello", + "", + "AppVersion", + "1.0", + "Release", + "", + "Debug", + "", + "ReleaseDate", + "2025-09-24T09:23:00Z", + "UserData", + "", + "", + " Foo", + " ", + " Str", + " ", + " Another Str", + " ", + " ", + " ", + " ", + "", + "Checksum", + "7841ff0076cdde93bdca02cfd332748c40620ce4", + "Plugins", + "", + " ", + " PluginName", + " Foo", + " Priority", + " 13", + " History", + " ", + " New File", + " Another New File", + " ", + " ", + " ", + " PluginName", + " Bar", + " Priority", + " 23", + " History", + " ", + " ", + "" ); + + var expected = Map.of( + "AppName", new Raw("Hello", Raw.Type.STRING), + "AppVersion", new Raw("1.0", Raw.Type.REAL), + "Release", new Raw(Boolean.TRUE.toString(), Raw.Type.BOOLEAN), + "Debug", new Raw(Boolean.FALSE.toString(), Raw.Type.BOOLEAN), + "ReleaseDate", new Raw("2025-09-24T09:23:00Z", Raw.Type.DATE), + "Checksum", new Raw("7841ff0076cdde93bdca02cfd332748c40620ce4", Raw.Type.DATA), + "UserData", Map.of( + "Foo", List.of( + new Raw("Str", Raw.Type.STRING), + List.of( + new Raw("Another Str", Raw.Type.STRING), + new Raw(Boolean.TRUE.toString(), Raw.Type.BOOLEAN), + new Raw(Boolean.FALSE.toString(), Raw.Type.BOOLEAN) + ) + ) + ), + "Plugins", List.of( + Map.of( + "PluginName", new Raw("Foo", Raw.Type.STRING), + "Priority", new Raw("13", Raw.Type.INTEGER), + "History", List.of( + new Raw("New File", Raw.Type.STRING), + new Raw("Another New File", Raw.Type.STRING) + ) + ), + Map.of( + "PluginName", new Raw("Bar", Raw.Type.STRING), + "Priority", new Raw("23", Raw.Type.REAL), + "History", List.of() + ) + ) + ); + + builder.expect(expected).queryType(QueryType.TO_MAP_RECURSIVE).create().test(); + } + + private static List test() { + + List data = new ArrayList<>(); + + Stream.of( + testSpec().expect("A").xml("fooA"), + testSpec().expect("A").xml("BfooA"), + testSpec().expect("").xml("foo some text "), + testSpec().xml("foo"), + testSpec().xml("foo"), + testSpec().xml("fooA"), + testSpec().expect(Boolean.TRUE).xml("foo"), + testSpec().expect(Boolean.FALSE).xml("foo"), + testSpec(QueryType.BOOLEAN).xml("foo"), + testSpec(QueryType.BOOLEAN).xml("foo"), + testSpec().expect(List.of("foo", "bar")).xml("foofoobar"), + testSpec().expect(List.of()).xml("foo"), + testSpec(QueryType.STRING_ARRAY).xml("foo"), + testSpec().expect("A").xml("fooAB"), + testSpec().expect("A").xml("fooAfooB"), + + testSpec().expect(Map.of()).xml("foo"), + + // + // Test that if there are multiple keys with the same name, all but the first are ignored. + // + testSpec().expect("A").xml("fooAfooBfooC"), + testSpec().expect("A").xml("fooAfooB"), + testSpec(QueryType.STRING).xml("fooBfooA"), + testSpec().expect(Boolean.TRUE).xml("foofoo"), + testSpec().expect(Boolean.TRUE).xml("foofoo"), + testSpec(QueryType.BOOLEAN).xml("foofoo"), + + // + // Test that it doesn't look up keys in nested "dict" or "array" elements. + // + testSpec().xml("foofooA"), + testSpec().expect("B").xml("barfooAfooB"), + testSpec().xml("foofooA"), + testSpec().expect("B").xml("barfooAfooB"), + + // + // Test empty arrays. + // + testSpec().expect(List.of()).queryType(QueryType.RAW_ARRAY_RECURSIVE).xml("foo"), + testSpec().expect(List.of()).queryType(QueryType.RAW_ARRAY).xml("foo") + + ).map(TestSpec.Builder::create).forEach(data::add); + + // + // Test toMap() method. + // + Stream.of( + testSpec().expect(Map.of()).xml(), + testSpec().expect(Map.of()).xml("foobar"), + testSpec().expect(Map.of()).xml("Abar"), + testSpec().expect(Map.of()).xml("A"), + testSpec().expect(Map.of()).xml("fooA"), + testSpec().expect(Map.of("foo", new Raw("A", Raw.Type.STRING))).xml("fooAB"), + testSpec().expect(Map.of("foo", new Raw("A", Raw.Type.STRING))).xml("fooA hello foo bye B"), + testSpec().expect(Map.of("foo", new Raw("A", Raw.Type.STRING), "Foo", new Raw("B", Raw.Type.STRING))).xml("fooAFooB") + ).map(builder -> { + return builder.queryType(QueryType.TO_MAP_RECURSIVE); + }).map(TestSpec.Builder::create).forEach(data::add); + + var arrayTestSpec = testSpec().expect(List.of( + new Raw("Hello", Raw.Type.STRING), + Map.of("foo", new Raw("Bye", Raw.Type.STRING)), + new Raw("integer", Raw.Type.INTEGER), + Map.of(), + new Raw(Boolean.TRUE.toString(), Raw.Type.BOOLEAN) + )).queryType(QueryType.RAW_ARRAY_RECURSIVE); + + Stream.of( + "HellofooByeinteger", + "HelloBingofooByeinteger", + "BHellofooByeByeeeinteger", + "HellobarfooByeinteger", + "HellofooByefooByeByeinteger" + ).map(xml -> { + return "foo" + xml + ""; + }).map(arrayTestSpec::xml).map(TestSpec.Builder::create).forEach(data::add); + + return data; } - private static QueryValueTestSpec.Builder testSpec() { - return new QueryValueTestSpec.Builder(); + private static TestSpec.Builder testSpec() { + return new TestSpec.Builder(); } - private static QueryValueTestSpec.Builder testSpec(QueryType queryType) { + private static TestSpec.Builder testSpec(QueryType queryType) { return testSpec().queryType(queryType); } @@ -248,7 +468,9 @@ private static String xmlToString(String ...xml) { final List content = new ArrayList<>(); content.add(""); content.add(""); + content.add(""); content.addAll(List.of(xml)); + content.add(""); content.add(""); return String.join("", content.toArray(String[]::new)); } diff --git a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java index 81831f59da3..e6d8b41f05f 100644 --- a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java +++ b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java @@ -21,15 +21,16 @@ * questions. */ +import static java.util.Map.entry; + import java.nio.file.Path; import java.util.List; import java.util.Map; -import static java.util.Map.entry; -import jdk.jpackage.test.JPackageCommand; -import jdk.jpackage.test.TKit; -import jdk.jpackage.test.MacHelper; import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.TKit; /** * Tests generation of app image with --file-associations and mac additional file @@ -80,21 +81,26 @@ private static void checkStringValue(PListReader plist, String key, String value "Check value of %s plist key", key)); } - private static void checkBoolValue(PListReader plist, String key, Boolean value) { - Boolean result = plist.queryBoolValue(key); - TKit.assertEquals(value.toString(), result.toString(), String.format( + private static void checkBoolValue(PListReader plist, String key, boolean value) { + boolean result = plist.queryBoolValue(key); + TKit.assertEquals(value, result, String.format( "Check value of %s plist key", key)); } private static void checkArrayValue(PListReader plist, String key, List values) { - List result = plist.queryArrayValue(key); + List result = plist.queryStringArrayValue(key); TKit.assertStringListEquals(values, result, String.format( "Check value of %s plist key", key)); } private static void verifyPList(Path appImage) throws Exception { - var plist = MacHelper.readPListFromAppImage(appImage); + final var rootPlist = MacHelper.readPListFromAppImage(appImage); + + TKit.traceFileContents(appImage.resolve("Contents/Info.plist"), "Info.plist"); + + var plist = rootPlist.queryArrayValue("CFBundleDocumentTypes", false).findFirst().map(PListReader.class::cast).orElseThrow(); + checkStringValue(plist, "CFBundleTypeRole", "Viewer"); checkStringValue(plist, "LSHandlerRank", "Default"); checkStringValue(plist, "NSDocumentClass", "SomeClass"); @@ -103,10 +109,13 @@ private static void verifyPList(Path appImage) throws Exception { checkBoolValue(plist, "LSSupportsOpeningDocumentsInPlace", false); checkBoolValue(plist, "UISupportsDocumentBrowser", false); - checkArrayValue(plist, "NSExportableTypes", List.of("public.png", - "public.jpg")); + plist = rootPlist.queryArrayValue("UTExportedTypeDeclarations", false).findFirst().map(PListReader.class::cast).orElseThrow(); + + checkArrayValue(plist, "UTTypeConformsTo", List.of("public.image", "public.data")); + + plist = plist.queryDictValue("UTTypeTagSpecification"); + + checkArrayValue(plist, "NSExportableTypes", List.of("public.png", "public.jpg")); - checkArrayValue(plist, "UTTypeConformsTo", List.of("public.image", - "public.data")); } } diff --git a/test/jdk/tools/sincechecker/modules/java.base/JavaBaseCheckSince.java b/test/jdk/tools/sincechecker/modules/java.base/JavaBaseCheckSince.java index 64d5bf2465f..b75b6d9401a 100644 --- a/test/jdk/tools/sincechecker/modules/java.base/JavaBaseCheckSince.java +++ b/test/jdk/tools/sincechecker/modules/java.base/JavaBaseCheckSince.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 @@ -23,8 +23,8 @@ /* * @test - * @bug 8331051 + * @bug 8331051 8367610 * @summary Test for `@since` in java.base module * @library /test/lib /test/jdk/tools/sincechecker - * @run main SinceChecker java.base --exclude java.lang.classfile + * @run main/timeout=480 SinceChecker java.base --exclude java.lang.classfile */ diff --git a/test/langtools/ProblemList.txt b/test/langtools/ProblemList.txt index 59b5b240a29..9d61a20663d 100644 --- a/test/langtools/ProblemList.txt +++ b/test/langtools/ProblemList.txt @@ -52,8 +52,6 @@ jdk/jshell/UserJdiUserRemoteTest.java jdk/jshell/UserInputTest.java 8169536 generic-all jdk/jshell/ToolBasicTest.java 8265357 macosx-aarch64 jdk/jshell/HighlightUITest.java 8284144 generic-all -jdk/jshell/ToolSimpleTest.java 8366582 generic-all -jdk/jshell/ToolLocalSimpleTest.java 8366582 generic-all ########################################################################### # diff --git a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java index 8615d9f1e64..00c2f017909 100644 --- a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java +++ b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java @@ -427,7 +427,8 @@ void checkSearchOutput(String fileName, boolean expectedOutput) { """, """ const pathtoroot = "./"; - loadScripts(document, 'script');""", + loadScripts(); + initTheme();""", "
", """
  • Search
  • """, diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java index 413de03d23b..26030629738 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8266666 8275788 8276964 8299080 + * @bug 8266666 8275788 8276964 8299080 8276966 * @summary Implementation for snippets * @library /tools/lib ../../lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -2166,6 +2166,7 @@ public void testNegativeHybridTag_Mismatch(Path base) throws Exception { Hello, Snippet! ----------------- external ----------------- Hello, Snippet!...more + -------------------------------------------- """); @@ -2207,8 +2208,16 @@ public void testNegativeHybridTagMarkup_RegionRegionMismatch(Path base) throws E "pkg"); checkExit(Exit.ERROR); checkOutput(Output.OUT, true, - """ - A.java:4: error: contents mismatch"""); + """ + A.java:4: error: contents mismatch""", + """ + ----------------- inline ------------------- + Hello, Snippet! ...more + \s\s + ----------------- external ----------------- + Hello, Snippet! + \s\s + --------------------------------------------"""); checkOutput("pkg/A.html", true, """
    invalid @snippet @@ -2219,6 +2228,7 @@ public void testNegativeHybridTagMarkup_RegionRegionMismatch(Path base) throws E ----------------- external ----------------- Hello, Snippet! + --------------------------------------------
    """); diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index 19f7b89a1b3..7907fa4d027 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -941,4 +941,14 @@ public void testAnnotation() { assertEval("import static java.lang.annotation.RetentionPolicy.*;"); assertCompletion("@AnnA(C|", true, "CLASS"); } + + @Test + public void testMultiSnippet() { + assertCompletion("String s = \"\"; s.len|", true, "length()"); + assertCompletion("String s() { return \"\"; } s().len|", true, "length()"); + assertCompletion("String s() { return \"\"; } import java.util.List; List.o|", true, "of("); + assertCompletion("String s() { return \"\"; } import java.ut| ", true, "util."); + assertCompletion("class S { public int length() { return 0; } } new S().len|", true, "length()"); + assertSignature("void f() { } f(|", "void f()"); + } } diff --git a/test/langtools/tools/javac/platform/CompilationTest.java b/test/langtools/tools/javac/platform/CompilationTest.java new file mode 100644 index 00000000000..93fb2fb2678 --- /dev/null +++ b/test/langtools/tools/javac/platform/CompilationTest.java @@ -0,0 +1,75 @@ +/* + * 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 8365060 + * @summary Verify javac can compile given snippets with --release + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.platform + * jdk.compiler/com.sun.tools.javac.util:+open + * @build toolbox.ToolBox CompilationTest + * @run main CompilationTest + */ + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class CompilationTest { + + private final ToolBox tb = new ToolBox(); + public static void main(String... args) throws IOException, URISyntaxException { + CompilationTest t = new CompilationTest(); + + t.testJdkNet(); + } + + void testJdkNet() throws IOException { + Path root = Paths.get("."); + Path classes = root.resolve("classes"); + Files.createDirectories(classes); + + new JavacTask(tb) + .outdir(classes) + .options("--release", "8", + "-XDrawDiagnostics") + .sources(""" + import jdk.net.ExtendedSocketOptions; + public class Test { + } + """) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + } + +} diff --git a/test/langtools/tools/javac/sym/ElementStructureTest.java b/test/langtools/tools/javac/sym/ElementStructureTest.java index f1cc3cd91fe..14fa194501a 100644 --- a/test/langtools/tools/javac/sym/ElementStructureTest.java +++ b/test/langtools/tools/javac/sym/ElementStructureTest.java @@ -132,10 +132,10 @@ public class ElementStructureTest { (byte) 0x3D, (byte) 0xC1, (byte) 0xFE, (byte) 0xCB }; static final byte[] hash8 = new byte[] { - (byte) 0x10, (byte) 0xE6, (byte) 0xE8, (byte) 0x11, - (byte) 0xC8, (byte) 0x02, (byte) 0x63, (byte) 0x9B, - (byte) 0xAB, (byte) 0x11, (byte) 0x9E, (byte) 0x4F, - (byte) 0xFA, (byte) 0x00, (byte) 0x6D, (byte) 0x81 + (byte) 0x07, (byte) 0xAB, (byte) 0x0A, (byte) 0x8D, + (byte) 0x1C, (byte) 0x44, (byte) 0x6D, (byte) 0x71, + (byte) 0x07, (byte) 0x53, (byte) 0x59, (byte) 0x74, + (byte) 0x5B, (byte) 0x49, (byte) 0x60, (byte) 0xAD }; final static Map version2Hash = new HashMap<>(); @@ -283,7 +283,7 @@ void realClasses(String location, Predicate acceptor, Writer output, Str } JavaFileObject file = new ByteArrayJavaFileObject(data.toByteArray()); try (InputStream in = new ByteArrayInputStream(data.toByteArray())) { - String name = ClassFile.of().parse(in.readAllBytes()).thisClass().name().stringValue(); + String name = ClassFile.of().parse(in.readAllBytes()).thisClass().name().stringValue().replace("/", "."); className2File.put(name, file); file2ClassName.put(file, name); } catch (IOException ex) { @@ -514,6 +514,8 @@ private void writeConstant(Object value) throws IOException { out.write(Double.toHexString((Double) value)); } else if (value instanceof Float) { out.write(Float.toHexString((Float) value)); + } else if (value instanceof Character ch && Character.isSurrogate(ch)) { + out.write(Integer.toHexString(ch)); } else { out.write(String.valueOf(value)); } diff --git a/test/langtools/tools/javac/tree/TreePosTest.java b/test/langtools/tools/javac/tree/TreePosTest.java index 0ae62ca940d..9e6dcf61306 100644 --- a/test/langtools/tools/javac/tree/TreePosTest.java +++ b/test/langtools/tools/javac/tree/TreePosTest.java @@ -38,16 +38,11 @@ import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.nio.charset.Charset; +import java.io.UncheckedIOException; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; import javax.swing.DefaultComboBoxModel; import javax.swing.JComboBox; @@ -71,7 +66,7 @@ import com.sun.source.tree.CaseTree.CaseKind; import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTaskPool; import com.sun.tools.javac.api.JavacTool; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.EndPosTable; @@ -80,7 +75,6 @@ import com.sun.tools.javac.tree.JCTree.JCCase; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; -import com.sun.tools.javac.tree.JCTree.JCImport; import com.sun.tools.javac.tree.JCTree.JCImportBase; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCNewClass; @@ -90,7 +84,6 @@ import static com.sun.tools.javac.tree.JCTree.Tag.*; import static com.sun.tools.javac.util.Position.NOPOS; -import java.util.stream.Stream; /** * Utility and test program to check validity of tree positions for tree nodes. @@ -275,6 +268,7 @@ void test(File file) { PrintWriter pw = new PrintWriter(sw); Reporter r = new Reporter(pw); JavacTool tool = JavacTool.create(); + JavacTaskPool pool = new JavacTaskPool(1); StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null); /** @@ -285,21 +279,25 @@ void test(File file) { * @throws TreePosTest.ParseException if any errors occur while parsing the file */ JCCompilationUnit read(File file) throws IOException, ParseException { - JavacTool tool = JavacTool.create(); r.errors = 0; Iterable files = fm.getJavaFileObjects(file); - JavacTask task = tool.getTask(pw, fm, r, List.of("-proc:none"), null, files); - Iterable trees = task.parse(); - pw.flush(); - if (r.errors > 0) - throw new ParseException(sw.toString()); - Iterator iter = trees.iterator(); - if (!iter.hasNext()) - throw new Error("no trees found"); - JCCompilationUnit t = (JCCompilationUnit) iter.next(); - if (iter.hasNext()) - throw new Error("too many trees found"); - return t; + return pool.getTask(pw, fm, r, List.of("-proc:none"), null, files, task -> { + try { + Iterable trees = task.parse(); + pw.flush(); + if (r.errors > 0) + throw new ParseException(sw.toString()); + Iterator iter = trees.iterator(); + if (!iter.hasNext()) + throw new Error("no trees found"); + JCCompilationUnit t = (JCCompilationUnit) iter.next(); + if (iter.hasNext()) + throw new Error("too many trees found"); + return t; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); } /** @@ -546,7 +544,7 @@ public String toString() { /** * Thrown when errors are found parsing a java file. */ - private static class ParseException extends Exception { + private static class ParseException extends RuntimeException { ParseException(String msg) { super(msg); } diff --git a/test/langtools/tools/javac/warnings/WerrorLint.e1.out b/test/langtools/tools/javac/warnings/WerrorLint.e1.out new file mode 100644 index 00000000000..ae99cfa5056 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint.e1.out @@ -0,0 +1,4 @@ +WerrorLint.java:20:19: compiler.warn.strictfp +- compiler.err.warnings.and.werror +1 error +1 warning diff --git a/test/langtools/tools/javac/warnings/WerrorLint.e2.out b/test/langtools/tools/javac/warnings/WerrorLint.e2.out new file mode 100644 index 00000000000..1c9bd4d54f8 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint.e2.out @@ -0,0 +1,5 @@ +WerrorLint.java:20:19: compiler.warn.strictfp +WerrorLint.java:21:30: compiler.warn.empty.if +- compiler.err.warnings.and.werror +1 error +2 warnings diff --git a/test/langtools/tools/javac/warnings/WerrorLint.java b/test/langtools/tools/javac/warnings/WerrorLint.java new file mode 100644 index 00000000000..3331a664d55 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint.java @@ -0,0 +1,23 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8349847 + * + * @compile -XDrawDiagnostics -Xlint:none WerrorLint.java + * @compile -XDrawDiagnostics -Xlint:none -Werror WerrorLint.java + * @compile -XDrawDiagnostics -Xlint:none -Werror:empty WerrorLint.java + * @compile -XDrawDiagnostics -Xlint:none -Werror:strictfp WerrorLint.java + * @compile/ref=WerrorLint.w2.out -XDrawDiagnostics -Xlint:all WerrorLint.java + * @compile/fail/ref=WerrorLint.e2.out -XDrawDiagnostics -Xlint:all -Werror WerrorLint.java + * @compile/fail/ref=WerrorLint.e2.out -XDrawDiagnostics -Xlint:all -Werror:empty WerrorLint.java + * @compile/fail/ref=WerrorLint.e2.out -XDrawDiagnostics -Xlint:all -Werror:strictfp WerrorLint.java + * @compile/ref=WerrorLint.w1.out -XDrawDiagnostics WerrorLint.java + * @compile/fail/ref=WerrorLint.e1.out -XDrawDiagnostics -Werror WerrorLint.java + * @compile/ref=WerrorLint.w1.out -XDrawDiagnostics -Werror:empty WerrorLint.java + * @compile/fail/ref=WerrorLint.e1.out -XDrawDiagnostics -Werror:strictfp WerrorLint.java + */ + +class WerrorLint { + strictfp void m() { // [strictfp] - this category is enabled by default + if (hashCode() == 1) ; // [empty] - this category is disabled by default + } +} diff --git a/test/langtools/tools/javac/warnings/WerrorLint.w1.out b/test/langtools/tools/javac/warnings/WerrorLint.w1.out new file mode 100644 index 00000000000..3e19de51033 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint.w1.out @@ -0,0 +1,2 @@ +WerrorLint.java:20:19: compiler.warn.strictfp +1 warning diff --git a/test/langtools/tools/javac/warnings/WerrorLint.w2.out b/test/langtools/tools/javac/warnings/WerrorLint.w2.out new file mode 100644 index 00000000000..bac258706a6 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint.w2.out @@ -0,0 +1,3 @@ +WerrorLint.java:20:19: compiler.warn.strictfp +WerrorLint.java:21:30: compiler.warn.empty.if +2 warnings diff --git a/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java b/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java index 83e381356a0..fb67ce83bbe 100644 --- a/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java +++ b/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java @@ -23,8 +23,7 @@ package jdk.test.lib.artifacts; -import jtreg.SkippedException; - +import java.io.IOException; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; @@ -90,15 +89,15 @@ public static Path resolve(String name, Map artifactDescription, * @return the local path to the artifact. If the artifact is a compressed * file that gets unpacked, this path will point to the root * directory of the uncompressed file(s). - * @throws SkippedException thrown if the artifact cannot be found + * @throws IOException thrown if the artifact cannot be found */ - public static Path fetchOne(Class klass) { + public static Path fetchOne(Class klass) throws IOException { try { return ArtifactResolver.resolve(klass).entrySet().stream() .findAny().get().getValue(); } catch (ArtifactResolverException e) { Artifact artifact = klass.getAnnotation(Artifact.class); - throw new SkippedException("Cannot find the artifact " + artifact.name(), e); + throw new IOException("Cannot find the artifact " + artifact.name(), e); } } diff --git a/test/lib/jdk/test/lib/net/SimpleHttpServer.java b/test/lib/jdk/test/lib/net/SimpleHttpServer.java deleted file mode 100644 index 1905091eac6..00000000000 --- a/test/lib/jdk/test/lib/net/SimpleHttpServer.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.test.lib.net; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.FileSystemNotFoundException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import com.sun.net.httpserver.Headers; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; - -/** - * A simple HTTP Server. - **/ -public class SimpleHttpServer { - private final HttpServer httpServer; - private ExecutorService executor; - private String address; - private final String context; - private final String docRoot; - private final InetSocketAddress inetSocketAddress; - - public SimpleHttpServer(final InetSocketAddress inetSocketAddress, final String context, final String docRoot) - throws IOException { - this.inetSocketAddress = inetSocketAddress; - this.context = context; - this.docRoot = docRoot; - httpServer = HttpServer.create(); - } - - public void start() throws IOException, URISyntaxException { - MyHttpHandler handler = new MyHttpHandler(docRoot); - httpServer.bind(inetSocketAddress, 0); - httpServer.createContext(context, handler); - executor = Executors.newCachedThreadPool(); - httpServer.setExecutor(executor); - httpServer.start(); - address = "http:" + URIBuilder.newBuilder().host(httpServer.getAddress().getAddress()). - port(httpServer.getAddress().getPort()).build().toString(); - } - - public void stop() { - httpServer.stop(0); - executor.shutdown(); - } - - public String getAddress() { - return address; - } - - public int getPort() { - return httpServer.getAddress().getPort(); - } - - class MyHttpHandler implements HttpHandler { - private final URI rootUri; - - MyHttpHandler(final String docroot) { - rootUri = Path.of(docroot).toUri().normalize(); - } - - public void handle(final HttpExchange t) throws IOException { - try (InputStream is = t.getRequestBody()) { - is.readAllBytes(); - Headers rMap = t.getResponseHeaders(); - try (OutputStream os = t.getResponseBody()) { - URI uri = t.getRequestURI(); - String path = uri.getRawPath(); - assert path.isEmpty() || path.startsWith("/"); - Path fPath; - try { - uri = URI.create("file://" + rootUri.getRawPath() + path).normalize(); - fPath = Path.of(uri); - } catch (IllegalArgumentException | FileSystemNotFoundException ex) { - ex.printStackTrace(); - notfound(t, path); - return; - } - byte[] bytes = Files.readAllBytes(fPath); - String method = t.getRequestMethod(); - if (method.equals("HEAD")) { - rMap.set("Content-Length", Long.toString(bytes.length)); - t.sendResponseHeaders(200, -1); - t.close(); - } else if (!method.equals("GET")) { - t.sendResponseHeaders(405, -1); - t.close(); - return; - } - if (path.endsWith(".html") || path.endsWith(".htm")) { - rMap.set("Content-Type", "text/html"); - } else { - rMap.set("Content-Type", "text/plain"); - } - t.sendResponseHeaders(200, bytes.length); - os.write(bytes); - } - } - } - void moved(final HttpExchange t) throws IOException { - Headers req = t.getRequestHeaders(); - Headers map = t.getResponseHeaders(); - URI uri = t.getRequestURI(); - String host = req.getFirst("Host"); - String location = "http://" + host + uri.getPath() + "/"; - map.set("Content-Type", "text/html"); - map.set("Location", location); - t.sendResponseHeaders(301, -1); - t.close(); - } - void notfound(final HttpExchange t, final String p) throws IOException { - t.getResponseHeaders().set("Content-Type", "text/html"); - t.sendResponseHeaders(404, 0); - try (OutputStream os = t.getResponseBody()) { - String s = "

    File not found

    "; - s = s + p + "

    "; - os.write(s.getBytes()); - } - t.close(); - } - } -} diff --git a/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java b/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java index 82252000154..6fa8cb2e408 100644 --- a/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java +++ b/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java @@ -23,6 +23,7 @@ package jdk.test.lib.security; +import java.io.IOException; import java.nio.file.Path; import jdk.test.lib.Platform; import jdk.test.lib.process.ProcessTools; @@ -49,42 +50,40 @@ public class OpensslArtifactFetcher { * * @return openssl binary path of the current version * @throws SkippedException if a valid version of OpenSSL cannot be found + * or if OpenSSL is not available on the target platform */ public static String getOpensslPath() { String path = getOpensslFromSystemProp(OPENSSL_BUNDLE_VERSION); if (path != null) { + System.out.println("Using OpenSSL from system property."); return path; } + path = getDefaultSystemOpensslPath(OPENSSL_BUNDLE_VERSION); if (path != null) { + System.out.println("Using OpenSSL from system."); return path; } + if (Platform.isX64()) { if (Platform.isLinux()) { - path = fetchOpenssl(LINUX_X64.class); + return fetchOpenssl(LINUX_X64.class); } else if (Platform.isOSX()) { - path = fetchOpenssl(MACOSX_X64.class); + return fetchOpenssl(MACOSX_X64.class); } else if (Platform.isWindows()) { - path = fetchOpenssl(WINDOWS_X64.class); + return fetchOpenssl(WINDOWS_X64.class); } } else if (Platform.isAArch64()) { if (Platform.isLinux()) { - path = fetchOpenssl(LINUX_AARCH64.class); + return fetchOpenssl(LINUX_AARCH64.class); } if (Platform.isOSX()) { - path = fetchOpenssl(MACOSX_AARCH64.class); + return fetchOpenssl(MACOSX_AARCH64.class); } } - if (!verifyOpensslVersion(path, OPENSSL_BUNDLE_VERSION)) { - String exMsg = "Can't find the version: " - + OpensslArtifactFetcher.getTestOpensslBundleVersion() - + " of openssl binary on this machine, please install" - + " and set openssl path with property 'test.openssl.path'"; - throw new SkippedException(exMsg); - } else { - return path; - } + throw new SkippedException(String.format("No OpenSSL %s found for %s/%s", + OPENSSL_BUNDLE_VERSION, Platform.getOsName(), Platform.getOsArch())); } private static String getOpensslFromSystemProp(String version) { @@ -120,9 +119,13 @@ private static boolean verifyOpensslVersion(String path, String version) { } private static String fetchOpenssl(Class clazz) { - return ArtifactResolver.fetchOne(clazz) - .resolve("openssl", "bin", "openssl") - .toString(); + try { + return ArtifactResolver.fetchOne(clazz) + .resolve("openssl", "bin", "openssl") + .toString(); + } catch (IOException exc) { + throw new SkippedException("Could not find openssl", exc); + } } // retrieve the provider directory path from /bin/openssl diff --git a/test/lib/jdk/test/lib/threaddump/ThreadDump.java b/test/lib/jdk/test/lib/threaddump/ThreadDump.java index f4964a9521f..ca728e625fc 100644 --- a/test/lib/jdk/test/lib/threaddump/ThreadDump.java +++ b/test/lib/jdk/test/lib/threaddump/ThreadDump.java @@ -296,6 +296,16 @@ public String parkBlocker() { return getStringProperty("parkBlocker", "object"); } + /** + * Returns the owner of the parkBlocker if the parkBlocker is an AbstractOwnableSynchronizer. + */ + public OptionalLong parkBlockerOwner() { + String owner = getStringProperty("parkBlocker", "owner"); + return (owner != null) + ? OptionalLong.of(Long.parseLong(owner)) + : OptionalLong.empty(); + } + /** * Returns the object that the thread is blocked entering its monitor. */ diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 5adb7bf5127..d07dedd2a8c 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -490,6 +490,12 @@ public Object[] getNMethod(Executable method, boolean isOsr) { Objects.requireNonNull(method); return getNMethod0(method, isOsr); } + private native void relocateNMethodFromMethod0(Executable method, int type); + public void relocateNMethodFromMethod(Executable method, int type) { + Objects.requireNonNull(method); + relocateNMethodFromMethod0(method, type); + } + public native void relocateNMethodFromAddr(long address, int type); public native long allocateCodeBlob(int size, int type); public long allocateCodeBlob(long size, int type) { int intSize = (int) size; @@ -841,13 +847,12 @@ public native int validateCgroup(boolean cgroupsV2Enabled, public native void waitUnsafe(int time_ms); - public native void busyWait(int cpuTimeMs); + public native void busyWaitCPUTime(int cpuTimeMs); + // returns true if supported, false if not public native boolean cpuSamplerSetOutOfStackWalking(boolean enable); - public native long cpuSamplerOutOfStackWalkingIterations(); - public native void pinObject(Object o); public native void unpinObject(Object o); diff --git a/test/lib/jdk/test/whitebox/code/CodeBlob.java b/test/lib/jdk/test/whitebox/code/CodeBlob.java index c6c23fdff0c..fd95b5a7e7d 100644 --- a/test/lib/jdk/test/whitebox/code/CodeBlob.java +++ b/test/lib/jdk/test/whitebox/code/CodeBlob.java @@ -46,18 +46,22 @@ public static CodeBlob getCodeBlob(long addr) { return new CodeBlob(obj); } protected CodeBlob(Object[] obj) { - assert obj.length == 4; + assert obj.length == 6; name = (String) obj[0]; size = (Integer) obj[1]; int blob_type_index = (Integer) obj[2]; code_blob_type = BlobType.values()[blob_type_index]; assert code_blob_type.id == (Integer) obj[2]; address = (Long) obj[3]; + code_begin = (Long) obj[4]; + isNMethod = (Boolean) obj[5]; } public final String name; public final int size; public final BlobType code_blob_type; public final long address; + public final long code_begin; + public final boolean isNMethod; @Override public String toString() { return "CodeBlob{" @@ -65,6 +69,7 @@ public String toString() { + ", size=" + size + ", code_blob_type=" + code_blob_type + ", address=" + address + + ", code_begin=" + code_begin + '}'; } } diff --git a/test/micro/org/openjdk/bench/java/text/DefFormatterBench.java b/test/micro/org/openjdk/bench/java/text/DefFormatterBench.java index 1da18cc97a0..cd49469c15d 100644 --- a/test/micro/org/openjdk/bench/java/text/DefFormatterBench.java +++ b/test/micro/org/openjdk/bench/java/text/DefFormatterBench.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 @@ -22,13 +22,16 @@ */ package org.openjdk.bench.java.text; +import java.math.BigDecimal; import java.text.NumberFormat; import java.util.Locale; import java.util.concurrent.TimeUnit; +import java.util.stream.DoubleStream; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OperationsPerInvocation; @@ -50,25 +53,52 @@ @State(Scope.Benchmark) public class DefFormatterBench { + public static final int VALUES_SIZE = 13; public double[] values; + public BigDecimal[] bdLargeValues; + public BigDecimal[] bdSmallValues; - @Setup + @Setup(Level.Invocation) public void setup() { values = new double[] { 1.23, 1.49, 1.80, 1.7, 0.0, -1.49, -1.50, 9999.9123, 1.494, 1.495, 1.03, 25.996, -25.996 }; + + bdLargeValues = DoubleStream.of(values) + .mapToObj(BigDecimal::new) + .toArray(BigDecimal[]::new); + + bdSmallValues = DoubleStream.of(values) + .mapToObj(BigDecimal::valueOf) + .toArray(BigDecimal[]::new); } private DefNumberFormat dnf = new DefNumberFormat(); @Benchmark - @OperationsPerInvocation(13) + @OperationsPerInvocation(VALUES_SIZE) public void testDefNumberFormatter(final Blackhole blackhole) { for (double value : values) { blackhole.consume(this.dnf.format(value)); } } + @Benchmark + @OperationsPerInvocation(VALUES_SIZE) + public void testSmallBigDecDefNumberFormatter(final Blackhole blackhole) { + for (BigDecimal value : bdSmallValues) { + blackhole.consume(this.dnf.format(value)); + } + } + + @Benchmark + @OperationsPerInvocation(VALUES_SIZE) + public void testLargeBigDecDefNumberFormatter(final Blackhole blackhole) { + for (BigDecimal value : bdLargeValues) { + blackhole.consume(this.dnf.format(value)); + } + } + public static void main(String... args) throws Exception { Options opts = new OptionsBuilder().include(DefFormatterBench.class.getSimpleName()).shouldDoGC(true).build(); new Runner(opts).run(); @@ -88,5 +118,9 @@ public DefNumberFormat() { public String format(final double d) { return this.n.format(d); } + + public String format(final BigDecimal bd) { + return this.n.format(bd); + } } }