diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a96f29c0835..9cdd6757260 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,7 +38,7 @@ on: platforms: description: 'Platform(s) to execute on (comma separated, e.g. "linux-x64, macos, aarch64")' required: true - default: 'linux-x64, linux-x86, linux-x64-variants, linux-cross-compile, macos-x64, macos-aarch64, windows-x64, windows-aarch64, docs' + default: 'linux-x64, linux-x86-hs, linux-x64-variants, linux-cross-compile, macos-x64, macos-aarch64, windows-x64, windows-aarch64, docs' configure-arguments: description: 'Additional configure arguments' required: false @@ -61,7 +61,7 @@ jobs: runs-on: ubuntu-22.04 outputs: linux-x64: ${{ steps.include.outputs.linux-x64 }} - linux-x86: ${{ steps.include.outputs.linux-x86 }} + linux-x86-hs: ${{ steps.include.outputs.linux-x86-hs }} linux-x64-variants: ${{ steps.include.outputs.linux-x64-variants }} linux-cross-compile: ${{ steps.include.outputs.linux-cross-compile }} macos-x64: ${{ steps.include.outputs.macos-x64 }} @@ -113,7 +113,7 @@ jobs: } echo "linux-x64=$(check_platform linux-x64 linux x64)" >> $GITHUB_OUTPUT - echo "linux-x86=$(check_platform linux-x86 linux x86)" >> $GITHUB_OUTPUT + echo "linux-x86-hs=$(check_platform linux-x86-hs linux x86)" >> $GITHUB_OUTPUT echo "linux-x64-variants=$(check_platform linux-x64-variants variants)" >> $GITHUB_OUTPUT echo "linux-cross-compile=$(check_platform linux-cross-compile cross-compile)" >> $GITHUB_OUTPUT echo "macos-x64=$(check_platform macos-x64 macos x64)" >> $GITHUB_OUTPUT @@ -152,12 +152,13 @@ jobs: make-arguments: ${{ github.event.inputs.make-arguments }} if: needs.select.outputs.linux-x64 == 'true' - build-linux-x86: - name: linux-x86 + build-linux-x86-hs: + name: linux-x86-hs needs: select uses: ./.github/workflows/build-linux.yml with: platform: linux-x86 + make-target: 'hotspot' gcc-major-version: '10' gcc-package-suffix: '-multilib' apt-architecture: 'i386' @@ -167,7 +168,7 @@ jobs: extra-conf-options: '--with-target-bits=32' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.linux-x86 == 'true' + if: needs.select.outputs.linux-x86-hs == 'true' build-linux-x64-hs-nopch: name: linux-x64-hs-nopch @@ -317,16 +318,6 @@ jobs: bootjdk-platform: linux-x64 runs-on: ubuntu-22.04 - test-linux-x86: - name: linux-x86 - needs: - - build-linux-x86 - uses: ./.github/workflows/test.yml - with: - platform: linux-x86 - bootjdk-platform: linux-x64 - runs-on: ubuntu-22.04 - test-macos-x64: name: macos-x64 needs: @@ -364,7 +355,7 @@ jobs: # if: always() # remove only when all passed, so that workflow can support rerun failed jobs needs: - build-linux-x64 - - build-linux-x86 + - build-linux-x86-hs - build-linux-x64-hs-nopch - build-linux-x64-hs-zero - build-linux-x64-hs-minimal @@ -375,31 +366,27 @@ jobs: - build-windows-x64 - build-windows-aarch64 - test-linux-x64 - - test-linux-x86 - test-macos-x64 - test-windows-x64 steps: - # Hack to get hold of the api environment variables that are only defined for actions - - name: 'Get API configuration' - id: api - uses: actions/github-script@v7 - with: - script: 'return { url: process.env["ACTIONS_RUNTIME_URL"], token: process.env["ACTIONS_RUNTIME_TOKEN"] }' - - name: 'Remove bundle artifacts' run: | # Find and remove all bundle artifacts - ALL_ARTIFACT_URLS="$(curl -s \ - -H 'Accept: application/json;api-version=6.0-preview' \ - -H 'Authorization: Bearer ${{ fromJson(steps.api.outputs.result).token }}' \ - '${{ fromJson(steps.api.outputs.result).url }}_apis/pipelines/workflows/${{ github.run_id }}/artifacts?api-version=6.0-preview')" - BUNDLE_ARTIFACT_URLS="$(echo "$ALL_ARTIFACT_URLS" | jq -r -c '.value | map(select(.name|startswith("bundles-"))) | .[].url')" - for url in $BUNDLE_ARTIFACT_URLS; do - echo "Removing $url" - curl -s \ - -H 'Accept: application/json;api-version=6.0-preview' \ - -H 'Authorization: Bearer ${{ fromJson(steps.api.outputs.result).token }}' \ - -X DELETE "$url" \ + # See: https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28 + ALL_ARTIFACT_IDS="$(curl -sL \ + -H 'Accept: application/vnd.github+json' \ + -H 'Authorization: Bearer ${{ github.token }}' \ + -H 'X-GitHub-Api-Version: 2022-11-28' \ + '${{ github.api_url }}/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts')" + BUNDLE_ARTIFACT_IDS="$(echo "$ALL_ARTIFACT_IDS" | jq -r -c '.artifacts | map(select(.name|startswith("bundles-"))) | .[].id')" + for id in $BUNDLE_ARTIFACT_IDS; do + echo "Removing $id" + curl -sL \ + -X DELETE \ + -H 'Accept: application/vnd.github+json' \ + -H 'Authorization: Bearer ${{ github.token }}' \ + -H 'X-GitHub-Api-Version: 2022-11-28' \ + "${{ github.api_url }}/repos/${{ github.repository }}/actions/artifacts/$id" \ || echo "Failed to remove bundle" done diff --git a/.jcheck/conf b/.jcheck/conf index dac5c3e0c81..889e226d1c4 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -1,10 +1,11 @@ [general] project=jdk-updates jbs=JDK -version=21.0.4 +version=21.0.5 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists +warning=issuestitle,binary [repository] tags=(?:jdk-(?:[1-9]([0-9]*)(?:\.(?:0|[1-9][0-9]*)){0,4})(?:\+(?:(?:[0-9]+))|(?:-ga)))|(?:jdk[4-9](?:u\d{1,3})?-(?:(?:b\d{2,3})|(?:ga)))|(?:hs\d\d(?:\.\d{1,2})?-b\d\d) diff --git a/make/autoconf/configure.ac b/make/autoconf/configure.ac index 6afa36ac18d..f7e9844a643 100644 --- a/make/autoconf/configure.ac +++ b/make/autoconf/configure.ac @@ -313,9 +313,11 @@ AC_OUTPUT # After AC_OUTPUT, we need to do final work CUSTOM_CONFIG_OUTPUT_GENERATED_HOOK -BASIC_POST_CONFIG_OUTPUT # Finally output some useful information to the user HELP_PRINT_SUMMARY_AND_WARNINGS CUSTOM_SUMMARY_AND_WARNINGS_HOOK HELP_REPEAT_WARNINGS + +# All output is done. Do the post-config output management. +BASIC_POST_CONFIG_OUTPUT diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 58e04be8a99..2cbdf74aef6 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -500,9 +500,15 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_LEAK_SANITIZER], # AC_DEFUN_ONCE([JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER], [ + UTIL_ARG_WITH(NAME: additional-ubsan-checks, TYPE: string, + DEFAULT: [], + DESC: [Customizes the ubsan checks], + OPTIONAL: true) + # GCC reports lots of likely false positives for stringop-truncation and format-overflow. # Silence them for now. - UBSAN_CHECKS="-fsanitize=undefined -fsanitize=float-divide-by-zero -fno-sanitize=shift-base -fno-sanitize=alignment" + UBSAN_CHECKS="-fsanitize=undefined -fsanitize=float-divide-by-zero -fno-sanitize=shift-base -fno-sanitize=alignment \ + $ADDITIONAL_UBSAN_CHECKS" UBSAN_CFLAGS="$UBSAN_CHECKS -Wno-stringop-truncation -Wno-format-overflow -fno-omit-frame-pointer -DUNDEFINED_BEHAVIOR_SANITIZER" UBSAN_LDFLAGS="$UBSAN_CHECKS" UTIL_ARG_ENABLE(NAME: ubsan, DEFAULT: false, RESULT: UBSAN_ENABLED, diff --git a/make/autoconf/lib-alsa.m4 b/make/autoconf/lib-alsa.m4 index 19a91f94809..8d0fb324cd0 100644 --- a/make/autoconf/lib-alsa.m4 +++ b/make/autoconf/lib-alsa.m4 @@ -70,6 +70,25 @@ AC_DEFUN_ONCE([LIB_SETUP_ALSA], PKG_CHECK_MODULES(ALSA, alsa, [ALSA_FOUND=yes], [ALSA_FOUND=no]) fi fi + if test "x$ALSA_FOUND" = xno; then + # If we have sysroot set, and no explicit library location is set, + # look at known locations in sysroot. + if test "x$SYSROOT" != "x" && test "x${with_alsa_lib}" == x; then + if test -f "$SYSROOT/usr/lib64/libasound.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + ALSA_LIBS="-L$SYSROOT/usr/lib64 -lasound" + ALSA_FOUND=yes + elif test -f "$SYSROOT/usr/lib/libasound.so"; then + ALSA_LIBS="-L$SYSROOT/usr/lib -lasound" + ALSA_FOUND=yes + elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libasound.so"; then + ALSA_LIBS="-L$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI -lasound" + ALSA_FOUND=yes + elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libasound.so"; then + ALSA_LIBS="-L$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI -lasound" + ALSA_FOUND=yes + fi + fi + fi if test "x$ALSA_FOUND" = xno; then AC_CHECK_HEADERS([alsa/asoundlib.h], [ diff --git a/make/autoconf/lib-x11.m4 b/make/autoconf/lib-x11.m4 index b1902a432a1..6849b4a26c7 100644 --- a/make/autoconf/lib-x11.m4 +++ b/make/autoconf/lib-x11.m4 @@ -71,9 +71,9 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], elif test -f "$SYSROOT/usr/lib/libX11.so"; then x_libraries="$SYSROOT/usr/lib" elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so"; then - x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so" + x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI" elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so"; then - x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so" + x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI" fi fi fi diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index bd499ac896a..e8c9ad9e308 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -28,15 +28,15 @@ DEFAULT_VERSION_FEATURE=21 DEFAULT_VERSION_INTERIM=0 -DEFAULT_VERSION_UPDATE=4 +DEFAULT_VERSION_UPDATE=5 DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2024-07-16 +DEFAULT_VERSION_DATE=2024-10-15 DEFAULT_VERSION_CLASSFILE_MAJOR=65 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 DEFAULT_ACCEPTABLE_BOOT_VERSIONS="20 21" DEFAULT_JDK_SOURCE_TARGET_VERSION=21 -DEFAULT_PROMOTED_VERSION_PRE= +DEFAULT_PROMOTED_VERSION_PRE=ea diff --git a/make/data/cldr/common/main/ff_Adlm.xml b/make/data/cldr/common/main/ff_Adlm.xml index ecb8421e6ab..d45d859e70e 100644 --- a/make/data/cldr/common/main/ff_Adlm.xml +++ b/make/data/cldr/common/main/ff_Adlm.xml @@ -708,7 +708,7 @@ CLDR data files are interpreted according to the LDML specification (http://unic 𞤄𞤢𞤸𞤢𞤥𞤢𞥄𞤧 𞤄𞤵𞥅𞤼𞤢𞥄𞤲 𞤅𞤵𞤪𞤭𞥅𞤪𞤫 𞤄𞤵𞥅𞤾𞤫𞥅 - ‮𞤄𞤮𞤼𞤧𞤵𞤱𞤢𞥄𞤲𞤢 + 𞤄𞤮𞤼𞤧𞤵𞤱𞤢𞥄𞤲𞤢 𞤄𞤫𞤤𞤢𞤪𞤵𞥅𞤧 𞤄𞤫𞤤𞤭𞥅𞥁 𞤑𞤢𞤲𞤢𞤣𞤢𞥄 @@ -8278,7 +8278,7 @@ CLDR data files are interpreted according to the LDML specification (http://unic 𞤐𞤵𞥅𞤳 - ‮𞤋𞤼𞥆𞤮𞤳𞤮𞤪𞤼𞤮𞥅𞤪𞤥𞤭𞥅𞤼 + 𞤋𞤼𞥆𞤮𞤳𞤮𞤪𞤼𞤮𞥅𞤪𞤥𞤭𞥅𞤼 𞤁𞤢𞥄𞤲𞤥𞤢𞤪𞤳𞥃𞤢𞥄𞤾𞤲 diff --git a/make/devkit/createJMHBundle.sh b/make/devkit/createJMHBundle.sh index b2b10769d15..889b7f914a4 100644 --- a/make/devkit/createJMHBundle.sh +++ b/make/devkit/createJMHBundle.sh @@ -44,7 +44,7 @@ rm -f * fetchJar() { url="${MAVEN_MIRROR}/$1/$2/$3/$2-$3.jar" if command -v curl > /dev/null; then - curl -O --fail $url + curl -OL --fail $url elif command -v wget > /dev/null; then wget $url else diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index d21e7f99c63..4b7bf9b6152 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -157,8 +157,13 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \ DISABLED_WARNINGS_gcc_ad_$(HOTSPOT_TARGET_CPU_ARCH).cpp := nonnull, \ DISABLED_WARNINGS_gcc_cgroupV1Subsystem_linux.cpp := address, \ DISABLED_WARNINGS_gcc_cgroupV2Subsystem_linux.cpp := address, \ + DISABLED_WARNINGS_gcc_handshake.cpp := stringop-overflow, \ DISABLED_WARNINGS_gcc_interp_masm_x86.cpp := uninitialized, \ + DISABLED_WARNINGS_gcc_jvmciCodeInstaller.cpp := stringop-overflow, \ + DISABLED_WARNINGS_gcc_jvmtiTagMap.cpp := stringop-overflow, \ DISABLED_WARNINGS_gcc_postaloc.cpp := address, \ + DISABLED_WARNINGS_gcc_shenandoahLock.cpp := stringop-overflow, \ + DISABLED_WARNINGS_gcc_synchronizer.cpp := stringop-overflow, \ DISABLED_WARNINGS_clang := $(DISABLED_WARNINGS_clang), \ DISABLED_WARNINGS_clang_arguments.cpp := missing-field-initializers, \ DISABLED_WARNINGS_clang_codeBuffer.cpp := tautological-undefined-compare, \ diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk index a33f219e83e..f0c92ee094f 100644 --- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk +++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk @@ -245,6 +245,13 @@ ifeq ($(call isTargetOs, windows macosx), false) DISABLED_WARNINGS_gcc_XRBackendNative.c := maybe-uninitialized, \ DISABLED_WARNINGS_gcc_XToolkit.c := unused-result, \ DISABLED_WARNINGS_gcc_XWindow.c := unused-function, \ + DISABLED_WARNINGS_clang_awt_Taskbar.c := parentheses, \ + DISABLED_WARNINGS_clang_gtk2_interface.c := parentheses, \ + DISABLED_WARNINGS_clang_gtk3_interface.c := parentheses, \ + DISABLED_WARNINGS_clang_OGLBufImgOps.c := format-nonliteral, \ + DISABLED_WARNINGS_clang_OGLPaints.c := format-nonliteral, \ + DISABLED_WARNINGS_clang_screencast_pipewire.c := format-nonliteral, \ + DISABLED_WARNINGS_clang_sun_awt_X11_GtkFileDialogPeer.c := parentheses, \ DISABLED_WARNINGS_clang_aix := deprecated-non-prototype, \ DISABLED_WARNINGS_clang_aix_awt_Taskbar.c := parentheses, \ DISABLED_WARNINGS_clang_aix_OGLPaints.c := format-nonliteral, \ @@ -465,7 +472,10 @@ else endif # hb-ft.cc is not presently needed, and requires freetype 2.4.2 or later. - LIBFONTMANAGER_EXCLUDE_FILES += libharfbuzz/hb-ft.cc + # hb-subset and hb-style APIs are not needed, excluded to cut on compilation time. + LIBFONTMANAGER_EXCLUDE_FILES += hb-ft.cc hb-subset-cff-common.cc \ + hb-subset-cff1.cc hb-subset-cff2.cc hb-subset-input.cc hb-subset-plan.cc \ + hb-subset.cc hb-subset-instancer-solver.cc gsubgpos-context.cc hb-style.cc # list of disabled warnings and the compilers for which it was specifically added. # array-bounds -> GCC 12 on Alpine Linux diff --git a/make/modules/java.security.jgss/Lib.gmk b/make/modules/java.security.jgss/Lib.gmk index a13c2987cd6..fcd46b44044 100644 --- a/make/modules/java.security.jgss/Lib.gmk +++ b/make/modules/java.security.jgss/Lib.gmk @@ -33,6 +33,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJ2GSS, \ CFLAGS := $(CFLAGS_JDKLIB), \ DISABLED_WARNINGS_gcc := undef, \ DISABLED_WARNINGS_clang_aix := undef, \ + DISABLED_WARNINGS_clang := undef, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS := $(LIBDL), \ diff --git a/make/modules/jdk.hotspot.agent/Lib.gmk b/make/modules/jdk.hotspot.agent/Lib.gmk index 478d199e5ec..d21c969c188 100644 --- a/make/modules/jdk.hotspot.agent/Lib.gmk +++ b/make/modules/jdk.hotspot.agent/Lib.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -61,6 +61,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBSA, \ OPTIMIZATION := HIGH, \ DISABLED_WARNINGS_gcc := sign-compare, \ DISABLED_WARNINGS_gcc_ps_core.c := pointer-arith, \ + DISABLED_WARNINGS_clang_ps_core.c := pointer-arith, \ DISABLED_WARNINGS_clang := sign-compare, \ DISABLED_WARNINGS_clang_libproc_impl.c := format-nonliteral, \ DISABLED_WARNINGS_clang_sadis.c := format-nonliteral, \ diff --git a/make/modules/jdk.jpackage/Lib.gmk b/make/modules/jdk.jpackage/Lib.gmk index 8cce38fe0cd..1d3e27e8a6b 100644 --- a/make/modules/jdk.jpackage/Lib.gmk +++ b/make/modules/jdk.jpackage/Lib.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,8 @@ $(eval $(call SetupJdkExecutable, BUILD_JPACKAGE_APPLAUNCHEREXE, \ INCLUDE_FILES := $(JPACKAGE_APPLAUNCHER_INCLUDE_FILES), \ TOOLCHAIN := $(JPACKAGE_APPLAUNCHER_TOOLCHAIN), \ OPTIMIZATION := LOW, \ + DISABLED_WARNINGS_clang_LinuxPackage.c := format-nonliteral, \ + DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \ CXXFLAGS := $(call JpackageWithStaticCrt, $(CXXFLAGS_JDKEXE)) \ $(JPACKAGE_APPLAUNCHER_INCLUDES), \ CFLAGS := $(call JpackageWithStaticCrt, $(CFLAGS_JDKEXE)) \ @@ -103,6 +105,8 @@ ifeq ($(call isTargetOs, linux), true) EXCLUDE_FILES := LinuxLauncher.c LinuxPackage.c, \ TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ OPTIMIZATION := LOW, \ + DISABLED_WARNINGS_clang_JvmLauncherLib.c := format-nonliteral, \ + DISABLED_WARNINGS_clang_tstrings.cpp := format-nonliteral, \ CXXFLAGS := $(CXXFLAGS_JDKLIB) $(JPACKAGE_LIBAPPLAUNCHER_INCLUDES), \ CFLAGS := $(CFLAGS_JDKLIB) $(JPACKAGE_LIBAPPLAUNCHER_INCLUDES), \ LDFLAGS := $(LDFLAGS_JDKLIB), \ diff --git a/make/modules/jdk.management/Lib.gmk b/make/modules/jdk.management/Lib.gmk index 7afce982380..b4bf5084413 100644 --- a/make/modules/jdk.management/Lib.gmk +++ b/make/modules/jdk.management/Lib.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. # 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 @@ endif $(eval $(call SetupJdkLibrary, BUILD_LIBMANAGEMENT_EXT, \ NAME := management_ext, \ OPTIMIZATION := $(LIBMANAGEMENT_EXT_OPTIMIZATION), \ + DISABLED_WARNINGS_clang_UnixOperatingSystem.c := format-nonliteral, \ CFLAGS := $(CFLAGS_JDKLIB) $(LIBMANAGEMENT_EXT_CFLAGS), \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ diff --git a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java index 6b89d02ad2f..354c3a01661 100644 --- a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java +++ b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -660,7 +660,7 @@ private static void printJfrEventControlHpp(Metadata metadata, File outputFile) out.write(""); out.write("union JfrNativeSettings {"); out.write(" // Array version."); - out.write(" jfrNativeEventSetting bits[NUMBER_OF_EVENTS];"); + out.write(" jfrNativeEventSetting bits[NUMBER_OF_EVENTS + NUMBER_OF_RESERVED_EVENTS];"); out.write(" // Then, to make it easy to debug,"); out.write(" // add named struct members also."); out.write(" struct {"); diff --git a/make/test/BuildFailureHandler.gmk b/make/test/BuildFailureHandler.gmk index ac133dc6a68..5b54ca22cf1 100644 --- a/make/test/BuildFailureHandler.gmk +++ b/make/test/BuildFailureHandler.gmk @@ -80,6 +80,10 @@ IMAGES_TARGETS += $(COPY_FH) # Use JTREG_TEST_OPTS for test VM options # Use JTREG_TESTS for jtreg tests parameter # +# Most likely you want to select a specific test from test/failure_handler/test +# and manually inspect the results. This target does not actually verify +# anything about the failure_handler's output or even if it ran at all. +# RUN_DIR := $(FH_SUPPORT)/test test: diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 5698d4356a7..6ad85089a4a 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -694,6 +694,11 @@ reg_class no_special_ptr_reg %{ return _NO_SPECIAL_PTR_REG_mask; %} +// Class for all non_special pointer registers (excluding rfp) +reg_class no_special_no_rfp_ptr_reg %{ + return _NO_SPECIAL_NO_RFP_PTR_REG_mask; +%} + // Class for all float registers reg_class float_reg( V0, @@ -1125,6 +1130,7 @@ extern RegMask _PTR_REG_mask; extern RegMask _NO_SPECIAL_REG32_mask; extern RegMask _NO_SPECIAL_REG_mask; extern RegMask _NO_SPECIAL_PTR_REG_mask; +extern RegMask _NO_SPECIAL_NO_RFP_PTR_REG_mask; class CallStubImpl { @@ -1213,6 +1219,7 @@ source %{ RegMask _NO_SPECIAL_REG32_mask; RegMask _NO_SPECIAL_REG_mask; RegMask _NO_SPECIAL_PTR_REG_mask; + RegMask _NO_SPECIAL_NO_RFP_PTR_REG_mask; void reg_mask_init() { // We derive below RegMask(s) from the ones which are auto-generated from @@ -1249,6 +1256,9 @@ source %{ _NO_SPECIAL_REG_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg())); _NO_SPECIAL_PTR_REG_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg())); } + + _NO_SPECIAL_NO_RFP_PTR_REG_mask = _NO_SPECIAL_PTR_REG_mask; + _NO_SPECIAL_NO_RFP_PTR_REG_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg())); } // Optimizaton of volatile gets and puts @@ -1721,8 +1731,8 @@ void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const { st->print("# stack bang size=%d\n\t", framesize); if (VM_Version::use_rop_protection()) { - st->print("ldr zr, [lr]\n\t"); - st->print("pacia lr, rfp\n\t"); + st->print("ldr zr, [lr]\n\t"); + st->print("paciaz\n\t"); } if (framesize < ((1 << 9) + 2 * wordSize)) { st->print("sub sp, sp, #%d\n\t", framesize); @@ -1851,8 +1861,8 @@ void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const { st->print("ldp lr, rfp, [sp],#%d\n\t", (2 * wordSize)); } if (VM_Version::use_rop_protection()) { - st->print("autia lr, rfp\n\t"); - st->print("ldr zr, [lr]\n\t"); + st->print("autiaz\n\t"); + st->print("ldr zr, [lr]\n\t"); } if (do_polling() && C->is_method_compilation()) { @@ -4885,6 +4895,18 @@ operand iRegPNoSp() interface(REG_INTER); %} +// This operand is not allowed to use rfp even if +// rfp is not used to hold the frame pointer. +operand iRegPNoSpNoRfp() +%{ + constraint(ALLOC_IN_RC(no_special_no_rfp_ptr_reg)); + match(RegP); + match(iRegPNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + // Pointer 64 bit Register R0 only operand iRegP_R0() %{ @@ -16576,7 +16598,9 @@ instruct CallLeafNoFPDirect(method meth) // Also known as an 'interprocedural jump'. // Target of jump will eventually return to caller. // TailJump below removes the return address. -instruct TailCalljmpInd(iRegPNoSp jump_target, inline_cache_RegP method_ptr) +// Don't use rfp for 'jump_target' because a MachEpilogNode has already been +// emitted just above the TailCall which has reset rfp to the caller state. +instruct TailCalljmpInd(iRegPNoSpNoRfp jump_target, inline_cache_RegP method_ptr) %{ match(TailCall jump_target method_ptr); @@ -16589,7 +16613,7 @@ instruct TailCalljmpInd(iRegPNoSp jump_target, inline_cache_RegP method_ptr) ins_pipe(pipe_class_call); %} -instruct TailjmpInd(iRegPNoSp jump_target, iRegP_R0 ex_oop) +instruct TailjmpInd(iRegPNoSpNoRfp jump_target, iRegP_R0 ex_oop) %{ match(TailJump jump_target ex_oop); diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index 4b7d2959a63..d2f4744a049 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -385,7 +385,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) { // load issuing PC (the return address for this stub) into r3 __ ldr(exception_pc, Address(rfp, 1*BytesPerWord)); - __ authenticate_return_address(exception_pc, rscratch1); + __ authenticate_return_address(exception_pc); // make sure that the vm_results are cleared (may be unnecessary) __ str(zr, Address(rthread, JavaThread::vm_result_offset())); @@ -434,7 +434,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) { __ str(exception_pc, Address(rthread, JavaThread::exception_pc_offset())); // patch throwing pc into return address (has bci & oop map) - __ protect_return_address(exception_pc, rscratch1); + __ protect_return_address(exception_pc); __ str(exception_pc, Address(rfp, 1*BytesPerWord)); // compute the exception handler. @@ -450,7 +450,7 @@ OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) { __ invalidate_registers(false, true, true, true, true, true); // patch the return address, this stub will directly return to the exception handler - __ protect_return_address(r0, rscratch1); + __ protect_return_address(r0); __ str(r0, Address(rfp, 1*BytesPerWord)); switch (id) { diff --git a/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp index 17c86c81071..82b579c724f 100644 --- a/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp @@ -62,7 +62,7 @@ inline frame FreezeBase::sender(const frame& f) { intptr_t** link_addr = link_address(f); intptr_t* sender_sp = (intptr_t*)(link_addr + frame::sender_sp_offset); // f.unextended_sp() + (fsize/wordSize); // - address sender_pc = (address) *(sender_sp-1); + address sender_pc = ContinuationHelper::return_address_at(sender_sp - 1); assert(sender_sp != f.sp(), "must have changed"); int slot = 0; @@ -217,7 +217,7 @@ template frame ThawBase::new_stack_frame(const frame& hf, frame& intptr_t* heap_sp = hf.unextended_sp(); // If caller is interpreted it already made room for the callee arguments int overlap = caller.is_interpreted_frame() ? ContinuationHelper::InterpretedFrame::stack_argsize(hf) : 0; - const int fsize = ContinuationHelper::InterpretedFrame::frame_bottom(hf) - hf.unextended_sp() - overlap; + const int fsize = (int)(ContinuationHelper::InterpretedFrame::frame_bottom(hf) - hf.unextended_sp() - overlap); const int locals = hf.interpreter_frame_method()->max_locals(); intptr_t* frame_sp = caller.unextended_sp() - fsize; intptr_t* fp = frame_sp + (hf.fp() - heap_sp); diff --git a/src/hotspot/cpu/aarch64/continuationHelper_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/continuationHelper_aarch64.inline.hpp index 7d673eb8d0d..772893aeb9e 100644 --- a/src/hotspot/cpu/aarch64/continuationHelper_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/continuationHelper_aarch64.inline.hpp @@ -68,6 +68,17 @@ inline void ContinuationHelper::push_pd(const frame& f) { *(intptr_t**)(f.sp() - frame::sender_sp_offset) = f.fp(); } +#define CPU_OVERRIDES_RETURN_ADDRESS_ACCESSORS + +inline address ContinuationHelper::return_address_at(intptr_t* sp) { + return pauth_strip_verifiable(*(address*)sp); +} + +inline void ContinuationHelper::patch_return_address_at(intptr_t* sp, + address pc) { + *(address*)sp = pauth_sign_return_address(pc); +} + inline void ContinuationHelper::set_anchor_to_entry_pd(JavaFrameAnchor* anchor, ContinuationEntry* entry) { anchor->set_last_Java_fp(entry->entry_fp()); } @@ -80,7 +91,8 @@ inline void ContinuationHelper::set_anchor_pd(JavaFrameAnchor* anchor, intptr_t* inline bool ContinuationHelper::Frame::assert_frame_laid_out(frame f) { intptr_t* sp = f.sp(); - address pc = *(address*)(sp - frame::sender_sp_ret_address_offset()); + address pc = ContinuationHelper::return_address_at( + sp - frame::sender_sp_ret_address_offset()); intptr_t* fp = *(intptr_t**)(sp - frame::sender_sp_offset); assert(f.raw_pc() == pc, "f.ra_pc: " INTPTR_FORMAT " actual: " INTPTR_FORMAT, p2i(f.raw_pc()), p2i(pc)); assert(f.fp() == fp, "f.fp: " INTPTR_FORMAT " actual: " INTPTR_FORMAT, p2i(f.fp()), p2i(fp)); @@ -108,13 +120,14 @@ inline void ContinuationHelper::InterpretedFrame::patch_sender_sp(frame& f, cons } inline address ContinuationHelper::Frame::real_pc(const frame& f) { + // Always used in assertions. Just strip it. address* pc_addr = &(((address*) f.sp())[-1]); - return *pc_addr; + return pauth_strip_pointer(*pc_addr); } inline void ContinuationHelper::Frame::patch_pc(const frame& f, address pc) { address* pc_addr = &(((address*) f.sp())[-1]); - *pc_addr = pc; + *pc_addr = pauth_sign_return_address(pc); } inline intptr_t* ContinuationHelper::InterpretedFrame::frame_top(const frame& f, InterpreterOopMap* mask) { // inclusive; this will be copied with the frame diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index 2357721ed3d..b10362db2d9 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -139,8 +139,7 @@ bool frame::safe_for_sender(JavaThread *thread) { sender_sp = (intptr_t*) addr_at(sender_sp_offset); sender_unextended_sp = (intptr_t*) this->fp()[interpreter_frame_sender_sp_offset]; saved_fp = (intptr_t*) this->fp()[link_offset]; - sender_pc = pauth_strip_verifiable((address) this->fp()[return_addr_offset], (address)saved_fp); - + sender_pc = pauth_strip_verifiable((address) this->fp()[return_addr_offset]); } else { // must be some sort of compiled/runtime frame // fp does not have to be safe (although it could be check for c1?) @@ -158,7 +157,9 @@ bool frame::safe_for_sender(JavaThread *thread) { sender_unextended_sp = sender_sp; // Note: frame::sender_sp_offset is only valid for compiled frame saved_fp = (intptr_t*) *(sender_sp - frame::sender_sp_offset); - sender_pc = pauth_strip_verifiable((address) *(sender_sp-1), (address)saved_fp); + // Note: PAC authentication may fail in case broken frame is passed in. + // Just strip it for now. + sender_pc = pauth_strip_pointer((address) *(sender_sp - 1)); } if (Continuation::is_return_barrier_entry(sender_pc)) { @@ -276,9 +277,8 @@ bool frame::safe_for_sender(JavaThread *thread) { void frame::patch_pc(Thread* thread, address pc) { assert(_cb == CodeCache::find_blob(pc), "unexpected pc"); address* pc_addr = &(((address*) sp())[-1]); - address signing_sp = (((address*) sp())[-2]); - address signed_pc = pauth_sign_return_address(pc, (address)signing_sp); - address pc_old = pauth_strip_verifiable(*pc_addr, (address)signing_sp); + address signed_pc = pauth_sign_return_address(pc); + address pc_old = pauth_strip_verifiable(*pc_addr); if (TracePcPatching) { tty->print("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]", @@ -472,8 +472,9 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { } #endif // COMPILER2_OR_JVMCI - // For ROP protection, Interpreter will have signed the sender_pc, but there is no requirement to authenticate it here. - address sender_pc = pauth_strip_verifiable(sender_pc_maybe_signed(), (address)link()); + // For ROP protection, Interpreter will have signed the sender_pc, + // but there is no requirement to authenticate it here. + address sender_pc = pauth_strip_verifiable(sender_pc_maybe_signed()); if (Continuation::is_return_barrier_entry(sender_pc)) { if (map->walk_cont()) { // about to walk into an h-stack diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp index 39dc16d2748..4b623294726 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp @@ -152,7 +152,10 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address setup(pc); } -inline frame::frame(intptr_t* sp) : frame(sp, sp, *(intptr_t**)(sp - frame::sender_sp_offset), *(address*)(sp - 1)) {} +inline frame::frame(intptr_t* sp) + : frame(sp, sp, + *(intptr_t**)(sp - frame::sender_sp_offset), + pauth_strip_verifiable(*(address*)(sp - 1))) {} inline frame::frame(intptr_t* sp, intptr_t* fp) { intptr_t a = intptr_t(sp); @@ -233,13 +236,13 @@ inline intptr_t* frame::real_fp() const { inline int frame::frame_size() const { return is_interpreted_frame() - ? sender_sp() - sp() + ? pointer_delta_as_int(sender_sp(), sp()) : cb()->frame_size(); } inline int frame::compiled_frame_stack_argsize() const { assert(cb()->is_compiled(), ""); - return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; + return (cb()->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; } inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const { @@ -416,9 +419,10 @@ inline frame frame::sender_for_compiled_frame(RegisterMap* map) const { : sender_sp(); assert(!_sp_is_trusted || l_sender_sp == real_fp(), ""); - // the return_address is always the word on the stack - // For ROP protection, C1/C2 will have signed the sender_pc, but there is no requirement to authenticate it here. - address sender_pc = pauth_strip_verifiable((address) *(l_sender_sp-1), (address) *(l_sender_sp-2)); + // The return_address is always the word on the stack. + // For ROP protection, C1/C2 will have signed the sender_pc, + // but there is no requirement to authenticate it here. + address sender_pc = pauth_strip_verifiable((address) *(l_sender_sp - 1)); intptr_t** saved_fp_addr = (intptr_t**) (l_sender_sp - frame::sender_sp_offset); diff --git a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp index e140525bcbc..cd834969e1a 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp @@ -38,7 +38,7 @@ // Default value if probing is not implemented for a certain platform // Max address bit is restricted by implicit assumptions in the code, for instance -// the bit layout of XForwardingEntry or Partial array entry (see XMarkStackEntry) in mark stack +// the bit layout of ZForwardingEntry or Partial array entry (see ZMarkStackEntry) in mark stack static const size_t DEFAULT_MAX_ADDRESS_BIT = 46; // Minimum value returned, if probing fail static const size_t MINIMUM_MAX_ADDRESS_BIT = 36; diff --git a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp index 2293d70c8da..801c8aae7fc 100644 --- a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -72,4 +72,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define USE_POINTERS_TO_REGISTER_IMPL_ARRAY +#define USE_TRAMPOLINE_STUB_FIX_OWNER + #endif // CPU_AARCH64_GLOBALDEFINITIONS_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 9eab3d967e1..2ba0110079c 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -6133,51 +6133,43 @@ void MacroAssembler::leave() { // For more details on PAC see pauth_aarch64.hpp. // Sign the LR. Use during construction of a stack frame, before storing the LR to memory. -// Uses the FP as the modifier. +// Uses value zero as the modifier. // void MacroAssembler::protect_return_address() { if (VM_Version::use_rop_protection()) { check_return_address(); - // The standard convention for C code is to use paciasp, which uses SP as the modifier. This - // works because in C code, FP and SP match on function entry. In the JDK, SP and FP may not - // match, so instead explicitly use the FP. - pacia(lr, rfp); + paciaz(); } } // Sign the return value in the given register. Use before updating the LR in the existing stack // frame for the current function. -// Uses the FP from the start of the function as the modifier - which is stored at the address of -// the current FP. +// Uses value zero as the modifier. // -void MacroAssembler::protect_return_address(Register return_reg, Register temp_reg) { +void MacroAssembler::protect_return_address(Register return_reg) { if (VM_Version::use_rop_protection()) { - assert(PreserveFramePointer, "PreserveFramePointer must be set for ROP protection"); check_return_address(return_reg); - ldr(temp_reg, Address(rfp)); - pacia(return_reg, temp_reg); + paciza(return_reg); } } // Authenticate the LR. Use before function return, after restoring FP and loading LR from memory. +// Uses value zero as the modifier. // -void MacroAssembler::authenticate_return_address(Register return_reg) { +void MacroAssembler::authenticate_return_address() { if (VM_Version::use_rop_protection()) { - autia(return_reg, rfp); - check_return_address(return_reg); + autiaz(); + check_return_address(); } } // Authenticate the return value in the given register. Use before updating the LR in the existing // stack frame for the current function. -// Uses the FP from the start of the function as the modifier - which is stored at the address of -// the current FP. +// Uses value zero as the modifier. // -void MacroAssembler::authenticate_return_address(Register return_reg, Register temp_reg) { +void MacroAssembler::authenticate_return_address(Register return_reg) { if (VM_Version::use_rop_protection()) { - assert(PreserveFramePointer, "PreserveFramePointer must be set for ROP protection"); - ldr(temp_reg, Address(rfp)); - autia(return_reg, temp_reg); + autiza(return_reg); check_return_address(return_reg); } } diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 8e8d22e55f3..d16a3893098 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -716,9 +716,9 @@ class MacroAssembler: public Assembler { // ROP Protection void protect_return_address(); - void protect_return_address(Register return_reg, Register temp_reg); - void authenticate_return_address(Register return_reg = lr); - void authenticate_return_address(Register return_reg, Register temp_reg); + void protect_return_address(Register return_reg); + void authenticate_return_address(); + void authenticate_return_address(Register return_reg); void strip_return_address(); void check_return_address(Register return_reg=lr) PRODUCT_RETURN; diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index 27bf35e12c8..a7a2006aeb1 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,7 +28,6 @@ #include "code/codeCache.hpp" #include "code/compiledIC.hpp" #include "gc/shared/collectedHeap.hpp" -#include "memory/resourceArea.hpp" #include "nativeInst_aarch64.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.hpp" @@ -159,13 +158,18 @@ void NativeGotJump::verify() const { } address NativeCall::destination() const { - address addr = (address)this; - address destination = instruction_address() + displacement(); + address addr = instruction_address(); + address destination = addr + displacement(); + + // Performance optimization: no need to call find_blob() if it is a self-call + if (destination == addr) { + return destination; + } // Do we use a trampoline stub for this call? CodeBlob* cb = CodeCache::find_blob(addr); - assert(cb && cb->is_nmethod(), "sanity"); - nmethod *nm = (nmethod *)cb; + assert(cb != nullptr && cb->is_nmethod(), "nmethod expected"); + nmethod *nm = cb->as_nmethod(); if (nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) { // Yes we do, so get the destination from the trampoline stub. const address trampoline_stub_addr = destination; @@ -180,17 +184,11 @@ address NativeCall::destination() const { // call instruction at all times. // // Used in the runtime linkage of calls; see class CompiledIC. -// -// Add parameter assert_lock to switch off assertion -// during code generation, where no patching lock is needed. -void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) { - assert(!assert_lock || - (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || +void NativeCall::set_destination_mt_safe(address dest) { + assert((Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || CompiledICLocker::is_safe(addr_at(0)), "concurrent code patching"); - ResourceMark rm; - int code_size = NativeInstruction::instruction_size; address addr_call = addr_at(0); bool reachable = Assembler::reachable_from_branch_at(addr_call, dest); assert(NativeCall::is_call_at(addr_call), "unexpected code at call site"); @@ -214,22 +212,18 @@ void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) { } address NativeCall::get_trampoline() { - address call_addr = addr_at(0); + address call_addr = instruction_address(); CodeBlob *code = CodeCache::find_blob(call_addr); - assert(code != nullptr, "Could not find the containing code blob"); + assert(code != nullptr && code->is_nmethod(), "nmethod expected"); + nmethod* nm = code->as_nmethod(); - address bl_destination - = MacroAssembler::pd_call_destination(call_addr); - if (code->contains(bl_destination) && + address bl_destination = call_addr + displacement(); + if (nm->stub_contains(bl_destination) && is_NativeCallTrampolineStub_at(bl_destination)) return bl_destination; - if (code->is_nmethod()) { - return trampoline_stub_Relocation::get_trampoline_for(call_addr, (nmethod*)code); - } - - return nullptr; + return trampoline_stub_Relocation::get_trampoline_for(call_addr, nm); } // Inserts a native call instruction at a given pc diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp index 1740fde772f..0c0122c891b 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2108, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -212,6 +212,7 @@ class NativeCall: public NativeInstruction { int displacement() const { return (int_at(displacement_offset) << 6) >> 4; } address displacement_address() const { return addr_at(displacement_offset); } address return_address() const { return addr_at(return_address_offset); } + address raw_destination() const { return instruction_address() + displacement(); } address destination() const; void set_destination(address dest) { @@ -251,9 +252,7 @@ class NativeCall: public NativeInstruction { // // Used in the runtime linkage of calls; see class CompiledIC. // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) - - // The parameter assert_lock disables the assertion during code generation. - void set_destination_mt_safe(address dest, bool assert_lock = true); + void set_destination_mt_safe(address dest); address get_trampoline(); #if INCLUDE_JVMCI diff --git a/src/hotspot/cpu/aarch64/pauth_aarch64.hpp b/src/hotspot/cpu/aarch64/pauth_aarch64.hpp index ac2b109b3ee..cd35af6c6c2 100644 --- a/src/hotspot/cpu/aarch64/pauth_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/pauth_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Arm Limited. All rights reserved. + * Copyright (c) 2021, 2023, Arm Limited. All rights reserved. * 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,9 +77,9 @@ inline bool pauth_ptr_is_raw(address ptr) { // Strip a return value (same as pauth_strip_pointer). When debug is enabled then authenticate // instead. // -inline address pauth_strip_verifiable(address ret_addr, address modifier) { +inline address pauth_strip_verifiable(address ret_addr) { if (VM_Version::use_rop_protection()) { - DEBUG_ONLY(ret_addr = pauth_authenticate_return_address(ret_addr, modifier);) + DEBUG_ONLY(ret_addr = pauth_authenticate_return_address(ret_addr);) NOT_DEBUG(ret_addr = pauth_strip_pointer(ret_addr)); } return ret_addr; diff --git a/src/hotspot/cpu/aarch64/register_aarch64.hpp b/src/hotspot/cpu/aarch64/register_aarch64.hpp index cd09a58ae8b..ef34e08a377 100644 --- a/src/hotspot/cpu/aarch64/register_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/register_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, 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. * @@ -52,7 +52,7 @@ class Register { public: // accessors - constexpr int raw_encoding() const { return this - first(); } + constexpr int raw_encoding() const { return checked_cast(this - first()); } constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } @@ -181,7 +181,7 @@ class FloatRegister { public: // accessors - constexpr int raw_encoding() const { return this - first(); } + constexpr int raw_encoding() const { return checked_cast(this - first()); } constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } @@ -314,7 +314,7 @@ class PRegister { public: // accessors - int raw_encoding() const { return this - first(); } + int raw_encoding() const { return checked_cast(this - first()); } int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } bool is_governing() const { return 0 <= raw_encoding() && raw_encoding() < number_of_governing_registers; } diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 4b7930c94a8..8333eb16bdf 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -60,13 +60,12 @@ void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { address Relocation::pd_call_destination(address orig_addr) { assert(is_call(), "should be a call here"); - if (NativeCall::is_call_at(addr())) { - address trampoline = nativeCall_at(addr())->get_trampoline(); - if (trampoline) { - return nativeCallTrampolineStub_at(trampoline)->destination(); + if (orig_addr == nullptr) { + if (NativeCall::is_call_at(addr())) { + NativeCall* call = nativeCall_at(addr()); + return call->destination(); } - } - if (orig_addr != nullptr) { + } else { address new_addr = MacroAssembler::pd_call_destination(orig_addr); // If call is branch to self, don't try to relocate it, just leave it // as branch to self. This happens during code generation if the code @@ -82,16 +81,26 @@ address Relocation::pd_call_destination(address orig_addr) { void Relocation::pd_set_call_destination(address x) { assert(is_call(), "should be a call here"); if (NativeCall::is_call_at(addr())) { - address trampoline = nativeCall_at(addr())->get_trampoline(); - if (trampoline) { - nativeCall_at(addr())->set_destination_mt_safe(x, /* assert_lock */false); - return; - } + NativeCall* call = nativeCall_at(addr()); + call->set_destination(x); + } else { + MacroAssembler::pd_patch_instruction(addr(), x); } - MacroAssembler::pd_patch_instruction(addr(), x); assert(pd_call_destination(addr()) == x, "fail in reloc"); } +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)) { + dest = trampoline; + } + call->set_destination(dest); +} + + address* Relocation::pd_address_in_code() { return (address*)(addr() + 8); } diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index cd2567434f4..8754897631a 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -394,7 +394,7 @@ static void patch_callers_callsite(MacroAssembler *masm) { __ mov(c_rarg0, rmethod); __ mov(c_rarg1, lr); - __ authenticate_return_address(c_rarg1, rscratch1); + __ authenticate_return_address(c_rarg1); __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::fixup_callers_callsite))); __ blr(rscratch1); @@ -1171,6 +1171,7 @@ static void gen_continuation_enter(MacroAssembler* masm, continuation_enter_cleanup(masm); __ ldr(c_rarg1, Address(rfp, wordSize)); // return address + __ authenticate_return_address(c_rarg1); __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, c_rarg1); // see OptoRuntime::generate_exception_blob: r0 -- exception oop, r3 -- exception pc @@ -2337,7 +2338,7 @@ void SharedRuntime::generate_deopt_blob() { // load throwing pc from JavaThread and patch it as the return address // of the current frame. Then clear the field in JavaThread __ ldr(r3, Address(rthread, JavaThread::exception_pc_offset())); - __ protect_return_address(r3, rscratch1); + __ protect_return_address(r3); __ str(r3, Address(rfp, wordSize)); __ str(zr, Address(rthread, JavaThread::exception_pc_offset())); @@ -2443,9 +2444,7 @@ void SharedRuntime::generate_deopt_blob() { __ ldrw(r2, Address(r5, Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset())); __ sub(r2, r2, 2 * wordSize); __ add(sp, sp, r2); - __ ldp(rfp, lr, __ post(sp, 2 * wordSize)); - __ authenticate_return_address(); - // LR should now be the return address to the caller (3) + __ ldp(rfp, zr, __ post(sp, 2 * wordSize)); #ifdef ASSERT // Compilers generate code that bang the stack by as much as the @@ -2660,9 +2659,7 @@ void SharedRuntime::generate_uncommon_trap_blob() { size_of_deoptimized_frame_offset())); __ sub(r2, r2, 2 * wordSize); __ add(sp, sp, r2); - __ ldp(rfp, lr, __ post(sp, 2 * wordSize)); - __ authenticate_return_address(); - // LR should now be the return address to the caller (3) frame + __ ldp(rfp, zr, __ post(sp, 2 * wordSize)); #ifdef ASSERT // Compilers generate code that bang the stack by as much as the @@ -2808,7 +2805,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t // it later to determine if someone changed the return address for // us! __ ldr(r20, Address(rthread, JavaThread::saved_exception_pc_offset())); - __ protect_return_address(r20, rscratch1); + __ protect_return_address(r20); __ str(r20, Address(rfp, wordSize)); } @@ -2849,7 +2846,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t __ ldr(rscratch1, Address(rfp, wordSize)); __ cmp(r20, rscratch1); __ br(Assembler::NE, no_adjust); - __ authenticate_return_address(r20, rscratch1); + __ authenticate_return_address(r20); #ifdef ASSERT // Verify the correct encoding of the poll we're about to skip. @@ -2864,7 +2861,7 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t #endif // Adjust return pc forward to step over the safepoint poll instruction __ add(r20, r20, NativeInstruction::instruction_size); - __ protect_return_address(r20, rscratch1); + __ protect_return_address(r20); __ str(r20, Address(rfp, wordSize)); } diff --git a/src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp index db38b9cf5df..dcba233c9dc 100644 --- a/src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp @@ -30,8 +30,15 @@ // Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } private: static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN DEBUG_ONLY({ assert (r == rfp->as_VMReg() || r == rfp->as_VMReg()->next(), "Reg: %s", r->name()); }) @@ -48,17 +55,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { - #ifdef ASSERT - for(int i = 0; i < RegisterMap::reg_count; i++) { - VMReg r = VMRegImpl::as_VMReg(i); - if (map->location(r, (intptr_t*)nullptr) != nullptr) assert_is_rfp(r); - } - #endif - } - inline address location(VMReg reg, intptr_t* sp) const { assert_is_rfp(reg); return (address)(sp - frame::sender_sp_offset); diff --git a/src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp index 598104264d8..6e662249dec 100644 --- a/src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * 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,6 +26,7 @@ #define CPU_AARCH64_STACKCHUNKFRAMESTREAM_AARCH64_INLINE_HPP #include "interpreter/oopMapCache.hpp" +#include "pauth_aarch64.hpp" #include "runtime/frame.inline.hpp" #include "runtime/registerMap.hpp" @@ -34,7 +35,7 @@ template inline bool StackChunkFrameStream::is_in_frame(void* p0) const { assert(!is_done(), ""); intptr_t* p = (intptr_t*)p0; - int argsize = is_compiled() ? (_cb->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; + int argsize = is_compiled() ? (_cb->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; int frame_size = _cb->frame_size() + argsize; return p == sp() - frame::sender_sp_offset || ((p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size); } @@ -52,7 +53,8 @@ inline frame StackChunkFrameStream::to_frame() const { template inline address StackChunkFrameStream::get_pc() const { assert(!is_done(), ""); - return *(address*)(_sp - 1); + // Just strip it for frames on the heap. + return pauth_strip_pointer(*(address*)(_sp - 1)); } template @@ -114,8 +116,8 @@ inline int StackChunkFrameStream::interpreter_frame_num_oops() const f.interpreted_frame_oop_map(&mask); return mask.num_oops() + 1 // for the mirror oop - + ((intptr_t*)f.interpreter_frame_monitor_begin() - - (intptr_t*)f.interpreter_frame_monitor_end())/BasicObjectLock::size(); + + pointer_delta_as_int((intptr_t*)f.interpreter_frame_monitor_begin(), + (intptr_t*)f.interpreter_frame_monitor_end())/BasicObjectLock::size(); } template<> diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index c30234aae38..31e130bd140 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -7008,8 +7008,10 @@ class StubGenerator: public StubCodeGenerator { if (return_barrier_exception) { __ ldr(c_rarg1, Address(rfp, wordSize)); // return address + __ authenticate_return_address(c_rarg1); __ verify_oop(r0); - __ mov(r19, r0); // save return value contaning the exception oop in callee-saved R19 + // save return value containing the exception oop in callee-saved R19 + __ mov(r19, r0); __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), rthread, c_rarg1); @@ -7019,7 +7021,7 @@ class StubGenerator: public StubCodeGenerator { // see OptoRuntime::generate_exception_blob: r0 -- exception oop, r3 -- exception pc __ mov(r1, r0); // the exception handler - __ mov(r0, r19); // restore return value contaning the exception oop + __ mov(r0, r19); // restore return value containing the exception oop __ verify_oop(r0); __ leave(); diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index 469edaef233..b69faddc552 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -1823,7 +1823,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() { Label caller_not_deoptimized; __ ldr(c_rarg1, Address(rfp, frame::return_addr_offset * wordSize)); // This is a return address, so requires authenticating for PAC. - __ authenticate_return_address(c_rarg1, rscratch1); + __ authenticate_return_address(c_rarg1); __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), c_rarg1); __ cbnz(r0, caller_not_deoptimized); diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 4cd89362064..48b9dcf32b8 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -215,10 +215,9 @@ void VM_Version::initialize() { } } - // Neoverse N1, N2 and V1 - if (_cpu == CPU_ARM && ((_model == 0xd0c || _model2 == 0xd0c) - || (_model == 0xd49 || _model2 == 0xd49) - || (_model == 0xd40 || _model2 == 0xd40))) { + // Neoverse N1, N2, V1, V2 + if (_cpu == CPU_ARM && (model_is(0xd0c) || model_is(0xd49) || + model_is(0xd40) || model_is(0xd4f))) { if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) { FLAG_SET_DEFAULT(UseSIMDForMemoryOps, true); } @@ -466,16 +465,12 @@ void VM_Version::initialize() { strcmp(UseBranchProtection, "pac-ret") == 0) { _rop_protection = false; // Enable ROP-protection if - // 1) this code has been built with branch-protection, - // 2) the CPU/OS supports it, and - // 3) incompatible VMContinuations isn't enabled. + // 1) this code has been built with branch-protection and + // 2) the CPU/OS supports it #ifdef __ARM_FEATURE_PAC_DEFAULT if (!VM_Version::supports_paca()) { // Disable PAC to prevent illegal instruction crashes. warning("ROP-protection specified, but not supported on this CPU. Disabling ROP-protection."); - } else if (VMContinuations) { - // Not currently compatible with continuation freeze/thaw. - warning("ROP-protection is incompatible with VMContinuations. Disabling ROP-protection."); } else { _rop_protection = true; } @@ -490,12 +485,6 @@ void VM_Version::initialize() { // Determine the mask of address bits used for PAC. Clear bit 55 of // the input to make it look like a user address. _pac_mask = (uintptr_t)pauth_strip_pointer((address)~(UINT64_C(1) << 55)); - - // The frame pointer must be preserved for ROP protection. - if (FLAG_IS_DEFAULT(PreserveFramePointer) == false && PreserveFramePointer == false ) { - vm_exit_during_initialization(err_msg("PreserveFramePointer cannot be disabled for ROP-protection")); - } - PreserveFramePointer = true; } #ifdef COMPILER2 diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index 2a2766aa6ed..4b0975c558a 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp @@ -153,6 +153,10 @@ enum Ampere_CPU_Model { static int cpu_variant() { return _variant; } static int cpu_revision() { return _revision; } + static bool model_is(int cpu_model) { + return _model == cpu_model || _model2 == cpu_model; + } + static bool is_zva_enabled() { return 0 <= _zva_length; } static int zva_length() { assert(is_zva_enabled(), "ZVA not available"); diff --git a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp index d9ead450194..af653f4b1d6 100644 --- a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp @@ -197,7 +197,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { temp_reg, temp_reg2, itable_index, L_no_such_interface); // Reduce "estimate" such that "padding" does not drop below 8. - const ptrdiff_t estimate = UseCompactObjectHeaders ? 132 : 124; + const ptrdiff_t estimate = UseCompactObjectHeaders ? 152 : 144; const ptrdiff_t codesize = __ pc() - start_pc; slop_delta = (int)(estimate - codesize); slop_bytes += slop_delta; diff --git a/src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp b/src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp index 4186eafd35f..08adbbd89d8 100644 --- a/src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp +++ b/src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp @@ -30,8 +30,15 @@ // Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } private: static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN DEBUG_ONLY({ Unimplemented(); }) @@ -46,12 +53,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { - Unimplemented(); - } - inline address location(VMReg reg, intptr_t* sp) const { Unimplemented(); return nullptr; diff --git a/src/hotspot/cpu/ppc/assembler_ppc.cpp b/src/hotspot/cpu/ppc/assembler_ppc.cpp index 018b66310e2..26fc1aacad3 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2023 SAP SE. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,9 +78,9 @@ int Assembler::branch_destination(int inst, int pos) { // Low-level andi-one-instruction-macro. void Assembler::andi(Register a, Register s, const long ui16) { - if (is_power_of_2(((jlong) ui16)+1)) { + if (is_power_of_2(((unsigned long) ui16)+1)) { // pow2minus1 - clrldi(a, s, 64 - log2i_exact((((jlong) ui16)+1))); + clrldi(a, s, 64 - log2i_exact((((unsigned long) ui16)+1))); } else if (is_power_of_2((jlong) ui16)) { // pow2 rlwinm(a, s, 0, 31 - log2i_exact((jlong) ui16), 31 - log2i_exact((jlong) ui16)); diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp index b58defc1847..2caca1dc556 100644 --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -578,7 +578,7 @@ inline bool can_handle_logic_op_as_uimm(ValueType *type, Bytecodes::Code bc) { is_power_of_2(int_or_long_const) || is_power_of_2(-int_or_long_const))) return true; if (bc == Bytecodes::_land && - (is_power_of_2(int_or_long_const+1) || + (is_power_of_2((unsigned long)int_or_long_const+1) || (Assembler::is_uimm(int_or_long_const, 32) && is_power_of_2(int_or_long_const)) || (int_or_long_const != min_jlong && is_power_of_2(-int_or_long_const)))) return true; diff --git a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp index c711882189a..012dfd55e85 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp @@ -363,7 +363,7 @@ inline const ImmutableOopMap* frame::get_oop_map() const { inline int frame::compiled_frame_stack_argsize() const { assert(cb()->is_compiled(), ""); - return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; + return (cb()->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; } inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const { diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index d6eaeb7c9af..aff244e0362 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -3533,6 +3533,7 @@ encode %{ call->_in_rms = _in_rms; call->_nesting = _nesting; call->_override_symbolic_info = _override_symbolic_info; + call->_arg_escape = _arg_escape; // New call needs all inputs of old call. // Req... diff --git a/src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp b/src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp index 8c96f51fd88..a6246cd7e74 100644 --- a/src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp @@ -30,9 +30,16 @@ // Java frames don't have callee saved registers, so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; -public: + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } + // as_RegisterMap is used when we didn't want to templatize and abstract over RegisterMap type to support SmallRegisterMap // Consider enhancing SmallRegisterMap to support those cases const RegisterMap* as_RegisterMap() const { return nullptr; } @@ -44,19 +51,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { -#ifdef ASSERT - for(int i = 0; i < RegisterMap::reg_count; i++) { - VMReg r = VMRegImpl::as_VMReg(i); - if (map->location(r, (intptr_t*)nullptr) != nullptr) { - assert(false, "Reg: %s", r->name()); // Should not reach here - } - } -#endif - } - inline address location(VMReg reg, intptr_t* sp) const { assert(false, "Reg: %s", reg->name()); return nullptr; diff --git a/src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp b/src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp index f8d60ed9f93..b4077719f43 100644 --- a/src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp @@ -35,7 +35,7 @@ inline bool StackChunkFrameStream::is_in_frame(void* p0) const { assert(!is_done(), ""); assert(is_compiled(), ""); intptr_t* p = (intptr_t*)p0; - int argsize = (_cb->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; + int argsize = (_cb->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; int frame_size = _cb->frame_size() + (argsize > 0 ? argsize + frame::metadata_words_at_top : 0); return (p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size; } diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 0988056f15a..24de7c15fe3 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -1772,9 +1772,11 @@ enum Nf { // Vector unordered indexed load instructions INSN(vluxei32_v, 0b0000111, 0b110, 0b01, 0b0); + INSN(vluxei64_v, 0b0000111, 0b111, 0b01, 0b0); // Vector unordered indexed store instructions INSN(vsuxei32_v, 0b0100111, 0b110, 0b01, 0b0); + INSN(vsuxei64_v, 0b0100111, 0b111, 0b01, 0b0); #undef INSN diff --git a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp index 5f4b256b192..71217de37da 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp @@ -233,7 +233,7 @@ inline int frame::frame_size() const { inline int frame::compiled_frame_stack_argsize() const { assert(cb()->is_compiled(), ""); - return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; + return (cb()->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; } inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const { diff --git a/src/hotspot/cpu/riscv/register_riscv.hpp b/src/hotspot/cpu/riscv/register_riscv.hpp index 7b547335cd0..bc632e05715 100644 --- a/src/hotspot/cpu/riscv/register_riscv.hpp +++ b/src/hotspot/cpu/riscv/register_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. 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. * @@ -70,7 +70,7 @@ class Register { public: // accessors - constexpr int raw_encoding() const { return this - first(); } + constexpr int raw_encoding() const { return checked_cast(this - first()); } constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } @@ -187,7 +187,7 @@ class FloatRegister { public: // accessors - constexpr int raw_encoding() const { return this - first(); } + constexpr int raw_encoding() const { return checked_cast(this - first()); } constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } @@ -297,7 +297,7 @@ class VectorRegister { public: // accessors - constexpr int raw_encoding() const { return this - first(); } + constexpr int raw_encoding() const { return checked_cast(this - first()); } constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index e63ff695a86..87bcd45e0e2 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -649,10 +649,12 @@ reg_class non_allocatable_reg( R23, R23_H // java thread ); +// Class for all non-special integer registers reg_class no_special_reg32 %{ return _NO_SPECIAL_REG32_mask; %} +// Class for all non-special long integer registers reg_class no_special_reg %{ return _NO_SPECIAL_REG_mask; %} @@ -661,10 +663,16 @@ reg_class ptr_reg %{ return _PTR_REG_mask; %} +// Class for all non_special pointer registers reg_class no_special_ptr_reg %{ return _NO_SPECIAL_PTR_REG_mask; %} +// Class for all non_special pointer registers (excluding fp) +reg_class no_special_no_fp_ptr_reg %{ + return _NO_SPECIAL_NO_FP_PTR_REG_mask; +%} + // Class for 64 bit register r10 reg_class r10_reg( R10, R10_H @@ -1017,6 +1025,7 @@ extern RegMask _PTR_REG_mask; extern RegMask _NO_SPECIAL_REG32_mask; extern RegMask _NO_SPECIAL_REG_mask; extern RegMask _NO_SPECIAL_PTR_REG_mask; +extern RegMask _NO_SPECIAL_NO_FP_PTR_REG_mask; class CallStubImpl { @@ -1079,6 +1088,7 @@ RegMask _PTR_REG_mask; RegMask _NO_SPECIAL_REG32_mask; RegMask _NO_SPECIAL_REG_mask; RegMask _NO_SPECIAL_PTR_REG_mask; +RegMask _NO_SPECIAL_NO_FP_PTR_REG_mask; void reg_mask_init() { @@ -1113,6 +1123,9 @@ void reg_mask_init() { _NO_SPECIAL_REG_mask.Remove(OptoReg::as_OptoReg(x8->as_VMReg())); _NO_SPECIAL_PTR_REG_mask.Remove(OptoReg::as_OptoReg(x8->as_VMReg())); } + + _NO_SPECIAL_NO_FP_PTR_REG_mask = _NO_SPECIAL_PTR_REG_mask; + _NO_SPECIAL_NO_FP_PTR_REG_mask.Remove(OptoReg::as_OptoReg(x8->as_VMReg())); } void PhaseOutput::pd_perform_mach_node_analysis() { @@ -3189,6 +3202,18 @@ operand iRegPNoSp() interface(REG_INTER); %} +// This operand is not allowed to use fp even if +// fp is not used to hold the frame pointer. +operand iRegPNoSpNoFp() +%{ + constraint(ALLOC_IN_RC(no_special_no_fp_ptr_reg)); + match(RegP); + match(iRegPNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + operand iRegP_R10() %{ constraint(ALLOC_IN_RC(r10_reg)); @@ -10241,7 +10266,9 @@ instruct cmpFastUnlock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp1, iR // Also known as an 'interprocedural jump'. // Target of jump will eventually return to caller. // TailJump below removes the return address. -instruct TailCalljmpInd(iRegPNoSp jump_target, inline_cache_RegP method_oop) +// Don't use fp for 'jump_target' because a MachEpilogNode has already been +// emitted just above the TailCall which has reset fp to the caller state. +instruct TailCalljmpInd(iRegPNoSpNoFp jump_target, inline_cache_RegP method_oop) %{ match(TailCall jump_target method_oop); @@ -10254,7 +10281,7 @@ instruct TailCalljmpInd(iRegPNoSp jump_target, inline_cache_RegP method_oop) ins_pipe(pipe_class_call); %} -instruct TailjmpInd(iRegPNoSp jump_target, iRegP_R10 ex_oop) +instruct TailjmpInd(iRegPNoSpNoFp jump_target, iRegP_R10 ex_oop) %{ match(TailJump jump_target ex_oop); diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 145453bb538..0392abe4db3 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -3595,12 +3595,11 @@ instruct vexpand(vReg dst, vReg src, vRegMask_V0 v0, vReg tmp) %{ // ------------------------------ Vector Load Gather --------------------------- -instruct gather_load(vReg dst, indirect mem, vReg idx) %{ - predicate(type2aelembytes(Matcher::vector_element_basic_type(n)) == 4 || - type2aelembytes(Matcher::vector_element_basic_type(n)) == 8); +instruct gather_loadS(vReg dst, indirect mem, vReg idx) %{ + predicate(type2aelembytes(Matcher::vector_element_basic_type(n)) == 4); match(Set dst (LoadVectorGather mem idx)); effect(TEMP_DEF dst); - format %{ "gather_load $dst, $mem, $idx" %} + format %{ "gather_loadS $dst, $mem, $idx" %} ins_encode %{ __ vmv1r_v(as_VectorRegister($dst$$reg), as_VectorRegister($idx$$reg)); BasicType bt = Matcher::vector_element_basic_type(this); @@ -3613,12 +3612,28 @@ instruct gather_load(vReg dst, indirect mem, vReg idx) %{ ins_pipe(pipe_slow); %} -instruct gather_load_masked(vReg dst, indirect mem, vReg idx, vRegMask_V0 v0, vReg tmp) %{ - predicate(type2aelembytes(Matcher::vector_element_basic_type(n)) == 4 || - type2aelembytes(Matcher::vector_element_basic_type(n)) == 8); +instruct gather_loadD(vReg dst, indirect mem, vReg idx) %{ + predicate(type2aelembytes(Matcher::vector_element_basic_type(n)) == 8); + match(Set dst (LoadVectorGather mem idx)); + effect(TEMP_DEF dst); + format %{ "gather_loadD $dst, $mem, $idx" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + Assembler::SEW sew = Assembler::elemtype_to_sew(bt); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vzext_vf2(as_VectorRegister($dst$$reg), as_VectorRegister($idx$$reg)); + __ vsll_vi(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), (int)sew); + __ vluxei64_v(as_VectorRegister($dst$$reg), as_Register($mem$$base), + as_VectorRegister($dst$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct gather_loadS_masked(vReg dst, indirect mem, vReg idx, vRegMask_V0 v0, vReg tmp) %{ + predicate(type2aelembytes(Matcher::vector_element_basic_type(n)) == 4); match(Set dst (LoadVectorGatherMasked mem (Binary idx v0))); effect(TEMP_DEF dst, TEMP tmp); - format %{ "gather_load_masked $dst, $mem, $idx, $v0\t# KILL $tmp" %} + format %{ "gather_loadS_masked $dst, $mem, $idx, $v0\t# KILL $tmp" %} ins_encode %{ __ vmv1r_v(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg)); BasicType bt = Matcher::vector_element_basic_type(this); @@ -3633,14 +3648,32 @@ instruct gather_load_masked(vReg dst, indirect mem, vReg idx, vRegMask_V0 v0, vR ins_pipe(pipe_slow); %} +instruct gather_loadD_masked(vReg dst, indirect mem, vReg idx, vRegMask_V0 v0, vReg tmp) %{ + predicate(type2aelembytes(Matcher::vector_element_basic_type(n)) == 8); + match(Set dst (LoadVectorGatherMasked mem (Binary idx v0))); + effect(TEMP_DEF dst, TEMP tmp); + format %{ "gather_loadD_masked $dst, $mem, $idx, $v0\t# KILL $tmp" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + Assembler::SEW sew = Assembler::elemtype_to_sew(bt); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vzext_vf2(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg)); + __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), (int)sew); + __ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), + as_VectorRegister($dst$$reg)); + __ vluxei64_v(as_VectorRegister($dst$$reg), as_Register($mem$$base), + as_VectorRegister($tmp$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + // ------------------------------ Vector Store Scatter ------------------------- -instruct scatter_store(indirect mem, vReg src, vReg idx, vReg tmp) %{ - predicate(type2aelembytes(Matcher::vector_element_basic_type(n->in(3)->in(1))) == 4 || - type2aelembytes(Matcher::vector_element_basic_type(n->in(3)->in(1))) == 8); +instruct scatter_storeS(indirect mem, vReg src, vReg idx, vReg tmp) %{ + predicate(type2aelembytes(Matcher::vector_element_basic_type(n->in(3)->in(1))) == 4); match(Set mem (StoreVectorScatter mem (Binary src idx))); effect(TEMP tmp); - format %{ "scatter_store $mem, $idx, $src\t# KILL $tmp" %} + format %{ "scatter_storeS $mem, $idx, $src\t# KILL $tmp" %} ins_encode %{ __ vmv1r_v(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg)); BasicType bt = Matcher::vector_element_basic_type(this, $src); @@ -3653,12 +3686,28 @@ instruct scatter_store(indirect mem, vReg src, vReg idx, vReg tmp) %{ ins_pipe(pipe_slow); %} -instruct scatter_store_masked(indirect mem, vReg src, vReg idx, vRegMask_V0 v0, vReg tmp) %{ - predicate(type2aelembytes(Matcher::vector_element_basic_type(n->in(3)->in(1))) == 4 || - type2aelembytes(Matcher::vector_element_basic_type(n->in(3)->in(1))) == 8); +instruct scatter_storeD(indirect mem, vReg src, vReg idx, vReg tmp) %{ + predicate(type2aelembytes(Matcher::vector_element_basic_type(n->in(3)->in(1))) == 8); + match(Set mem (StoreVectorScatter mem (Binary src idx))); + effect(TEMP tmp); + format %{ "scatter_storeD $mem, $idx, $src\t# KILL $tmp" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this, $src); + Assembler::SEW sew = Assembler::elemtype_to_sew(bt); + __ vsetvli_helper(bt, Matcher::vector_length(this, $src)); + __ vzext_vf2(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg)); + __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), (int)sew); + __ vsuxei64_v(as_VectorRegister($src$$reg), as_Register($mem$$base), + as_VectorRegister($tmp$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct scatter_storeS_masked(indirect mem, vReg src, vReg idx, vRegMask_V0 v0, vReg tmp) %{ + predicate(type2aelembytes(Matcher::vector_element_basic_type(n->in(3)->in(1))) == 4); match(Set mem (StoreVectorScatterMasked mem (Binary src (Binary idx v0)))); effect(TEMP tmp); - format %{ "scatter_store_masked $mem, $idx, $src, $v0\t# KILL $tmp" %} + format %{ "scatter_storeS_masked $mem, $idx, $src, $v0\t# KILL $tmp" %} ins_encode %{ __ vmv1r_v(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg)); BasicType bt = Matcher::vector_element_basic_type(this, $src); @@ -3671,6 +3720,23 @@ instruct scatter_store_masked(indirect mem, vReg src, vReg idx, vRegMask_V0 v0, ins_pipe(pipe_slow); %} +instruct scatter_storeD_masked(indirect mem, vReg src, vReg idx, vRegMask_V0 v0, vReg tmp) %{ + predicate(type2aelembytes(Matcher::vector_element_basic_type(n->in(3)->in(1))) == 8); + match(Set mem (StoreVectorScatterMasked mem (Binary src (Binary idx v0)))); + effect(TEMP tmp); + format %{ "scatter_storeD_masked $mem, $idx, $src, $v0\t# KILL $tmp" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this, $src); + Assembler::SEW sew = Assembler::elemtype_to_sew(bt); + __ vsetvli_helper(bt, Matcher::vector_length(this, $src)); + __ vzext_vf2(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg)); + __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), (int)sew); + __ vsuxei64_v(as_VectorRegister($src$$reg), as_Register($mem$$base), + as_VectorRegister($tmp$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + // ------------------------------ Populate Index to a Vector ------------------- instruct populateindex(vReg dst, iRegIorL2I src1, iRegIorL2I src2, vReg tmp) %{ diff --git a/src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp b/src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp index 93adaadcef6..9fc4f1d7b0a 100644 --- a/src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp @@ -30,8 +30,15 @@ // Java frames don't have callee saved registers (except for fp), so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } private: static void assert_is_fp(VMReg r) NOT_DEBUG_RETURN DEBUG_ONLY({ assert (r == fp->as_VMReg() || r == fp->as_VMReg()->next(), "Reg: %s", r->name()); }) @@ -48,17 +55,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { - #ifdef ASSERT - for(int i = 0; i < RegisterMap::reg_count; i++) { - VMReg r = VMRegImpl::as_VMReg(i); - if (map->location(r, (intptr_t*)nullptr) != nullptr) assert_is_fp(r); - } - #endif - } - inline address location(VMReg reg, intptr_t* sp) const { assert_is_fp(reg); return (address)(sp - 2); diff --git a/src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp b/src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp index 38ee1de6470..8028a365fcd 100644 --- a/src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp @@ -34,7 +34,7 @@ template inline bool StackChunkFrameStream::is_in_frame(void* p0) const { assert(!is_done(), ""); intptr_t* p = (intptr_t*)p0; - int argsize = is_compiled() ? (_cb->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; + int argsize = is_compiled() ? (_cb->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; int frame_size = _cb->frame_size() + argsize; return p == sp() - 2 || ((p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size); } diff --git a/src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp b/src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp index 8c74eb7dd6d..625d17cf992 100644 --- a/src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp +++ b/src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp @@ -30,8 +30,15 @@ // Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } private: static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN DEBUG_ONLY({ Unimplemented(); }) @@ -46,12 +53,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { - Unimplemented(); - } - inline address location(VMReg reg, intptr_t* sp) const { Unimplemented(); return nullptr; diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index d619ccaf251..5bfa14f6175 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -1907,7 +1907,7 @@ void Assembler::crc32(Register crc, Address adr, int8_t sizeInBytes) { int8_t w = 0x01; Prefix p = Prefix_EMPTY; - emit_int8((int8_t)0xF2); + emit_int8((uint8_t)0xF2); switch (sizeInBytes) { case 1: w = 0; @@ -2507,7 +2507,7 @@ void Assembler::jmp_literal(address dest, RelocationHolder const& rspec) { assert(dest != nullptr, "must have a target"); intptr_t disp = dest - (pc() + sizeof(int32_t)); assert(is_simm32(disp), "must be 32bit offset (jmp)"); - emit_data(disp, rspec, call32_operand); + emit_data(checked_cast(disp), rspec, call32_operand); } void Assembler::jmpb_0(Label& L, const char* file, int line) { @@ -6458,6 +6458,14 @@ void Assembler::xorw(Register dst, Register src) { emit_arith(0x33, 0xC0, dst, src); } +void Assembler::xorw(Register dst, Address src) { + InstructionMark im(this); + emit_int8(0x66); + prefix(src, dst); + emit_int8(0x33); + emit_operand(dst, src, 0); +} + // AVX 3-operands scalar float-point arithmetic instructions void Assembler::vaddsd(XMMRegister dst, XMMRegister nds, Address src) { @@ -13342,17 +13350,6 @@ void Assembler::movsbq(Register dst, Register src) { emit_int24(0x0F, (unsigned char)0xBE, (0xC0 | encode)); } -void Assembler::movslq(Register dst, int32_t imm32) { - // dbx shows movslq(rcx, 3) as movq $0x0000000049000000,(%rbx) - // and movslq(r8, 3); as movl $0x0000000048000000,(%rbx) - // as a result we shouldn't use until tested at runtime... - ShouldNotReachHere(); - InstructionMark im(this); - int encode = prefixq_and_encode(dst->encoding()); - emit_int8(0xC7 | encode); - emit_int32(imm32); -} - void Assembler::movslq(Address dst, int32_t imm32) { assert(is_simm32(imm32), "lost bits"); InstructionMark im(this); diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index ff0fee0f5de..491bf5e21dc 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -238,7 +238,7 @@ class Address { _index(index.register_or_noreg()), _xmmindex(xnoreg), _scale(scale), - _disp (disp + (index.constant_or_zero() * scale_size(scale))), + _disp (disp + checked_cast(index.constant_or_zero() * scale_size(scale))), _isxmmindex(false){ if (!index.is_register()) scale = Address::no_scale; assert(!_index->is_valid() == (scale == Address::no_scale), @@ -276,7 +276,7 @@ class Address { } Address plus_disp(RegisterOrConstant disp, ScaleFactor scale = times_1) const { Address a = (*this); - a._disp += disp.constant_or_zero() * scale_size(scale); + a._disp += checked_cast(disp.constant_or_zero() * scale_size(scale)); if (disp.is_register()) { assert(!a.index()->is_valid(), "competing indexes"); a._index = disp.as_register(); @@ -1644,7 +1644,6 @@ class Assembler : public AbstractAssembler { // Move signed 32bit immediate to 64bit extending sign void movslq(Address dst, int32_t imm64); - void movslq(Register dst, int32_t imm64); void movslq(Register dst, Address src); void movslq(Register dst, Register src); @@ -2229,6 +2228,7 @@ class Assembler : public AbstractAssembler { void xorb(Address dst, Register src); void xorb(Register dst, Address src); void xorw(Register dst, Register src); + void xorw(Register dst, Address src); void xorq(Register dst, Address src); void xorq(Address dst, int32_t imm32); diff --git a/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp b/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp index 1078e1dca67..08b1b285651 100644 --- a/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp +++ b/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp @@ -214,7 +214,7 @@ template frame ThawBase::new_stack_frame(const frame& hf, frame& intptr_t* heap_sp = hf.unextended_sp(); // If caller is interpreted it already made room for the callee arguments int overlap = caller.is_interpreted_frame() ? ContinuationHelper::InterpretedFrame::stack_argsize(hf) : 0; - const int fsize = ContinuationHelper::InterpretedFrame::frame_bottom(hf) - hf.unextended_sp() - overlap; + const int fsize = (int)(ContinuationHelper::InterpretedFrame::frame_bottom(hf) - hf.unextended_sp() - overlap); const int locals = hf.interpreter_frame_method()->max_locals(); intptr_t* frame_sp = caller.unextended_sp() - fsize; intptr_t* fp = frame_sp + (hf.fp() - heap_sp); diff --git a/src/hotspot/cpu/x86/frame_x86.inline.hpp b/src/hotspot/cpu/x86/frame_x86.inline.hpp index 6c1fd90ca58..fbe7f7ebb29 100644 --- a/src/hotspot/cpu/x86/frame_x86.inline.hpp +++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp @@ -222,13 +222,13 @@ inline intptr_t* frame::real_fp() const { inline int frame::frame_size() const { return is_interpreted_frame() - ? sender_sp() - sp() + ? pointer_delta_as_int(sender_sp(), sp()) : cb()->frame_size(); } inline int frame::compiled_frame_stack_argsize() const { assert(cb()->is_compiled(), ""); - return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; + return (cb()->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; } inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const { diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index c7843fad296..84504f47939 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1337,7 +1337,12 @@ void MacroAssembler::call(AddressLiteral entry, Register rscratch) { void MacroAssembler::ic_call(address entry, jint method_index) { RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); +#ifdef _LP64 + // Needs full 64-bit immediate for later patching. + mov64(rax, (intptr_t)Universe::non_oop_word()); +#else movptr(rax, (intptr_t)Universe::non_oop_word()); +#endif call(AddressLiteral(entry, rh)); } @@ -2035,10 +2040,10 @@ void MacroAssembler::post_call_nop() { InstructionMark im(this); relocate(post_call_nop_Relocation::spec()); InlineSkippedInstructionsCounter skipCounter(this); - emit_int8((int8_t)0x0f); - emit_int8((int8_t)0x1f); - emit_int8((int8_t)0x84); - emit_int8((int8_t)0x00); + emit_int8((uint8_t)0x0f); + emit_int8((uint8_t)0x1f); + emit_int8((uint8_t)0x84); + emit_int8((uint8_t)0x00); emit_int32(0x00); } @@ -2047,11 +2052,11 @@ void MacroAssembler::fat_nop() { if (UseAddressNop) { addr_nop_5(); } else { - emit_int8((int8_t)0x26); // es: - emit_int8((int8_t)0x2e); // cs: - emit_int8((int8_t)0x64); // fs: - emit_int8((int8_t)0x65); // gs: - emit_int8((int8_t)0x90); + emit_int8((uint8_t)0x26); // es: + emit_int8((uint8_t)0x2e); // cs: + emit_int8((uint8_t)0x64); // fs: + emit_int8((uint8_t)0x65); // gs: + emit_int8((uint8_t)0x90); } } @@ -2574,7 +2579,15 @@ void MacroAssembler::movptr(Register dst, Address src) { // src should NEVER be a real pointer. Use AddressLiteral for true pointers void MacroAssembler::movptr(Register dst, intptr_t src) { - LP64_ONLY(mov64(dst, src)) NOT_LP64(movl(dst, src)); +#ifdef _LP64 + if (is_simm32(src)) { + movq(dst, checked_cast(src)); + } else { + mov64(dst, src); + } +#else + movl(dst, src); +#endif } void MacroAssembler::movptr(Address dst, Register src) { diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 4799d584206..e5a4ee6df76 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -117,13 +117,13 @@ class MacroAssembler: public Assembler { if (op == 0xEB || (op & 0xF0) == 0x70) { // short offset operators (jmp and jcc) char* disp = (char*) &branch[1]; - int imm8 = target - (address) &disp[1]; + int imm8 = checked_cast(target - (address) &disp[1]); guarantee(this->is8bit(imm8), "Short forward jump exceeds 8-bit offset at %s:%d", file == nullptr ? "" : file, line); - *disp = imm8; + *disp = (char)imm8; } else { int* disp = (int*) &branch[(op == 0x0F || op == 0xC7)? 2: 1]; - int imm32 = target - (address) &disp[1]; + int imm32 = checked_cast(target - (address) &disp[1]); *disp = imm32; } } @@ -760,7 +760,7 @@ class MacroAssembler: public Assembler { void addptr(Register dst, int32_t src); void addptr(Register dst, Register src); void addptr(Register dst, RegisterOrConstant src) { - if (src.is_constant()) addptr(dst, src.as_constant()); + if (src.is_constant()) addptr(dst, checked_cast(src.as_constant())); else addptr(dst, src.as_register()); } diff --git a/src/hotspot/cpu/x86/nativeInst_x86.hpp b/src/hotspot/cpu/x86/nativeInst_x86.hpp index d8a2faa44f3..938a10cb63d 100644 --- a/src/hotspot/cpu/x86/nativeInst_x86.hpp +++ b/src/hotspot/cpu/x86/nativeInst_x86.hpp @@ -171,7 +171,7 @@ class NativeCall: public NativeInstruction { intptr_t disp = dest - return_address(); guarantee(disp == (intptr_t)(jint)disp, "must be 32-bit offset"); #endif // AMD64 - set_int_at(displacement_offset, dest - return_address()); + set_int_at(displacement_offset, (int)(dest - return_address())); } // Returns whether the 4-byte displacement operand is 4-byte aligned. bool is_displacement_aligned(); diff --git a/src/hotspot/cpu/x86/register_x86.hpp b/src/hotspot/cpu/x86/register_x86.hpp index 6ec00c8ce74..8c7b1d92c08 100644 --- a/src/hotspot/cpu/x86/register_x86.hpp +++ b/src/hotspot/cpu/x86/register_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ class Register { public: // accessors - constexpr int raw_encoding() const { return this - first(); } + constexpr int raw_encoding() const { return checked_cast(this - first()); } constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } bool has_byte_register() const { return 0 <= raw_encoding() && raw_encoding() < number_of_byte_registers; } @@ -139,7 +139,7 @@ class FloatRegister { public: // accessors - int raw_encoding() const { return this - first(); } + int raw_encoding() const { return checked_cast(this - first()); } int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } @@ -202,7 +202,7 @@ class XMMRegister { public: // accessors - constexpr int raw_encoding() const { return this - first(); } + constexpr int raw_encoding() const { return checked_cast(this - first()); } constexpr int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } constexpr bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } @@ -313,7 +313,7 @@ class KRegister { public: // accessors - int raw_encoding() const { return this - first(); } + int raw_encoding() const { return checked_cast(this - first()); } int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); } bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; } diff --git a/src/hotspot/cpu/x86/relocInfo_x86.cpp b/src/hotspot/cpu/x86/relocInfo_x86.cpp index b382b02902f..648c4d4b5e7 100644 --- a/src/hotspot/cpu/x86/relocInfo_x86.cpp +++ b/src/hotspot/cpu/x86/relocInfo_x86.cpp @@ -97,7 +97,11 @@ address Relocation::pd_call_destination(address orig_addr) { if (ni->is_call()) { return nativeCall_at(addr())->destination() + adj; } else if (ni->is_jump()) { - return nativeJump_at(addr())->jump_destination() + adj; + address dest = nativeJump_at(addr())->jump_destination(); + if (dest == (address) -1) { + return addr(); // jump to self + } + return dest + adj; } else if (ni->is_cond_jump()) { return nativeGeneralJump_at(addr())->jump_destination() + adj; } else if (ni->is_mov_literal64()) { diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp index 8bca9e865ed..d4fe079f8e1 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp @@ -26,6 +26,7 @@ #include "asm/macroAssembler.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/sharedRuntime.hpp" +#include "utilities/globalDefinitions.hpp" #include "vmreg_x86.inline.hpp" #ifdef COMPILER1 #include "c1/c1_Runtime1.hpp" @@ -59,9 +60,16 @@ void SharedRuntime::inline_check_hashcode_from_object_header(MacroAssembler* mas __ movptr(result, Address(obj_reg, oopDesc::mark_offset_in_bytes())); - // check if locked - __ testptr(result, markWord::unlocked_value); - __ jcc(Assembler::zero, slowCase); + + if (LockingMode == LM_LIGHTWEIGHT) { + // check if monitor + __ testptr(result, markWord::monitor_value); + __ jcc(Assembler::notZero, slowCase); + } else { + // check if locked + __ testptr(result, markWord::unlocked_value); + __ jcc(Assembler::zero, slowCase); + } // get hash #ifdef _LP64 diff --git a/src/hotspot/cpu/x86/smallRegisterMap_x86.inline.hpp b/src/hotspot/cpu/x86/smallRegisterMap_x86.inline.hpp index 5f21939a3aa..63212a686af 100644 --- a/src/hotspot/cpu/x86/smallRegisterMap_x86.inline.hpp +++ b/src/hotspot/cpu/x86/smallRegisterMap_x86.inline.hpp @@ -30,8 +30,16 @@ // Java frames don't have callee saved registers (except for rbp), so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } + private: static void assert_is_rbp(VMReg r) NOT_DEBUG_RETURN DEBUG_ONLY({ assert(r == rbp->as_VMReg() || r == rbp->as_VMReg()->next(), "Reg: %s", r->name()); }) @@ -48,17 +56,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { - #ifdef ASSERT - for(int i = 0; i < RegisterMap::reg_count; i++) { - VMReg r = VMRegImpl::as_VMReg(i); - if (map->location(r, (intptr_t*)nullptr) != nullptr) assert_is_rbp(r); - } - #endif - } - inline address location(VMReg reg, intptr_t* sp) const { assert_is_rbp(reg); return (address)(sp - frame::sender_sp_offset); diff --git a/src/hotspot/cpu/x86/stackChunkFrameStream_x86.inline.hpp b/src/hotspot/cpu/x86/stackChunkFrameStream_x86.inline.hpp index 6240de27b6b..47f451d2895 100644 --- a/src/hotspot/cpu/x86/stackChunkFrameStream_x86.inline.hpp +++ b/src/hotspot/cpu/x86/stackChunkFrameStream_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ template inline bool StackChunkFrameStream::is_in_frame(void* p0) const { assert(!is_done(), ""); intptr_t* p = (intptr_t*)p0; - int argsize = is_compiled() ? (_cb->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; + int argsize = is_compiled() ? (_cb->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; int frame_size = _cb->frame_size() + argsize; return p == sp() - frame::sender_sp_offset || ((p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size); } @@ -114,8 +114,8 @@ inline int StackChunkFrameStream::interpreter_frame_num_oops() const f.interpreted_frame_oop_map(&mask); return mask.num_oops() + 1 // for the mirror oop - + ((intptr_t*)f.interpreter_frame_monitor_begin() - - (intptr_t*)f.interpreter_frame_monitor_end())/BasicObjectLock::size(); + + pointer_delta_as_int((intptr_t*)f.interpreter_frame_monitor_begin(), + (intptr_t*)f.interpreter_frame_monitor_end())/BasicObjectLock::size(); } template<> diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index 7b1fb54853e..accddcd943f 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -2073,6 +2073,7 @@ void StubGenerator::aesctr_encrypt(Register src_addr, Register dest_addr, Regist const Register rounds = rax; const Register pos = r12; + const Register tail = r15; Label PRELOOP_START, EXIT_PRELOOP, REMAINDER, REMAINDER_16, LOOP, END, EXIT, END_LOOP, AES192, AES256, AES192_REMAINDER16, REMAINDER16_END_LOOP, AES256_REMAINDER16, @@ -2503,29 +2504,36 @@ void StubGenerator::aesctr_encrypt(Register src_addr, Register dest_addr, Regist // Save encrypted counter value in xmm0 for next invocation, before XOR operation __ movdqu(Address(saved_encCounter_start, 0), xmm0); // XOR encryted block cipher in xmm0 with PT to produce CT - __ evpxorq(xmm0, xmm0, Address(src_addr, pos, Address::times_1, 0), Assembler::AVX_128bit); // extract up to 15 bytes of CT from xmm0 as specified by length register __ testptr(len_reg, 8); __ jcc(Assembler::zero, EXTRACT_TAIL_4BYTES); - __ pextrq(Address(dest_addr, pos), xmm0, 0); + __ pextrq(tail, xmm0, 0); + __ xorq(tail, Address(src_addr, pos, Address::times_1, 0)); + __ movq(Address(dest_addr, pos), tail); __ psrldq(xmm0, 8); __ addl(pos, 8); __ bind(EXTRACT_TAIL_4BYTES); __ testptr(len_reg, 4); __ jcc(Assembler::zero, EXTRACT_TAIL_2BYTES); - __ pextrd(Address(dest_addr, pos), xmm0, 0); + __ pextrd(tail, xmm0, 0); + __ xorl(tail, Address(src_addr, pos, Address::times_1, 0)); + __ movl(Address(dest_addr, pos), tail); __ psrldq(xmm0, 4); __ addq(pos, 4); __ bind(EXTRACT_TAIL_2BYTES); __ testptr(len_reg, 2); __ jcc(Assembler::zero, EXTRACT_TAIL_1BYTE); - __ pextrw(Address(dest_addr, pos), xmm0, 0); + __ pextrw(tail, xmm0, 0); + __ xorw(tail, Address(src_addr, pos, Address::times_1, 0)); + __ movw(Address(dest_addr, pos), tail); __ psrldq(xmm0, 2); __ addl(pos, 2); __ bind(EXTRACT_TAIL_1BYTE); __ testptr(len_reg, 1); __ jcc(Assembler::zero, END); - __ pextrb(Address(dest_addr, pos), xmm0, 0); + __ pextrb(tail, xmm0, 0); + __ xorb(tail, Address(src_addr, pos, Address::times_1, 0)); + __ movb(Address(dest_addr, pos), tail); __ addl(pos, 1); __ bind(END); diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 1f9238c60cb..b7f5a2bc912 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -3145,8 +3145,8 @@ uint VM_Version::threads_per_core() { return (result == 0 ? 1 : result); } -intx VM_Version::L1_line_size() { - intx result = 0; +uint VM_Version::L1_line_size() { + uint result = 0; if (is_intel()) { result = (_cpuid_info.dcp_cpuid4_ebx.bits.L1_line_size + 1); } else if (is_amd_family()) { diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index 3074621229a..cb9e806999b 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -633,9 +633,9 @@ class VM_Version : public Abstract_VM_Version { static uint cores_per_cpu(); static uint threads_per_core(); - static intx L1_line_size(); + static uint L1_line_size(); - static intx prefetch_data_size() { + static uint prefetch_data_size() { return L1_line_size(); } diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 1a37e3124d5..3581cfb5e85 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -7016,11 +7016,10 @@ instruct vxor_mem(vec dst, vec src, memory mem) %{ // --------------------------------- VectorCast -------------------------------------- instruct vcastBtoX(vec dst, vec src) %{ + predicate(VM_Version::supports_avx512vl() || Matcher::vector_element_basic_type(n) != T_DOUBLE); match(Set dst (VectorCastB2X src)); format %{ "vector_cast_b2x $dst,$src\t!" %} ins_encode %{ - assert(UseAVX > 0, "required"); - BasicType to_elem_bt = Matcher::vector_element_basic_type(this); int vlen_enc = vector_length_encoding(this); __ vconvert_b2x(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); @@ -7028,6 +7027,17 @@ instruct vcastBtoX(vec dst, vec src) %{ ins_pipe( pipe_slow ); %} +instruct vcastBtoD(legVec dst, legVec src) %{ + predicate(!VM_Version::supports_avx512vl() && Matcher::vector_element_basic_type(n) == T_DOUBLE); + match(Set dst (VectorCastB2X src)); + format %{ "vector_cast_b2x $dst,$src\t!" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + __ vconvert_b2x(T_DOUBLE, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + instruct castStoX(vec dst, vec src) %{ predicate((UseAVX <= 2 || !VM_Version::supports_avx512vlbw()) && Matcher::vector_length(n->in(1)) <= 8 && // src diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad index baa81934012..bf79d165800 100644 --- a/src/hotspot/cpu/x86/x86_32.ad +++ b/src/hotspot/cpu/x86/x86_32.ad @@ -13707,6 +13707,8 @@ instruct Ret() %{ // Also known as an 'interprocedural jump'. // Target of jump will eventually return to caller. // TailJump below removes the return address. +// Don't use ebp for 'jump_target' because a MachEpilogNode has already been +// emitted just above the TailCall which has reset ebp to the caller state. instruct TailCalljmpInd(eRegP_no_EBP jump_target, eBXRegP method_ptr) %{ match(TailCall jump_target method_ptr); ins_cost(300); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index cbbd7c62c32..ada87b2f7fd 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -13472,6 +13472,8 @@ instruct Ret() // Also known as an 'interprocedural jump'. // Target of jump will eventually return to caller. // TailJump below removes the return address. +// Don't use rbp for 'jump_target' because a MachEpilogNode has already been +// emitted just above the TailCall which has reset rbp to the caller state. instruct TailCalljmpInd(no_rbp_RegP jump_target, rbx_RegP method_ptr) %{ match(TailCall jump_target method_ptr); diff --git a/src/hotspot/cpu/zero/smallRegisterMap_zero.inline.hpp b/src/hotspot/cpu/zero/smallRegisterMap_zero.inline.hpp index b85ead32fd2..51fb114f595 100644 --- a/src/hotspot/cpu/zero/smallRegisterMap_zero.inline.hpp +++ b/src/hotspot/cpu/zero/smallRegisterMap_zero.inline.hpp @@ -30,8 +30,15 @@ // Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } private: static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN DEBUG_ONLY({ Unimplemented(); }) @@ -46,12 +53,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { - Unimplemented(); - } - inline address location(VMReg reg, intptr_t* sp) const { Unimplemented(); return nullptr; diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index ac9b4541db3..0ecff8b28a6 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1871,6 +1871,10 @@ void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) { } +size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) { + return page_size; +} + void os::numa_make_global(char *addr, size_t bytes) { } @@ -3006,4 +3010,3 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {} void os::jfr_report_memory_info() {} #endif // INCLUDE_JFR - diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 0a786ddf35c..2aa5815a9b2 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1573,6 +1573,10 @@ void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) { ::madvise(addr, bytes, MADV_DONTNEED); } +size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) { + return page_size; +} + void os::numa_make_global(char *addr, size_t bytes) { } @@ -1979,16 +1983,25 @@ jint os::init_2(void) { if (status != 0) { log_info(os)("os::init_2 getrlimit failed: %s", os::strerror(errno)); } else { - nbr_files.rlim_cur = nbr_files.rlim_max; - -#ifdef __APPLE__ - // Darwin returns RLIM_INFINITY for rlim_max, but fails with EINVAL if - // you attempt to use RLIM_INFINITY. As per setrlimit(2), OPEN_MAX must - // be used instead - nbr_files.rlim_cur = MIN(OPEN_MAX, nbr_files.rlim_cur); -#endif + rlim_t rlim_original = nbr_files.rlim_cur; + + // On macOS according to setrlimit(2), OPEN_MAX must be used instead + // of RLIM_INFINITY, but testing on macOS >= 10.6, reveals that + // we can, in fact, use even RLIM_INFINITY, so try the max value + // that the system claims can be used first, same as other BSD OSes. + // However, some terminals (ksh) will internally use "int" type + // to store this value and since RLIM_INFINITY overflows an "int" + // we might end up with a negative value, so cap the system limit max + // at INT_MAX instead, just in case, for everyone. + nbr_files.rlim_cur = MIN(INT_MAX, nbr_files.rlim_max); status = setrlimit(RLIMIT_NOFILE, &nbr_files); + if (status != 0) { + // If that fails then try lowering the limit to either OPEN_MAX + // (which is safe) or the original limit, whichever was greater. + nbr_files.rlim_cur = MAX(OPEN_MAX, rlim_original); + status = setrlimit(RLIMIT_NOFILE, &nbr_files); + } if (status != 0) { log_info(os)("os::init_2 setrlimit failed: %s", os::strerror(errno)); } diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index 038593a2bc4..6c5470445f1 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -132,7 +132,7 @@ template int subsystem_file_line_contents(CgroupController* c, } else { // File consists of multiple lines in a "key value" // fashion, we have to find the key. - const int key_len = strlen(key); + const int key_len = (int)strlen(key); for (; line != nullptr; line = fgets(buf, buf_len, fp)) { char* key_substr = strstr(line, key); char after_key = line[key_len]; diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index f0cbc9780b2..70768b44751 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -98,7 +98,9 @@ develop(bool, DelayThreadStartALot, false, \ "Artificially delay thread starts randomly for testing.") \ \ - + product(bool, UseMadvPopulateWrite, true, DIAGNOSTIC, \ + "Use MADV_POPULATE_WRITE in os::pd_pretouch_memory.") \ + \ // end of RUNTIME_OS_FLAGS diff --git a/src/hotspot/os/linux/hugepages.cpp b/src/hotspot/os/linux/hugepages.cpp index f9f9dd497c7..715bfc165c4 100644 --- a/src/hotspot/os/linux/hugepages.cpp +++ b/src/hotspot/os/linux/hugepages.cpp @@ -230,6 +230,19 @@ void THPSupport::print_on(outputStream* os) { StaticHugePageSupport HugePages::_static_hugepage_support; THPSupport HugePages::_thp_support; +size_t HugePages::thp_pagesize_fallback() { + // Older kernels won't publish the THP page size. Fall back to default static huge page size, + // since that is likely to be the THP page size as well. Don't do it if the page size is considered + // too large to avoid large alignment waste. If static huge page size is unknown, use educated guess. + if (thp_pagesize() != 0) { + return thp_pagesize(); + } + if (supports_static_hugepages()) { + return MIN2(default_static_hugepage_size(), 16 * M); + } + return 2 * M; +} + void HugePages::initialize() { _static_hugepage_support.scan_os(); _thp_support.scan_os(); diff --git a/src/hotspot/os/linux/hugepages.hpp b/src/hotspot/os/linux/hugepages.hpp index cb7c992d789..5d196504c1c 100644 --- a/src/hotspot/os/linux/hugepages.hpp +++ b/src/hotspot/os/linux/hugepages.hpp @@ -107,6 +107,7 @@ class HugePages : public AllStatic { static THPMode thp_mode() { return _thp_support.mode(); } static bool supports_thp() { return thp_mode() == THPMode::madvise || thp_mode() == THPMode::always; } static size_t thp_pagesize() { return _thp_support.pagesize(); } + static size_t thp_pagesize_fallback(); static void initialize(); static void print_on(outputStream* os); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 492300a37d4..7cb862d7c3e 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2830,6 +2830,25 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, #define MADV_HUGEPAGE 14 #endif +// Define MADV_POPULATE_WRITE here so we can build HotSpot on old systems. +#define MADV_POPULATE_WRITE_value 23 +#ifndef MADV_POPULATE_WRITE + #define MADV_POPULATE_WRITE MADV_POPULATE_WRITE_value +#else + // Sanity-check our assumed default value if we build with a new enough libc. + STATIC_ASSERT(MADV_POPULATE_WRITE == MADV_POPULATE_WRITE_value); +#endif + +// Note that the value for MAP_FIXED_NOREPLACE differs between architectures, but all architectures +// supported by OpenJDK share the same flag value. +#define MAP_FIXED_NOREPLACE_value 0x100000 +#ifndef MAP_FIXED_NOREPLACE + #define MAP_FIXED_NOREPLACE MAP_FIXED_NOREPLACE_value +#else + // Sanity-check our assumed default value if we build with a new enough libc. + STATIC_ASSERT(MAP_FIXED_NOREPLACE == MAP_FIXED_NOREPLACE_value); +#endif + int os::Linux::commit_memory_impl(char* addr, size_t size, size_t alignment_hint, bool exec) { int err = os::Linux::commit_memory_impl(addr, size, exec); @@ -2875,6 +2894,31 @@ void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) { } } +size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) { + const size_t len = pointer_delta(last, first, sizeof(char)) + page_size; + // Use madvise to pretouch on Linux when THP is used, and fallback to the + // common method if unsupported. THP can form right after madvise rather than + // being assembled later. + if (HugePages::thp_mode() == THPMode::always || UseTransparentHugePages) { + int err = 0; + if (UseMadvPopulateWrite && + ::madvise(first, len, MADV_POPULATE_WRITE) == -1) { + err = errno; + } + if (!UseMadvPopulateWrite || err == EINVAL) { // Not to use or not supported + // When using THP we need to always pre-touch using small pages as the + // OS will initially always use small pages. + return os::vm_page_size(); + } else if (err != 0) { + log_info(gc, os)("::madvise(" PTR_FORMAT ", " SIZE_FORMAT ", %d) failed; " + "error='%s' (errno=%d)", p2i(first), len, + MADV_POPULATE_WRITE, os::strerror(err), err); + } + return 0; + } + return page_size; +} + void os::numa_make_global(char *addr, size_t bytes) { Linux::numa_interleave_memory(addr, bytes); } @@ -3836,8 +3880,12 @@ void os::large_page_init() { // In THP mode: // - os::large_page_size() is the *THP page size* // - os::pagesizes() has two members, the THP page size and the system page size - assert(HugePages::supports_thp() && HugePages::thp_pagesize() > 0, "Missing OS info"); _large_page_size = HugePages::thp_pagesize(); + if (_large_page_size == 0) { + log_info(pagesize) ("Cannot determine THP page size (kernel < 4.10 ?)"); + _large_page_size = HugePages::thp_pagesize_fallback(); + log_info(pagesize) ("Assuming THP page size to be: " EXACTFMT " (heuristics)", EXACTFMTARGS(_large_page_size)); + } _page_sizes.add(_large_page_size); _page_sizes.add(os::vm_page_size()); @@ -4441,6 +4489,9 @@ void os::init(void) { check_pax(); + // Check the availability of MADV_POPULATE_WRITE. + FLAG_SET_DEFAULT(UseMadvPopulateWrite, (::madvise(0, 0, MADV_POPULATE_WRITE) == 0)); + os::Posix::init(); } diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp index ff416d47eb0..25600c36bd4 100644 --- a/src/hotspot/os/linux/os_perf_linux.cpp +++ b/src/hotspot/os/linux/os_perf_linux.cpp @@ -847,7 +847,7 @@ SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() { bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() { _dir = os::opendir("/proc"); _entry = nullptr; - _valid = true; + _valid = _dir != nullptr; // May be null if /proc is not accessible. next_process(); return true; diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 3359bd0c63e..7afacbe8d24 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3785,6 +3785,11 @@ bool os::unguard_memory(char* addr, size_t bytes) { void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { } void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) { } + +size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) { + return page_size; +} + void os::numa_make_global(char *addr, size_t bytes) { } void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } bool os::numa_topology_changed() { return false; } diff --git a/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp b/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp index 4d07bbef303..cfe98118b13 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp +++ b/src/hotspot/os_cpu/bsd_aarch64/pauth_bsd_aarch64.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Arm Limited. All rights reserved. + * Copyright (c) 2021, 2023, Arm Limited. All rights reserved. * 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,12 +33,12 @@ inline address pauth_strip_pointer(address ptr) { return ptr; } -inline address pauth_sign_return_address(address ret_addr, address sp) { +inline address pauth_sign_return_address(address ret_addr) { // No PAC support in BSD as of yet. return ret_addr; } -inline address pauth_authenticate_return_address(address ret_addr, address sp) { +inline address pauth_authenticate_return_address(address ret_addr) { // No PAC support in BSD as of yet. return ret_addr; } diff --git a/src/hotspot/os_cpu/linux_aarch64/pauth_linux_aarch64.inline.hpp b/src/hotspot/os_cpu/linux_aarch64/pauth_linux_aarch64.inline.hpp index 1eb1b92b936..0244a579595 100644 --- a/src/hotspot/os_cpu/linux_aarch64/pauth_linux_aarch64.inline.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/pauth_linux_aarch64.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Arm Limited. All rights reserved. + * Copyright (c) 2021, 2023, Arm Limited. All rights reserved. * 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,15 +30,14 @@ inline bool pauth_ptr_is_raw(address ptr); -// Use only the PAC instructions in the NOP space. This ensures the binaries work on systems -// without PAC. Write these instructions using their alternate "hint" instructions to ensure older -// compilers can still be used. -#define XPACLRI "hint #0x7;" -#define PACIA1716 "hint #0x8;" -#define AUTIA1716 "hint #0xc;" +// Write these instructions using their alternate "hint" instructions to +// ensure older compilers can still be used. +#define XPACLRI "hint #0x7;" +#define PACIAZ "hint #0x18;" +#define AUTIAZ "hint #0x1c;" -// Strip an address. Use with caution - only if there is no guaranteed way of authenticating the -// value. +// Strip an address. Use with caution - +// only if there is no guaranteed way of authenticating the value. // inline address pauth_strip_pointer(address ptr) { register address result __asm__("x30") = ptr; @@ -46,36 +45,35 @@ inline address pauth_strip_pointer(address ptr) { return result; } -// Sign a return value, using the given modifier. +// Sign a return value, using value zero as the modifier. // -inline address pauth_sign_return_address(address ret_addr, address sp) { +inline address pauth_sign_return_address(address ret_addr) { if (VM_Version::use_rop_protection()) { // A pointer cannot be double signed. guarantee(pauth_ptr_is_raw(ret_addr), "Return address is already signed"); - register address r17 __asm("r17") = ret_addr; - register address r16 __asm("r16") = sp; - asm (PACIA1716 : "+r"(r17) : "r"(r16)); - ret_addr = r17; + register address reg30 __asm__("x30") = ret_addr; + asm (PACIAZ : "+r"(reg30)); + ret_addr = reg30; } return ret_addr; } -// Authenticate a return value, using the given modifier. +// Authenticate a return value, using value zero as the modifier. // -inline address pauth_authenticate_return_address(address ret_addr, address sp) { +inline address pauth_authenticate_return_address(address ret_addr) { if (VM_Version::use_rop_protection()) { - register address r17 __asm("r17") = ret_addr; - register address r16 __asm("r16") = sp; - asm (AUTIA1716 : "+r"(r17) : "r"(r16)); - ret_addr = r17; + register address reg30 __asm__("x30") = ret_addr; + asm (AUTIAZ : "+r"(reg30)); + ret_addr = reg30; // Ensure that the pointer authenticated. - guarantee(pauth_ptr_is_raw(ret_addr), "Return address did not authenticate"); + guarantee(pauth_ptr_is_raw(ret_addr), + "Return address did not authenticate"); } return ret_addr; } #undef XPACLRI -#undef PACIA1716 -#undef AUTIA1716 +#undef PACIAZ +#undef AUTIAZ #endif // OS_CPU_LINUX_AARCH64_PAUTH_LINUX_AARCH64_INLINE_HPP 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 7b4381cb590..c44d7bc05e9 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 @@ -131,7 +131,10 @@ void VM_Version::setup_cpu_available_features() { if (_feature_list[i]->feature_string()) { const char* tmp = _feature_list[i]->pretty(); if (strlen(tmp) == 1) { - strcat(buf, " "); + // Feature string is expected to be in multi-character form + // like rvc, rvv, etc so that it will be easier to specify + // target feature string in tests. + strcat(buf, " rv"); strcat(buf, tmp); } else { // Feature string is expected to be lower case. diff --git a/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp b/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp index 6b5c9eecb72..dff45632243 100644 --- a/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/pauth_windows_aarch64.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Arm Limited. All rights reserved. + * Copyright (c) 2021, 2023, Arm Limited. All rights reserved. * 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,12 +33,12 @@ inline address pauth_strip_pointer(address ptr) { return ptr; } -inline address pauth_sign_return_address(address ret_addr, address sp) { +inline address pauth_sign_return_address(address ret_addr) { // No PAC support in windows as of yet. return ret_addr; } -inline address pauth_authenticate_return_address(address ret_addr, address sp) { +inline address pauth_authenticate_return_address(address ret_addr) { // No PAC support in windows as of yet. return ret_addr; } diff --git a/src/hotspot/share/asm/assembler.cpp b/src/hotspot/share/asm/assembler.cpp index c5e3a143327..4c7715e975c 100644 --- a/src/hotspot/share/asm/assembler.cpp +++ b/src/hotspot/share/asm/assembler.cpp @@ -86,7 +86,7 @@ address AbstractAssembler::start_a_const(int required_space, int required_align) CodeSection* cs = cb->consts(); assert(_code_section == cb->insts() || _code_section == cb->stubs(), "not in insts/stubs?"); address end = cs->end(); - int pad = -(intptr_t)end & (required_align-1); + int pad = checked_cast(-(intptr_t)end & (required_align-1)); if (cs->maybe_expand_to_ensure_remaining(pad + required_space)) { if (cb->blob() == nullptr) return nullptr; end = cs->end(); // refresh pointer diff --git a/src/hotspot/share/asm/assembler.hpp b/src/hotspot/share/asm/assembler.hpp index 1d1578c2818..add473999ea 100644 --- a/src/hotspot/share/asm/assembler.hpp +++ b/src/hotspot/share/asm/assembler.hpp @@ -252,7 +252,7 @@ class AbstractAssembler : public ResourceObj { InlineSkippedInstructionsCounter(AbstractAssembler* assm) : _assm(assm), _start(assm->pc()) { } ~InlineSkippedInstructionsCounter() { - _assm->register_skipped(_assm->pc() - _start); + _assm->register_skipped(checked_cast(_assm->pc() - _start)); } }; diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index ab8aed1cb66..daecba17a68 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -524,7 +524,7 @@ void CodeBuffer::finalize_oop_references(const methodHandle& mh) { for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) { // pull code out of each section CodeSection* cs = code_section(n); - if (cs->is_empty() || !cs->has_locs()) continue; // skip trivial section + if (cs->is_empty() || (cs->locs_count() == 0)) continue; // skip trivial section RelocIterator iter(cs); while (iter.next()) { if (iter.type() == relocInfo::metadata_type) { @@ -790,10 +790,8 @@ void CodeBuffer::relocate_code_to(CodeBuffer* dest) const { // call) is relocated. Stubs are placed behind the main code // section, so that section has to be copied before relocating. for (int n = (int) SECT_FIRST; n < (int)SECT_LIMIT; n++) { - // pull code out of each section - const CodeSection* cs = code_section(n); - if (cs->is_empty() || !cs->has_locs()) continue; // skip trivial section CodeSection* dest_cs = dest->code_section(n); + if (dest_cs->is_empty() || (dest_cs->locs_count() == 0)) continue; // skip trivial section { // Repair the pc relative information in the code after the move RelocIterator iter(dest_cs); while (iter.next()) { @@ -1054,7 +1052,7 @@ void CodeSection::print(const char* name) { name, p2i(start()), p2i(end()), p2i(limit()), size(), capacity()); tty->print_cr(" %7s.locs = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d) point=%d", name, p2i(locs_start()), p2i(locs_end()), p2i(locs_limit()), locs_size, locs_capacity(), locs_point_off()); - if (PrintRelocations) { + if (PrintRelocations && (locs_size != 0)) { RelocIterator iter(this); iter.print(); } diff --git a/src/hotspot/share/c1/c1_CodeStubs.hpp b/src/hotspot/share/c1/c1_CodeStubs.hpp index 3c5f5937560..4c30b93e3aa 100644 --- a/src/hotspot/share/c1/c1_CodeStubs.hpp +++ b/src/hotspot/share/c1/c1_CodeStubs.hpp @@ -443,7 +443,7 @@ class PatchingStub: public CodeStub { _info = info; _obj = obj; masm->bind(_patch_site_continuation); - _bytes_to_copy = masm->pc() - pc_start(); + _bytes_to_copy = pointer_delta_as_int(masm->pc(), pc_start()); if (_id == PatchingStub::access_field_id) { // embed a fixed offset to handle long patches which need to be offset by a word. // the patching code will just add the field offset field to this offset so diff --git a/src/hotspot/share/c1/c1_Instruction.hpp b/src/hotspot/share/c1/c1_Instruction.hpp index f4794297da8..363f4f6e561 100644 --- a/src/hotspot/share/c1/c1_Instruction.hpp +++ b/src/hotspot/share/c1/c1_Instruction.hpp @@ -325,9 +325,9 @@ class Instruction: public CompilationResourceObj { void set_arg_needs_null_check(int i, bool check) { if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { if (check) { - _nonnull_state |= nth_bit(i); + _nonnull_state |= (int)nth_bit(i); } else { - _nonnull_state &= ~(nth_bit(i)); + _nonnull_state &= (int)~(nth_bit(i)); } } } diff --git a/src/hotspot/share/cds/archiveHeapLoader.cpp b/src/hotspot/share/cds/archiveHeapLoader.cpp index 28d2718b75a..2d39ccef7e2 100644 --- a/src/hotspot/share/cds/archiveHeapLoader.cpp +++ b/src/hotspot/share/cds/archiveHeapLoader.cpp @@ -33,6 +33,7 @@ #include "memory/iterator.inline.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" +#include "sanitizers/ub.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/copy.hpp" @@ -59,6 +60,7 @@ ptrdiff_t ArchiveHeapLoader::_mapped_heap_delta = 0; // Every mapped region is offset by _mapped_heap_delta from its requested address. // See FileMapInfo::heap_region_requested_address(). +ATTRIBUTE_NO_UBSAN void ArchiveHeapLoader::init_mapped_heap_relocation(ptrdiff_t delta, int dumptime_oop_shift) { assert(!_mapped_heap_relocation_initialized, "only once"); if (!UseCompressedOops) { diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp index 84fdabf7665..47d289787e2 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.cpp +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp @@ -436,10 +436,8 @@ void ArchiveHeapWriter::update_header_for_requested_obj(oop requested_obj, oop s } // We need to retain the identity_hash, because it may have been used by some hashtables - // in the shared heap. This also has the side effect of pre-initializing the - // identity_hash for all shared objects, so they are less likely to be written - // into during run time, increasing the potential of memory sharing. - if (src_obj != nullptr) { + // in the shared heap. + if (src_obj != nullptr && !src_obj->fast_no_hash_check()) { int src_hash = src_obj->identity_hash(); if (UseCompactObjectHeaders) { fake_oop->set_mark(markWord::prototype().set_narrow_klass(nk).copy_set_hash(src_hash)); diff --git a/src/hotspot/share/cds/archiveHeapWriter.hpp b/src/hotspot/share/cds/archiveHeapWriter.hpp index 6001012ba85..c5fa71fc0b4 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.hpp +++ b/src/hotspot/share/cds/archiveHeapWriter.hpp @@ -115,7 +115,7 @@ class ArchiveHeapWriter : AllStatic { // Both Java bytearray and GrowableArraty use int indices and lengths. Do a safe typecast with range check static int to_array_index(size_t i) { assert(i <= (size_t)max_jint, "must be"); - return (size_t)i; + return (int)i; } static int to_array_length(size_t n) { return to_array_index(n); diff --git a/src/hotspot/share/cds/cdsHeapVerifier.cpp b/src/hotspot/share/cds/cdsHeapVerifier.cpp index b687ad566b3..767454260d2 100644 --- a/src/hotspot/share/cds/cdsHeapVerifier.cpp +++ b/src/hotspot/share/cds/cdsHeapVerifier.cpp @@ -129,7 +129,23 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0) // This just points to an empty Map ADD_EXCL("jdk/internal/reflect/Reflection", "methodFilterMap"); // E ADD_EXCL("jdk/internal/util/StaticProperty", "FILE_ENCODING", // C - "JAVA_LOCALE_USE_OLD_ISO_CODES"); // C + "JAVA_LOCALE_USE_OLD_ISO_CODES", // C + "USER_LANGUAGE", // C + "USER_LANGUAGE_DISPLAY", // C + "USER_LANGUAGE_FORMAT", // C + "USER_SCRIPT", // C + "USER_SCRIPT_DISPLAY", // C + "USER_SCRIPT_FORMAT", // C + "USER_COUNTRY", // C + "USER_COUNTRY_DISPLAY", // C + "USER_COUNTRY_FORMAT", // C + "USER_VARIANT", // C + "USER_VARIANT_DISPLAY", // C + "USER_VARIANT_FORMAT", // C + "USER_EXTENSIONS", // C + "USER_EXTENSIONS_DISPLAY", // C + "USER_EXTENSIONS_FORMAT", // C + "USER_REGION"); // C // Integer for 0 and 1 are in java/lang/Integer$IntegerCache and are archived ADD_EXCL("sun/invoke/util/ValueConversions", "ONE_INT", // E diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp index 94ec7cd9f19..6586a586e82 100644 --- a/src/hotspot/share/cds/cppVtables.cpp +++ b/src/hotspot/share/cds/cppVtables.cpp @@ -65,19 +65,17 @@ class CppVtableInfo { intptr_t _vtable_size; - intptr_t _cloned_vtable[1]; + intptr_t _cloned_vtable[1]; // Pseudo flexible array member. + static size_t cloned_vtable_offset() { return offset_of(CppVtableInfo, _cloned_vtable); } public: - static int num_slots(int vtable_size) { - return 1 + vtable_size; // Need to add the space occupied by _vtable_size; - } int vtable_size() { return int(uintx(_vtable_size)); } void set_vtable_size(int n) { _vtable_size = intptr_t(n); } - intptr_t* cloned_vtable() { return &_cloned_vtable[0]; } - void zero() { memset(_cloned_vtable, 0, sizeof(intptr_t) * vtable_size()); } + // Using _cloned_vtable[i] for i > 0 causes undefined behavior. We use address calculation instead. + intptr_t* cloned_vtable() { return (intptr_t*)((char*)this + cloned_vtable_offset()); } + void zero() { memset(cloned_vtable(), 0, sizeof(intptr_t) * vtable_size()); } // Returns the address of the next CppVtableInfo that can be placed immediately after this CppVtableInfo static size_t byte_size(int vtable_size) { - CppVtableInfo i; - return pointer_delta(&i._cloned_vtable[vtable_size], &i, sizeof(u1)); + return cloned_vtable_offset() + (sizeof(intptr_t) * vtable_size); } }; diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 9f618f9d245..f44b2e512ae 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -276,12 +276,6 @@ bool HeapShared::archive_object(oop obj) { } else { count_allocation(obj->size()); ArchiveHeapWriter::add_source_obj(obj); - - // The archived objects are discovered in a predictable order. Compute - // their identity_hash() as soon as we see them. This ensures that the - // the identity_hash in the object header will have a predictable value, - // making the archive reproducible. - obj->identity_hash(); CachedOopInfo info = make_cached_oop_info(); archived_object_cache()->put(obj, info); mark_native_pointers(obj); diff --git a/src/hotspot/share/ci/ciMethodData.hpp b/src/hotspot/share/ci/ciMethodData.hpp index 9c6c877da67..005fa214647 100644 --- a/src/hotspot/share/ci/ciMethodData.hpp +++ b/src/hotspot/share/ci/ciMethodData.hpp @@ -501,7 +501,7 @@ class ciMethodData : public ciMetadata { // Convert a dp (data pointer) to a di (data index). int dp_to_di(address dp) { - return dp - ((address)_data); + return pointer_delta_as_int(dp, ((address)_data)); } // Get the data at an arbitrary (sort of) data index. diff --git a/src/hotspot/share/ci/ciStreams.hpp b/src/hotspot/share/ci/ciStreams.hpp index 7dae21a0290..110002b3b43 100644 --- a/src/hotspot/share/ci/ciStreams.hpp +++ b/src/hotspot/share/ci/ciStreams.hpp @@ -110,9 +110,9 @@ class ciBytecodeStream : StackObj { } address cur_bcp() const { return _bc_start; } // Returns bcp to current instruction - int next_bci() const { return _pc - _start; } - int cur_bci() const { return _bc_start - _start; } - int instruction_size() const { return _pc - _bc_start; } + int next_bci() const { return pointer_delta_as_int(_pc, _start); } + int cur_bci() const { return pointer_delta_as_int(_bc_start, _start); } + int instruction_size() const { return pointer_delta_as_int(_pc, _bc_start); } Bytecodes::Code cur_bc() const{ return check_java(_bc); } Bytecodes::Code cur_bc_raw() const { return check_defined(_raw_bc); } diff --git a/src/hotspot/share/classfile/classFileStream.hpp b/src/hotspot/share/classfile/classFileStream.hpp index 55bcf082940..b84956983b9 100644 --- a/src/hotspot/share/classfile/classFileStream.hpp +++ b/src/hotspot/share/classfile/classFileStream.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ class ClassFileStream: public ResourceObj { // Buffer access const u1* buffer() const { return _buffer_start; } - int length() const { return _buffer_end - _buffer_start; } + int length() const { return pointer_delta_as_int(_buffer_end, _buffer_start); } const u1* current() const { return _current; } void set_current(const u1* pos) const { assert(pos >= _buffer_start && pos <= _buffer_end, "invariant"); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 24ea8ab77f8..54e8f0d8112 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -787,6 +787,7 @@ int java_lang_Class::_class_loader_offset; int java_lang_Class::_module_offset; int java_lang_Class::_protection_domain_offset; int java_lang_Class::_component_mirror_offset; +int java_lang_Class::_init_lock_offset; int java_lang_Class::_signers_offset; int java_lang_Class::_name_offset; int java_lang_Class::_source_file_offset; @@ -912,6 +913,12 @@ void java_lang_Class::initialize_mirror_fields(Klass* k, Handle protection_domain, Handle classData, TRAPS) { + // Allocate a simple java object for a lock. + // This needs to be a java object because during class initialization + // it can be held across a java call. + typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK); + set_init_lock(mirror(), r); + // Set protection domain also set_protection_domain(mirror(), protection_domain()); @@ -1133,6 +1140,10 @@ bool java_lang_Class::restore_archived_mirror(Klass *k, if (!k->is_array_klass()) { // - local static final fields with initial values were initialized at dump time + // create the init_lock + typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK_(false)); + set_init_lock(mirror(), r); + if (protection_domain.not_null()) { set_protection_domain(mirror(), protection_domain()); } @@ -1197,6 +1208,15 @@ oop java_lang_Class::component_mirror(oop java_class) { return java_class->obj_field(_component_mirror_offset); } +oop java_lang_Class::init_lock(oop java_class) { + assert(_init_lock_offset != 0, "must be set"); + return java_class->obj_field(_init_lock_offset); +} +void java_lang_Class::set_init_lock(oop java_class, oop init_lock) { + assert(_init_lock_offset != 0, "must be set"); + java_class->obj_field_put(_init_lock_offset, init_lock); +} + objArrayOop java_lang_Class::signers(oop java_class) { assert(_signers_offset != 0, "must be set"); return (objArrayOop)java_class->obj_field(_signers_offset); @@ -1415,7 +1435,6 @@ void java_lang_Class::compute_offsets() { InstanceKlass* k = vmClasses::Class_klass(); CLASS_FIELDS_DO(FIELD_COMPUTE_OFFSET); - CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index ab0b8f444b4..79f80dfe976 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,6 +208,7 @@ class java_lang_String : AllStatic { macro(java_lang_Class, protection_domain, object_signature, false) \ macro(java_lang_Class, signers, object_signature, false) \ macro(java_lang_Class, source_file, object_signature, false) \ + macro(java_lang_Class, init_lock, object_signature, false) class java_lang_Class : AllStatic { friend class VMStructs; @@ -224,6 +225,7 @@ class java_lang_Class : AllStatic { static int _static_oop_field_count_offset; static int _protection_domain_offset; + static int _init_lock_offset; static int _signers_offset; static int _class_loader_offset; static int _module_offset; @@ -238,6 +240,7 @@ class java_lang_Class : AllStatic { static GrowableArray* _fixup_mirror_list; static GrowableArray* _fixup_module_field_list; + static void set_init_lock(oop java_class, oop init_lock); static void set_protection_domain(oop java_class, oop protection_domain); static void set_class_loader(oop java_class, oop class_loader); static void set_component_mirror(oop java_class, oop comp_mirror); @@ -290,6 +293,10 @@ class java_lang_Class : AllStatic { // Support for embedded per-class oops static oop protection_domain(oop java_class); + static oop init_lock(oop java_class); + static void clear_init_lock(oop java_class) { + set_init_lock(java_class, nullptr); + } static oop component_mirror(oop java_class); static objArrayOop signers(oop java_class); static void set_signers(oop java_class, objArrayOop signers); diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 1677597e72b..d4cc1d9c570 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -427,7 +427,7 @@ template(yieldInfo_name, "yieldInfo") \ template(tail_name, "tail") \ template(size_name, "size") \ - template(argsize_name, "argsize") \ + template(bottom_name, "bottom") \ template(mode_name, "mode") \ template(numFrames_name, "numFrames") \ template(numOops_name, "numOops") \ diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index c1c34a06c75..e842bd88a4c 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -194,9 +194,9 @@ class CodeBlob { // Sizes int size() const { return _size; } int header_size() const { return _header_size; } - int relocation_size() const { return (address) relocation_end() - (address) relocation_begin(); } - int content_size() const { return content_end() - content_begin(); } - int code_size() const { return code_end() - code_begin(); } + int relocation_size() const { return pointer_delta_as_int((address) relocation_end(), (address) relocation_begin()); } + int content_size() const { return pointer_delta_as_int(content_end(), content_begin()); } + int code_size() const { return pointer_delta_as_int(code_end(), code_begin()); } // Only used from CodeCache::free_unused_tail() after the Interpreter blob was trimmed void adjust_size(size_t used) { _size = (int)used; diff --git a/src/hotspot/share/code/codeBlob.inline.hpp b/src/hotspot/share/code/codeBlob.inline.hpp index bd49fdba210..dbe55435970 100644 --- a/src/hotspot/share/code/codeBlob.inline.hpp +++ b/src/hotspot/share/code/codeBlob.inline.hpp @@ -33,7 +33,7 @@ inline const ImmutableOopMap* CodeBlob::oop_map_for_slot(int slot, address return_address) const { assert(_oop_maps != nullptr, "nope"); - return _oop_maps->find_map_at_slot(slot, (intptr_t) return_address - (intptr_t) code_begin()); + return _oop_maps->find_map_at_slot(slot, pointer_delta_as_int(return_address, code_begin())); } #endif // SHARE_CODE_CODEBLOB_INLINE_HPP diff --git a/src/hotspot/share/code/dependencies.hpp b/src/hotspot/share/code/dependencies.hpp index bdb7998fd8c..124db0b1369 100644 --- a/src/hotspot/share/code/dependencies.hpp +++ b/src/hotspot/share/code/dependencies.hpp @@ -666,7 +666,7 @@ class DependencySignature : public ResourceObj { } static bool equals(DependencySignature const& s1, DependencySignature const& s2); - static unsigned hash (DependencySignature const& s1) { return s1.arg(0) >> 2; } + static unsigned hash (DependencySignature const& s1) { return (unsigned)(s1.arg(0) >> 2); } int args_count() const { return _args_count; } uintptr_t arg(int idx) const { return _argument_hash[idx]; } diff --git a/src/hotspot/share/code/exceptionHandlerTable.hpp b/src/hotspot/share/code/exceptionHandlerTable.hpp index d30d602b33c..f1dcab657ff 100644 --- a/src/hotspot/share/code/exceptionHandlerTable.hpp +++ b/src/hotspot/share/code/exceptionHandlerTable.hpp @@ -172,7 +172,7 @@ class ImplicitExceptionTable { uint get_exec_offset(uint i) { assert(i < _len, "oob"); return *adr(i); } uint get_cont_offset(uint i) { assert(i < _len, "oob"); return *(adr(i) + 1); } - int size_in_bytes() const { return len() == 0 ? 0 : ((2 * len() + 1) * sizeof(implicit_null_entry)); } + int size_in_bytes() const { return len() == 0 ? 0 : ((2 * len() + 1) * (int)sizeof(implicit_null_entry)); } void copy_to(nmethod* nm); void copy_bytes_to(address addr, int size); diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index c07b5e28c17..500ddbc2fe4 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -656,6 +656,7 @@ nmethod::nmethod( init_defaults(); _comp_level = CompLevel_none; _entry_bci = InvocationEntryBci; + _num_stack_arg_slots = _method->constMethod()->num_stack_arg_slots(); // We have no exception handler or deopt handler make the // values something that will never match a pc like the nmethod vtable entry _exception_offset = 0; @@ -799,6 +800,7 @@ nmethod::nmethod( init_defaults(); _entry_bci = entry_bci; + _num_stack_arg_slots = entry_bci != InvocationEntryBci ? 0 : _method->constMethod()->num_stack_arg_slots(); _compile_id = compile_id; _comp_level = comp_level; _orig_pc_offset = orig_pc_offset; diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index f428aa4ef3d..03b8210c31c 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -229,6 +229,8 @@ class nmethod : public CompiledMethod { int _compile_id; // which compilation made this nmethod + int _num_stack_arg_slots; // Number of arguments passed on the stack + #if INCLUDE_RTM_OPT // RTM state at compile time. Used during deoptimization to decide // whether to restart collecting RTM locking abort statistic again. @@ -515,6 +517,10 @@ class nmethod : public CompiledMethod { nmethod* osr_link() const { return _osr_link; } void set_osr_link(nmethod *n) { _osr_link = n; } + int num_stack_arg_slots(bool rounded = true) const { + return rounded ? align_up(_num_stack_arg_slots, 2) : _num_stack_arg_slots; + } + // Verify calls to dead methods have been cleaned. void verify_clean_inline_caches(); diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 3394802f452..308ad10b2c4 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -149,8 +149,7 @@ void RelocIterator::initialize(CompiledMethod* nm, address begin, address limit) RelocIterator::RelocIterator(CodeSection* cs, address begin, address limit) { initialize_misc(); - assert((cs->locs_start() != nullptr) && (cs->locs_end() != nullptr) || - (cs->locs_start() == nullptr) && (cs->locs_end() == nullptr), "valid start and end pointer"); + assert(((cs->locs_start() != nullptr) && (cs->locs_end() != nullptr)), "valid start and end pointer"); _current = cs->locs_start()-1; _end = cs->locs_end(); _addr = cs->start(); @@ -397,6 +396,14 @@ void CallRelocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer } +#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; + pd_fix_owner_after_move(); +} +#endif + //// pack/unpack methods void oop_Relocation::pack_data_to(CodeSection* dest) { diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 2972f30ce56..d8825245e76 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -1287,6 +1287,11 @@ class runtime_call_w_cp_Relocation : public CallRelocation { // in the code, it can patch it to jump to the trampoline where is // sufficient space for a far branch. Needed on PPC. class trampoline_stub_Relocation : public Relocation { +#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER + void pd_fix_owner_after_move(); + void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; +#endif + public: static RelocationHolder spec(address static_call) { return RelocationHolder::construct(static_call); diff --git a/src/hotspot/share/code/vmreg.cpp b/src/hotspot/share/code/vmreg.cpp index 9b8e4ba599d..ba30c114c6c 100644 --- a/src/hotspot/share/code/vmreg.cpp +++ b/src/hotspot/share/code/vmreg.cpp @@ -30,7 +30,7 @@ // used by SA and jvmti, but it's a leaky abstraction: SA and jvmti // "know" that stack0 is an integer masquerading as a pointer. For the // sake of those clients, we preserve this interface. -VMReg VMRegImpl::stack0 = (VMReg)VMRegImpl::stack_0()->value(); +VMReg VMRegImpl::stack0 = (VMReg)(intptr_t)FIRST_STACK; // VMRegs are 4 bytes wide on all platforms const int VMRegImpl::stack_slot_size = 4; @@ -42,7 +42,7 @@ const char *VMRegImpl::regName[ConcreteRegisterImpl::number_of_registers]; void VMRegImpl::print_on(outputStream* st) const { if (is_reg()) { - assert(VMRegImpl::regName[value()], "VMRegImpl::regName[" INTPTR_FORMAT "] returns nullptr", value()); + assert(VMRegImpl::regName[value()], "VMRegImpl::regName[%d] returns nullptr", value()); st->print("%s",VMRegImpl::regName[value()]); } else if (is_stack()) { int stk = reg2stack(); diff --git a/src/hotspot/share/code/vmreg.hpp b/src/hotspot/share/code/vmreg.hpp index 59ac28c4cf8..1172dd65d98 100644 --- a/src/hotspot/share/code/vmreg.hpp +++ b/src/hotspot/share/code/vmreg.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. * 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,7 +53,8 @@ friend class OptoReg; // friend class Location; private: enum { - BAD_REG = -1 + BAD_REG = -1, + FIRST_STACK = (ConcreteRegisterImpl::number_of_registers + 7) & ~7 }; // Despite being private, this field is exported to the @@ -70,7 +71,7 @@ friend class OptoReg; public: static constexpr VMReg stack_0() { - return first() + ((ConcreteRegisterImpl::number_of_registers + 7) & ~7); + return first() + FIRST_STACK; } static VMReg as_VMReg(int val, bool bad_ok = false) { @@ -88,7 +89,7 @@ friend class OptoReg; return "STACKED REG"; } } - intptr_t value() const { return this - first(); } + int value() const { return checked_cast(this - first()); } static VMReg Bad() { return BAD_REG+first(); } bool is_valid() const { return value() != BAD_REG; } bool is_stack() const { return this >= stack_0(); } @@ -143,9 +144,9 @@ friend class OptoReg; return stack_0() + idx; } - uintptr_t reg2stack() const { + int reg2stack() const { assert(is_stack(), "Not a stack-based register"); - return this - stack_0(); + return checked_cast(this - stack_0()); } static void set_regName(); diff --git a/src/hotspot/share/code/vtableStubs.hpp b/src/hotspot/share/code/vtableStubs.hpp index 0a7308d9038..5a5f4aa32c7 100644 --- a/src/hotspot/share/code/vtableStubs.hpp +++ b/src/hotspot/share/code/vtableStubs.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "asm/macroAssembler.hpp" #include "code/vmreg.hpp" #include "memory/allStatic.hpp" +#include "sanitizers/ub.hpp" // A VtableStub holds an individual code stub for a pair (vtable index, #args) for either itables or vtables // There's a one-to-one relationship between a VtableStub and such a pair. @@ -131,7 +132,7 @@ class VtableStub { void* operator new(size_t size, int code_size) throw(); - VtableStub(bool is_vtable_stub, int index) + VtableStub(bool is_vtable_stub, short index) : _next(nullptr), _index(index), _ame_offset(-1), _npe_offset(-1), _is_vtable_stub(is_vtable_stub) {} VtableStub* next() const { return _next; } @@ -152,8 +153,8 @@ class VtableStub { private: void set_exception_points(address npe_addr, address ame_addr) { - _npe_offset = npe_addr - code_begin(); - _ame_offset = ame_addr - code_begin(); + _npe_offset = checked_cast(npe_addr - code_begin()); + _ame_offset = checked_cast(ame_addr - code_begin()); assert(is_abstract_method_error(ame_addr), "offset must be correct"); assert(is_null_pointer_exception(npe_addr), "offset must be correct"); assert(!is_abstract_method_error(npe_addr), "offset must be correct"); @@ -173,6 +174,9 @@ class VtableStub { public: // Query bool is_itable_stub() { return !_is_vtable_stub; } + // We reinterpret arbitrary memory as VtableStub. This does not cause failures because the lookup/equality + // check will reject false objects. Disabling UBSan is a temporary workaround until JDK-8331725 is fixed. + ATTRIBUTE_NO_UBSAN bool is_vtable_stub() { return _is_vtable_stub; } bool is_abstract_method_error(address epc) { return epc == code_begin()+_ame_offset; } bool is_null_pointer_exception(address epc) { return epc == code_begin()+_npe_offset; } diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 8cc58cd26d5..dfa2a9d01b4 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -1026,7 +1026,7 @@ CompLevel CompilationPolicy::common(const methodHandle& method, CompLevel cur_le if (force_comp_at_level_simple(method)) { next_level = CompLevel_simple; } else { - if (is_trivial(method)) { + if (is_trivial(method) || method->is_native()) { next_level = CompilationModeFlag::disable_intermediate() ? CompLevel_full_optimization : CompLevel_simple; } else { switch(cur_level) { diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 9cf5d2ab7bb..9c1bf5393ac 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -832,8 +832,15 @@ void DeoptimizeObjectsALotThread::deoptimize_objects_alot_loop_all() { JavaThread* CompileBroker::make_thread(ThreadType type, jobject thread_handle, CompileQueue* queue, AbstractCompiler* comp, JavaThread* THREAD) { - JavaThread* new_thread = nullptr; + Handle thread_oop(THREAD, JNIHandles::resolve_non_null(thread_handle)); + if (java_lang_Thread::thread(thread_oop()) != nullptr) { + assert(type == compiler_t, "should only happen with reused compiler threads"); + // The compiler thread hasn't actually exited yet so don't try to reuse it + return nullptr; + } + + JavaThread* new_thread = nullptr; switch (type) { case compiler_t: assert(comp != nullptr, "Compiler instance missing."); @@ -862,7 +869,6 @@ JavaThread* CompileBroker::make_thread(ThreadType type, jobject thread_handle, C // JavaThread due to lack of resources. We will handle that failure below. // Also check new_thread so that static analysis is happy. if (new_thread != nullptr && new_thread->osthread() != nullptr) { - Handle thread_oop(THREAD, JNIHandles::resolve_non_null(thread_handle)); if (type == compiler_t) { CompilerThread::cast(new_thread)->set_compiler(comp); diff --git a/src/hotspot/share/compiler/compileTask.cpp b/src/hotspot/share/compiler/compileTask.cpp index bb0826d9245..524f11b3d74 100644 --- a/src/hotspot/share/compiler/compileTask.cpp +++ b/src/hotspot/share/compiler/compileTask.cpp @@ -221,13 +221,13 @@ void CompileTask::print_impl(outputStream* st, Method* method, int compile_id, i jlong time_queued, jlong time_started) { if (!short_form) { // Print current time - st->print("%7d ", (int)tty->time_stamp().milliseconds()); + st->print(UINT64_FORMAT " ", (uint64_t) tty->time_stamp().milliseconds()); if (Verbose && time_queued != 0) { // Print time in queue and time being processed by compiler thread jlong now = os::elapsed_counter(); - st->print("%d ", (int)TimeHelper::counter_to_millis(now-time_queued)); + st->print("%.0f ", TimeHelper::counter_to_millis(now-time_queued)); if (time_started != 0) { - st->print("%d ", (int)TimeHelper::counter_to_millis(now-time_started)); + st->print("%.0f ", TimeHelper::counter_to_millis(now-time_started)); } } } diff --git a/src/hotspot/share/compiler/oopMap.cpp b/src/hotspot/share/compiler/oopMap.cpp index ede9f91025f..6ab8970a795 100644 --- a/src/hotspot/share/compiler/oopMap.cpp +++ b/src/hotspot/share/compiler/oopMap.cpp @@ -281,15 +281,15 @@ void OopMapSort::print() { OopMapValue omv = _values[i]; if (omv.type() == OopMapValue::oop_value || omv.type() == OopMapValue::narrowoop_value) { if (omv.reg()->is_reg()) { - tty->print_cr("[%c][%d] -> reg (" INTPTR_FORMAT ")", omv.type() == OopMapValue::narrowoop_value ? 'n' : 'o', i, omv.reg()->value()); + tty->print_cr("[%c][%d] -> reg (%d)", omv.type() == OopMapValue::narrowoop_value ? 'n' : 'o', i, omv.reg()->value()); } else { - tty->print_cr("[%c][%d] -> stack (" INTPTR_FORMAT ")", omv.type() == OopMapValue::narrowoop_value ? 'n' : 'o', i, omv.reg()->reg2stack() * VMRegImpl::stack_slot_size); + tty->print_cr("[%c][%d] -> stack (%d)", omv.type() == OopMapValue::narrowoop_value ? 'n' : 'o', i, omv.reg()->reg2stack() * VMRegImpl::stack_slot_size); } } else { if (omv.content_reg()->is_reg()) { - tty->print_cr("[d][%d] -> reg (" INTPTR_FORMAT ") stack (" INTPTR_FORMAT ")", i, omv.content_reg()->value(), omv.reg()->reg2stack() * VMRegImpl::stack_slot_size); + tty->print_cr("[d][%d] -> reg (%d) stack (%d)", i, omv.content_reg()->value(), omv.reg()->reg2stack() * VMRegImpl::stack_slot_size); } else if (omv.reg()->is_reg()) { - tty->print_cr("[d][%d] -> stack (" INTPTR_FORMAT ") reg (" INTPTR_FORMAT ")", i, omv.content_reg()->reg2stack() * VMRegImpl::stack_slot_size, omv.reg()->value()); + tty->print_cr("[d][%d] -> stack (%d) reg (%d)", i, omv.content_reg()->reg2stack() * VMRegImpl::stack_slot_size, omv.reg()->value()); } else { int derived_offset = omv.reg()->reg2stack() * VMRegImpl::stack_slot_size; int base_offset = omv.content_reg()->reg2stack() * VMRegImpl::stack_slot_size; diff --git a/src/hotspot/share/compiler/oopMap.hpp b/src/hotspot/share/compiler/oopMap.hpp index 146637f3654..e6d0274395a 100644 --- a/src/hotspot/share/compiler/oopMap.hpp +++ b/src/hotspot/share/compiler/oopMap.hpp @@ -54,9 +54,9 @@ enum class derived_pointer : intptr_t {}; class OopMapValue: public StackObj { friend class VMStructs; private: - short _value; - int value() const { return _value; } - void set_value(int value) { _value = value; } + unsigned short _value; + unsigned short value() const { return _value; } + void set_value(unsigned short value) { _value = value; } short _content_reg; public: @@ -88,8 +88,8 @@ class OopMapValue: public StackObj { } private: - void set_reg_type(VMReg p, oop_types t) { - set_value((p->value() << register_shift) | t); + void set_reg_type(VMReg p, oop_types t) { + set_value(checked_cast((p->value() << register_shift) | t)); assert(reg() == p, "sanity check" ); assert(type() == t, "sanity check" ); } @@ -103,7 +103,7 @@ class OopMapValue: public StackObj { } else { assert (!r->is_valid(), "valid VMReg not allowed"); } - _content_reg = r->value(); + _content_reg = checked_cast(r->value()); } public: @@ -111,12 +111,12 @@ class OopMapValue: public StackObj { void write_on(CompressedWriteStream* stream) { stream->write_int(value()); if(is_callee_saved() || is_derived_oop()) { - stream->write_int(content_reg()->value()); + stream->write_int(checked_cast(content_reg()->value())); } } void read_from(CompressedReadStream* stream) { - set_value(stream->read_int()); + set_value(checked_cast(stream->read_int())); if (is_callee_saved() || is_derived_oop()) { set_content_reg(VMRegImpl::as_VMReg(stream->read_int(), true)); } @@ -128,7 +128,7 @@ class OopMapValue: public StackObj { bool is_callee_saved() { return mask_bits(value(), type_mask_in_place) == callee_saved_value; } bool is_derived_oop() { return mask_bits(value(), type_mask_in_place) == derived_oop_value; } - VMReg reg() const { return VMRegImpl::as_VMReg(mask_bits(value(), register_mask_in_place) >> register_shift); } + VMReg reg() const { return VMRegImpl::as_VMReg(checked_cast(mask_bits(value(), register_mask_in_place) >> register_shift)); } oop_types type() const { return (oop_types)mask_bits(value(), type_mask_in_place); } static bool legal_vm_reg_name(VMReg p) { diff --git a/src/hotspot/share/compiler/oopMap.inline.hpp b/src/hotspot/share/compiler/oopMap.inline.hpp index c6531b1cd3a..f2a3b3ba834 100644 --- a/src/hotspot/share/compiler/oopMap.inline.hpp +++ b/src/hotspot/share/compiler/oopMap.inline.hpp @@ -113,7 +113,7 @@ void OopMapDo::iterate_oops_do(const frame if (reg_map->should_skip_missing()) continue; VMReg reg = omv.reg(); - tty->print_cr("missing saved register: reg: " INTPTR_FORMAT " %s loc: %p", reg->value(), reg->name(), loc); + tty->print_cr("missing saved register: reg: %d %s loc: %p", reg->value(), reg->name(), loc); fr->print_on(tty); } #endif diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index a8520d78a64..5b33e24de75 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -191,11 +191,14 @@ size_t G1Allocator::unsafe_max_tlab_alloc() { uint node_index = current_node_index(); HeapRegion* hr = mutator_alloc_region(node_index)->get(); size_t max_tlab = _g1h->max_tlab_size() * wordSize; - if (hr == nullptr) { + + if (hr == nullptr || hr->free() < MinTLABSize) { + // The next TLAB allocation will most probably happen in a new region, + // therefore we can attempt to allocate the maximum allowed TLAB size. return max_tlab; - } else { - return clamp(hr->free(), MinTLABSize, max_tlab); } + + return MIN2(hr->free(), max_tlab); } size_t G1Allocator::used_in_alloc_regions() { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 88463486adb..44e19ca6f5f 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2489,7 +2489,7 @@ void G1CollectedHeap::expand_heap_after_young_collection(){ bool G1CollectedHeap::do_collection_pause_at_safepoint() { assert_at_safepoint_on_vm_thread(); - guarantee(!is_gc_active(), "collection is not reentrant"); + guarantee(!is_stw_gc_active(), "collection is not reentrant"); if (GCLocker::check_active_before_gc()) { return false; @@ -2557,7 +2557,7 @@ void G1CollectedHeap::retire_tlabs() { void G1CollectedHeap::do_collection_pause_at_safepoint_helper() { ResourceMark rm; - IsGCActiveMark active_gc_mark; + IsSTWGCActiveMark active_gc_mark; GCIdMark gc_id_mark; SvcGCMarker sgcm(SvcGCMarker::MINOR); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 447535f2f86..88f4f680800 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -753,7 +753,7 @@ class G1CollectedHeap : public CollectedHeap { // false if unable to do the collection due to the GC locker being // active, true otherwise. // precondition: at safepoint on VM thread - // precondition: !is_gc_active() + // precondition: !is_stw_gc_active() bool do_collection_pause_at_safepoint(); // Helper for do_collection_pause_at_safepoint, containing the guts diff --git a/src/hotspot/share/gc/g1/g1EvacStats.cpp b/src/hotspot/share/gc/g1/g1EvacStats.cpp index 85ec939e79e..a426c4f9306 100644 --- a/src/hotspot/share/gc/g1/g1EvacStats.cpp +++ b/src/hotspot/share/gc/g1/g1EvacStats.cpp @@ -133,7 +133,9 @@ G1EvacStats::G1EvacStats(const char* description, size_t default_per_thread_plab // Calculates plab size for current number of gc worker threads. size_t G1EvacStats::desired_plab_size(uint no_of_gc_workers) const { if (!ResizePLAB) { - return _default_plab_size; + // There is a circular dependency between the heap and PLAB initialization, + // so _default_plab_size can have an unaligned value. + return align_object_size(_default_plab_size); } return align_object_size(clamp(_desired_net_plab_size / no_of_gc_workers, min_size(), max_size())); } diff --git a/src/hotspot/share/gc/g1/g1FullGCScope.hpp b/src/hotspot/share/gc/g1/g1FullGCScope.hpp index f3d89c7646f..ab3b99fea04 100644 --- a/src/hotspot/share/gc/g1/g1FullGCScope.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCScope.hpp @@ -52,7 +52,7 @@ class G1FullGCScope : public StackObj { SvcGCMarker _svc_marker; STWGCTimer _timer; G1FullGCTracer* _tracer; - IsGCActiveMark _active; + IsSTWGCActiveMark _active; G1FullGCJFRTracerMark _tracer_mark; ClearedAllSoftRefs _soft_refs; G1FullGCMonitoringScope _monitoring_scope; diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 8c5760f1b5f..fdeb06eb8c6 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1549,7 +1549,7 @@ bool G1RemSet::clean_card_before_refine(CardValue** const card_ptr_addr) { void G1RemSet::refine_card_concurrently(CardValue* const card_ptr, const uint worker_id) { - assert(!_g1h->is_gc_active(), "Only call concurrently"); + assert(!_g1h->is_stw_gc_active(), "Only call concurrently"); check_card_ptr(card_ptr, _ct); // Construct the MemRegion representing the card. diff --git a/src/hotspot/share/gc/g1/g1VMOperations.cpp b/src/hotspot/share/gc/g1/g1VMOperations.cpp index c19c399cfb6..bdee54c8ac3 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.cpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.cpp @@ -168,7 +168,7 @@ void VM_G1PauseConcurrent::doit() { G1ConcGCMonitoringScope monitoring_scope(g1h->monitoring_support()); SvcGCMarker sgcm(SvcGCMarker::CONCURRENT); - IsGCActiveMark x; + IsSTWGCActiveMark x; work(); } diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 40488093f7d..d344742256a 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -455,7 +455,7 @@ void ParallelScavengeHeap::do_full_collection(bool clear_all_soft_refs) { HeapWord* ParallelScavengeHeap::failed_mem_allocate(size_t size) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - assert(!is_gc_active(), "not reentrant"); + assert(!is_stw_gc_active(), "not reentrant"); assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); // We assume that allocation in eden will fail unless we collect. diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 741d415fe91..de3f5b581aa 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -1688,9 +1688,9 @@ bool PSParallelCompact::invoke(bool maximum_heap_compaction) { "should be in vm thread"); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - assert(!heap->is_gc_active(), "not reentrant"); + assert(!heap->is_stw_gc_active(), "not reentrant"); - IsGCActiveMark mark; + IsSTWGCActiveMark mark; if (ScavengeBeforeFullGC) { PSScavenge::invoke_no_policy(); @@ -1921,7 +1921,7 @@ class PCAddThreadRootsMarkingTaskClosure : public ThreadClosure { public: PCAddThreadRootsMarkingTaskClosure(uint worker_id) : _worker_id(worker_id) { } void do_thread(Thread* thread) { - assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_stw_gc_active(), "called outside gc"); ResourceMark rm; @@ -1938,7 +1938,7 @@ class PCAddThreadRootsMarkingTaskClosure : public ThreadClosure { }; void steal_marking_work(TaskTerminator& terminator, uint worker_id) { - assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_stw_gc_active(), "called outside gc"); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); @@ -2401,7 +2401,7 @@ void PSParallelCompact::write_block_fill_histogram() #endif // #ifdef ASSERT static void compaction_with_stealing_work(TaskTerminator* terminator, uint worker_id) { - assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_stw_gc_active(), "called outside gc"); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 7da789261c0..bcea2c80e25 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -84,7 +84,7 @@ ParallelScavengeTracer PSScavenge::_gc_tracer; CollectorCounters* PSScavenge::_counters = nullptr; static void scavenge_roots_work(ParallelRootType::Value root_type, uint worker_id) { - assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_stw_gc_active(), "called outside gc"); PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(worker_id); PSPromoteRootsClosure roots_to_old_closure(pm); @@ -115,7 +115,7 @@ static void scavenge_roots_work(ParallelRootType::Value root_type, uint worker_i } static void steal_work(TaskTerminator& terminator, uint worker_id) { - assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_stw_gc_active(), "called outside gc"); PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(worker_id); @@ -232,11 +232,11 @@ class ParallelScavengeRefProcProxyTask : public RefProcProxyTask { bool PSScavenge::invoke() { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); - assert(!ParallelScavengeHeap::heap()->is_gc_active(), "not reentrant"); + assert(!ParallelScavengeHeap::heap()->is_stw_gc_active(), "not reentrant"); ParallelScavengeHeap* const heap = ParallelScavengeHeap::heap(); PSAdaptiveSizePolicy* policy = heap->size_policy(); - IsGCActiveMark mark; + IsSTWGCActiveMark mark; const bool scavenge_done = PSScavenge::invoke_no_policy(); const bool need_full_gc = !scavenge_done; @@ -264,7 +264,7 @@ class PSThreadRootsTaskClosure : public ThreadClosure { public: PSThreadRootsTaskClosure(uint worker_id) : _worker_id(worker_id) { } virtual void do_thread(Thread* thread) { - assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); + assert(ParallelScavengeHeap::heap()->is_stw_gc_active(), "called outside gc"); PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(_worker_id); PSScavengeRootsClosure roots_closure(pm); diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index 569c06201d8..b4fe30d1007 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -243,7 +243,7 @@ bool CollectedHeap::is_oop(oop object) const { CollectedHeap::CollectedHeap() : _capacity_at_last_gc(0), _used_at_last_gc(0), - _is_gc_active(false), + _is_stw_gc_active(false), _last_whole_heap_examined_time_ns(os::javaTimeNanos()), _total_collections(0), _total_full_collections(0), diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index bba2b84e2bc..88f1da4349f 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -94,8 +94,7 @@ class ParallelObjectIterator : public StackObj { class CollectedHeap : public CHeapObj { friend class VMStructs; friend class JVMCIVMStructs; - friend class IsGCActiveMark; // Block structured external access to _is_gc_active - friend class DisableIsGCActiveMark; // Disable current IsGCActiveMark + friend class IsSTWGCActiveMark; // Block structured external access to _is_stw_gc_active friend class MemAllocator; friend class ParallelObjectIterator; @@ -114,7 +113,7 @@ class CollectedHeap : public CHeapObj { // Not used by all GCs MemRegion _reserved; - bool _is_gc_active; + bool _is_stw_gc_active; // (Minimum) Alignment reserve for TLABs and PLABs. static size_t _lab_alignment_reserve; @@ -382,10 +381,8 @@ class CollectedHeap : public CHeapObj { // allocated object. virtual bool requires_barriers(stackChunkOop obj) const = 0; - // Returns "true" iff there is a stop-world GC in progress. (I assume - // that it should answer "false" for the concurrent part of a concurrent - // collector -- dld). - bool is_gc_active() const { return _is_gc_active; } + // Returns "true" iff there is a stop-world GC in progress. + bool is_stw_gc_active() const { return _is_stw_gc_active; } // Total number of GC collections (started) unsigned int total_collections() const { return _total_collections; } diff --git a/src/hotspot/share/gc/shared/gcOverheadChecker.cpp b/src/hotspot/share/gc/shared/gcOverheadChecker.cpp index d72d1f1e59f..84ecf6d9d68 100644 --- a/src/hotspot/share/gc/shared/gcOverheadChecker.cpp +++ b/src/hotspot/share/gc/shared/gcOverheadChecker.cpp @@ -41,7 +41,11 @@ void GCOverheadChecker::check_gc_overhead_limit(GCOverheadTester* time_overhead, bool is_full_gc, GCCause::Cause gc_cause, SoftRefPolicy* soft_ref_policy) { - + if (is_full_gc) { + // Explicit Full GC would do the clearing of soft-refs as well + // So reset in the beginning + soft_ref_policy->set_should_clear_all_soft_refs(false); + } // Ignore explicit GC's. Exiting here does not set the flag and // does not reset the count. if (GCCause::is_user_requested_gc(gc_cause) || diff --git a/src/hotspot/share/gc/shared/gcVMOperations.cpp b/src/hotspot/share/gc/shared/gcVMOperations.cpp index 80358f38e2d..4a87e1432e1 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.cpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.cpp @@ -130,9 +130,9 @@ bool VM_GC_Operation::doit_prologue() { void VM_GC_Operation::doit_epilogue() { - // Clean up old interpreter OopMap entries that were replaced - // during the GC thread root traversal. - OopMapCache::cleanup_old_entries(); + // GC thread root traversal likely used OopMapCache a lot, which + // might have created lots of old entries. Trigger the cleanup now. + OopMapCache::try_trigger_cleanup(); if (Universe::has_reference_pending_list()) { Heap_lock->notify_all(); } diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp index 7e625b9cd39..ead8111bff0 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp @@ -460,7 +460,7 @@ void GenCollectedHeap::do_collection(bool full, assert(my_thread->is_VM_thread(), "only VM thread"); assert(Heap_lock->is_locked(), "the requesting thread should have the Heap_lock"); - guarantee(!is_gc_active(), "collection is not reentrant"); + guarantee(!is_stw_gc_active(), "collection is not reentrant"); if (GCLocker::check_active_before_gc()) { return; // GC is disabled (e.g. JNI GetXXXCritical operation) @@ -471,7 +471,7 @@ void GenCollectedHeap::do_collection(bool full, ClearedAllSoftRefs casr(do_clear_all_soft_refs, soft_ref_policy()); - AutoModifyRestore temporarily(_is_gc_active, true); + AutoModifyRestore temporarily(_is_stw_gc_active, true); bool complete = full && (max_generation == OldGen); bool old_collects_young = complete && !ScavengeBeforeFullGC; diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.hpp b/src/hotspot/share/gc/shared/genCollectedHeap.hpp index 271703b6dc0..41cd2078f23 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.hpp @@ -270,7 +270,7 @@ class GenCollectedHeap : public CollectedHeap { _old_gen->update_gc_stats(current_generation, full); } - bool no_gc_in_progress() { return !is_gc_active(); } + bool no_gc_in_progress() { return !is_stw_gc_active(); } void prepare_for_verify() override; void verify(VerifyOption option) override; diff --git a/src/hotspot/share/gc/shared/isGCActiveMark.cpp b/src/hotspot/share/gc/shared/isGCActiveMark.cpp index c797ff43e5a..7c400f2acc0 100644 --- a/src/hotspot/share/gc/shared/isGCActiveMark.cpp +++ b/src/hotspot/share/gc/shared/isGCActiveMark.cpp @@ -29,28 +29,16 @@ #include "utilities/debug.hpp" // This class provides a method for block structured setting of the -// _is_gc_active state without requiring accessors in CollectedHeap +// _is_stw_gc_active state without requiring accessors in CollectedHeap -IsGCActiveMark::IsGCActiveMark() { +IsSTWGCActiveMark::IsSTWGCActiveMark() { CollectedHeap* heap = Universe::heap(); - assert(!heap->is_gc_active(), "Not reentrant"); - heap->_is_gc_active = true; + assert(!heap->is_stw_gc_active(), "Not reentrant"); + heap->_is_stw_gc_active = true; } -IsGCActiveMark::~IsGCActiveMark() { +IsSTWGCActiveMark::~IsSTWGCActiveMark() { CollectedHeap* heap = Universe::heap(); - assert(heap->is_gc_active(), "Sanity"); - heap->_is_gc_active = false; -} - -DisableIsGCActiveMark::DisableIsGCActiveMark() { - CollectedHeap* heap = Universe::heap(); - assert(heap->is_gc_active(), "Not reentrant"); - heap->_is_gc_active = false; -} - -DisableIsGCActiveMark::~DisableIsGCActiveMark() { - CollectedHeap* heap = Universe::heap(); - assert(!heap->is_gc_active(), "Sanity"); - heap->_is_gc_active = true; + assert(heap->is_stw_gc_active(), "Sanity"); + heap->_is_stw_gc_active = false; } diff --git a/src/hotspot/share/gc/shared/isGCActiveMark.hpp b/src/hotspot/share/gc/shared/isGCActiveMark.hpp index c6d95d8a634..e523c600ace 100644 --- a/src/hotspot/share/gc/shared/isGCActiveMark.hpp +++ b/src/hotspot/share/gc/shared/isGCActiveMark.hpp @@ -28,18 +28,12 @@ #include "memory/allocation.hpp" // This class provides a method for block structured setting of the -// _is_gc_active state without requiring accessors in CollectedHeap +// _is_stw_gc_active state without requiring accessors in CollectedHeap -class IsGCActiveMark : public StackObj { +class IsSTWGCActiveMark : public StackObj { public: - IsGCActiveMark(); - ~IsGCActiveMark(); -}; - -class DisableIsGCActiveMark : public StackObj { - public: - DisableIsGCActiveMark(); - ~DisableIsGCActiveMark(); + IsSTWGCActiveMark(); + ~IsSTWGCActiveMark(); }; #endif // SHARE_GC_SHARED_ISGCACTIVEMARK_HPP diff --git a/src/hotspot/share/gc/shared/memAllocator.cpp b/src/hotspot/share/gc/shared/memAllocator.cpp index eb2d1a90b49..f56a2c8c6ea 100644 --- a/src/hotspot/share/gc/shared/memAllocator.cpp +++ b/src/hotspot/share/gc/shared/memAllocator.cpp @@ -145,7 +145,7 @@ void MemAllocator::Allocation::verify_before() { JavaThread* THREAD = _thread; // For exception macros. assert(!HAS_PENDING_EXCEPTION, "Should not allocate with exception pending"); debug_only(check_for_valid_allocation_state()); - assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed"); + assert(!Universe::heap()->is_stw_gc_active(), "Allocation during GC pause not allowed"); } #ifdef ASSERT @@ -314,18 +314,15 @@ HeapWord* MemAllocator::mem_allocate_inside_tlab_slow(Allocation& allocation) co PTR_FORMAT " min: " SIZE_FORMAT ", desired: " SIZE_FORMAT, p2i(mem), min_tlab_size, new_tlab_size); + // ...and clear or zap just allocated TLAB, if needed. if (ZeroTLAB) { - // ..and clear it. Copy::zero_to_words(mem, allocation._allocated_tlab_size); - } else { - // ...and zap just allocated object. -#ifdef ASSERT + } else if (ZapTLAB) { // Skip mangling the space corresponding to the object header to // ensure that the returned space is not considered parsable by // any concurrent GC thread. size_t hdr_size = oopDesc::header_size(); Copy::fill_to_words(mem + hdr_size, allocation._allocated_tlab_size - hdr_size, badHeapWordVal); -#endif // ASSERT } tlab.fill(mem, mem + _word_size, allocation._allocated_tlab_size); diff --git a/src/hotspot/share/gc/shared/plab.cpp b/src/hotspot/share/gc/shared/plab.cpp index e9b267879ae..ac2025e97a1 100644 --- a/src/hotspot/share/gc/shared/plab.cpp +++ b/src/hotspot/share/gc/shared/plab.cpp @@ -51,6 +51,13 @@ void PLAB::startup_initialization() { FLAG_SET_ERGO(OldPLABSize, MAX2(ThreadLocalAllocBuffer::min_size(), OldPLABSize)); } } + uint obj_alignment = checked_cast(ObjectAlignmentInBytes / HeapWordSize); + if (!is_aligned(YoungPLABSize, obj_alignment)) { + FLAG_SET_ERGO(YoungPLABSize, align_up(YoungPLABSize, obj_alignment)); + } + if (!is_aligned(OldPLABSize, obj_alignment)) { + FLAG_SET_ERGO(OldPLABSize, align_up(OldPLABSize, obj_alignment)); + } } PLAB::PLAB(size_t desired_plab_sz_) : diff --git a/src/hotspot/share/gc/shared/pretouchTask.cpp b/src/hotspot/share/gc/shared/pretouchTask.cpp index 1b9d527bb06..254b9152e02 100644 --- a/src/hotspot/share/gc/shared/pretouchTask.cpp +++ b/src/hotspot/share/gc/shared/pretouchTask.cpp @@ -68,12 +68,6 @@ void PretouchTask::pretouch(const char* task_name, char* start_address, char* en // Page-align the chunk size, so if start_address is also page-aligned (as // is common) then there won't be any pages shared by multiple chunks. size_t chunk_size = align_down_bounded(PretouchTask::chunk_size(), page_size); -#ifdef LINUX - // When using THP we need to always pre-touch using small pages as the OS will - // initially always use small pages. - page_size = UseTransparentHugePages ? (size_t)os::vm_page_size() : page_size; -#endif - PretouchTask task(task_name, start_address, end_address, page_size, chunk_size); size_t total_bytes = pointer_delta(end_address, start_address, sizeof(char)); diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp index 3988134a8e9..6910d9c1860 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,14 +39,8 @@ inline HeapWord* ThreadLocalAllocBuffer::allocate(size_t size) { invariants(); HeapWord* obj = top(); if (pointer_delta(end(), obj) >= size) { - // successful thread-local allocation -#ifdef ASSERT - // Skip mangling the space corresponding to the object header to - // ensure that the returned space is not considered parsable by - // any concurrent GC thread. - size_t hdr_size = oopDesc::header_size(); - Copy::fill_to_words(obj + hdr_size, size - hdr_size, badHeapWordVal); -#endif // ASSERT + // Successful thread-local allocation. + // This addition is safe because we know that top is // at least size below end, so the add can't wrap. set_top(obj + size); diff --git a/src/hotspot/share/gc/shared/vmStructs_gc.hpp b/src/hotspot/share/gc/shared/vmStructs_gc.hpp index acd153cd45d..be22e957efa 100644 --- a/src/hotspot/share/gc/shared/vmStructs_gc.hpp +++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp @@ -96,7 +96,7 @@ nonstatic_field(CardTableBarrierSet, _card_table, CardTable*) \ \ nonstatic_field(CollectedHeap, _reserved, MemRegion) \ - nonstatic_field(CollectedHeap, _is_gc_active, bool) \ + nonstatic_field(CollectedHeap, _is_stw_gc_active, bool) \ nonstatic_field(CollectedHeap, _total_collections, unsigned int) \ \ nonstatic_field(ContiguousSpace, _compaction_top, HeapWord*) \ diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index ac3afa774e1..8e956ad5dcd 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -1104,7 +1104,7 @@ Node* ShenandoahBarrierSetC2::ideal_node(PhaseGVN* phase, Node* n, bool can_resh return nullptr; } - return n->as_If()->dominated_by(prev_dom, phase->is_IterGVN()); + return n->as_If()->dominated_by(prev_dom, phase->is_IterGVN(), false); } return nullptr; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index a8f71c8c5df..4f46611c49c 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -243,7 +243,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { double avg_cycle_time = _gc_time_history->davg() + (_margin_of_error_sd * _gc_time_history->dsd()); double avg_alloc_rate = _allocation_rate.upper_bound(_margin_of_error_sd); - if (avg_cycle_time > allocation_headroom / avg_alloc_rate) { + if (avg_cycle_time * avg_alloc_rate > allocation_headroom) { log_info(gc)("Trigger: Average GC time (%.2f ms) is above the time for average allocation rate (%.0f %sB/s) to deplete free headroom (" SIZE_FORMAT "%s) (margin of error = %.2f)", avg_cycle_time * 1000, byte_size_in_proper_unit(avg_alloc_rate), proper_unit_for_byte_size(avg_alloc_rate), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetNMethod.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetNMethod.cpp index 20954156b9e..7b30e1ecbac 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetNMethod.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSetNMethod.cpp @@ -36,13 +36,19 @@ #include "runtime/threadWXSetters.inline.hpp" bool ShenandoahBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { + if (!is_armed(nm)) { + // Some other thread got here first and healed the oops + // and disarmed the nmethod. No need to continue. + return true; + } + ShenandoahReentrantLock* lock = ShenandoahNMethod::lock_for_nmethod(nm); assert(lock != nullptr, "Must be"); ShenandoahReentrantLocker locker(lock); if (!is_armed(nm)) { - // Some other thread got here first and healed the oops - // and disarmed the nmethod. + // Some other thread managed to complete while we were + // waiting for lock. No need to continue. return true; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp index c5b6d787b95..a9296a56a23 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2022, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -103,13 +104,6 @@ class ShenandoahDisarmNMethodsTask : public WorkerTask { WorkerTask("Shenandoah Disarm NMethods"), _iterator(ShenandoahCodeRoots::table()) { assert(SafepointSynchronize::is_at_safepoint(), "Only at a safepoint"); - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - _iterator.nmethods_do_begin(); - } - - ~ShenandoahDisarmNMethodsTask() { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - _iterator.nmethods_do_end(); } virtual void work(uint worker_id) { @@ -191,15 +185,7 @@ class ShenandoahUnlinkTask : public WorkerTask { WorkerTask("Shenandoah Unlink NMethods"), _cl(unloading_occurred), _verifier(verifier), - _iterator(ShenandoahCodeRoots::table()) { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - _iterator.nmethods_do_begin(); - } - - ~ShenandoahUnlinkTask() { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - _iterator.nmethods_do_end(); - } + _iterator(ShenandoahCodeRoots::table()) {} virtual void work(uint worker_id) { ICRefillVerifierMark mark(_verifier); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 7564af5f6b7..ec25cdf2a09 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2022, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -749,18 +750,9 @@ class ShenandoahConcurrentWeakRootsEvacUpdateTask : public WorkerTask { _vm_roots(phase), _cld_roots(phase, ShenandoahHeap::heap()->workers()->active_workers(), false /*heap iteration*/), _nmethod_itr(ShenandoahCodeRoots::table()), - _phase(phase) { - if (ShenandoahHeap::heap()->unload_classes()) { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - _nmethod_itr.nmethods_do_begin(); - } - } + _phase(phase) {} ~ShenandoahConcurrentWeakRootsEvacUpdateTask() { - if (ShenandoahHeap::heap()->unload_classes()) { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - _nmethod_itr.nmethods_do_end(); - } // Notify runtime data structures of potentially dead oops _vm_roots.report_num_dead(); } @@ -862,19 +854,7 @@ class ShenandoahConcurrentRootsEvacUpdateTask : public WorkerTask { _phase(phase), _vm_roots(phase), _cld_roots(phase, ShenandoahHeap::heap()->workers()->active_workers(), false /*heap iteration*/), - _nmethod_itr(ShenandoahCodeRoots::table()) { - if (!ShenandoahHeap::heap()->unload_classes()) { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - _nmethod_itr.nmethods_do_begin(); - } - } - - ~ShenandoahConcurrentRootsEvacUpdateTask() { - if (!ShenandoahHeap::heap()->unload_classes()) { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - _nmethod_itr.nmethods_do_end(); - } - } + _nmethod_itr(ShenandoahCodeRoots::table()) {} void work(uint worker_id) { ShenandoahConcurrentWorkerSession worker_session(worker_id); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 8074299c7b2..de4dfaea146 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -364,11 +364,13 @@ class ShenandoahPrepareForCompactionObjectClosure : public ObjectClosure { _compact_point = _to_region->bottom(); } - // Object fits into current region, record new location: + // Object fits into current region, record new location, if object does not move: assert(_compact_point + obj_size <= _to_region->end(), "must fit"); shenandoah_assert_not_forwarded(nullptr, p); - _preserved_marks->push_if_necessary(p, p->mark()); - SlidingForwarding::forward_to(p, cast_to_oop(_compact_point)); + if (_compact_point != cast_from_oop(p)) { + _preserved_marks->push_if_necessary(p, p->mark()); + SlidingForwarding::forward_to(p, cast_to_oop(_compact_point)); + } _compact_point += obj_size; } }; @@ -895,6 +897,7 @@ class ShenandoahCompactObjectsClosure : public ObjectClosure { if (SlidingForwarding::is_forwarded(p)) { HeapWord* compact_from = cast_from_oop(p); HeapWord* compact_to = cast_from_oop(SlidingForwarding::forwardee(p)); + assert(compact_from != compact_to, "Forwarded object should move"); Copy::aligned_conjoint_words(compact_from, compact_to, size); oop new_obj = cast_to_oop(compact_to); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index a835a20dc6d..5f3e0b5e41b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -780,18 +780,15 @@ HeapWord* ShenandoahHeap::allocate_from_gclab_slow(Thread* thread, size_t size) assert (size <= actual_size, "allocation should fit"); + // ...and clear or zap just allocated TLAB, if needed. if (ZeroTLAB) { - // ..and clear it. Copy::zero_to_words(gclab_buf, actual_size); - } else { - // ...and zap just allocated object. -#ifdef ASSERT + } else if (ZapTLAB) { // Skip mangling the space corresponding to the object header to // ensure that the returned space is not considered parsable by // any concurrent GC thread. size_t hdr_size = oopDesc::header_size(); Copy::fill_to_words(gclab_buf + hdr_size, actual_size - hdr_size, badHeapWordVal); -#endif // ASSERT } gclab->set_buf(gclab_buf, actual_size); return gclab->allocate(size); @@ -888,7 +885,11 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) { } HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req, bool& in_new_region) { - ShenandoahHeapLocker locker(lock()); + // If we are dealing with mutator allocation, then we may need to block for safepoint. + // We cannot block for safepoint for GC allocations, because there is a high chance + // we are already running at safepoint or from stack watermark machinery, and we cannot + // block again. + ShenandoahHeapLocker locker(lock(), req.is_mutator_alloc()); return _free_set->allocate(req, in_new_region); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp index 3a9b612860b..63c6c9ea886 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.cpp @@ -28,9 +28,57 @@ #include "gc/shenandoah/shenandoahLock.hpp" #include "runtime/atomic.hpp" +#include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.hpp" #include "runtime/os.inline.hpp" +void ShenandoahLock::contended_lock(bool allow_block_for_safepoint) { + Thread* thread = Thread::current(); + if (allow_block_for_safepoint && thread->is_Java_thread()) { + contended_lock_internal(JavaThread::cast(thread)); + } else { + contended_lock_internal(nullptr); + } +} + +template +void ShenandoahLock::contended_lock_internal(JavaThread* java_thread) { + assert(!ALLOW_BLOCK || java_thread != nullptr, "Must have a Java thread when allowing block."); + // Spin this much, but only on multi-processor systems. + int ctr = os::is_MP() ? 0xFF : 0; + // Apply TTAS to avoid more expensive CAS calls if the lock is still held by other thread. + while (Atomic::load(&_state) == locked || + Atomic::cmpxchg(&_state, unlocked, locked) != unlocked) { + if (ctr > 0 && !SafepointSynchronize::is_synchronizing()) { + // Lightly contended, spin a little if no safepoint is pending. + SpinPause(); + ctr--; + } else if (ALLOW_BLOCK) { + ThreadBlockInVM block(java_thread); + if (SafepointSynchronize::is_synchronizing()) { + // If safepoint is pending, we want to block and allow safepoint to proceed. + // Normally, TBIVM above would block us in its destructor. + // + // But that blocking only happens when TBIVM knows the thread poll is armed. + // There is a window between announcing a safepoint and arming the thread poll + // during which trying to continuously enter TBIVM is counter-productive. + // Under high contention, we may end up going in circles thousands of times. + // To avoid it, we wait here until local poll is armed and then proceed + // to TBVIM exit for blocking. We do not SpinPause, but yield to let + // VM thread to arm the poll sooner. + while (SafepointSynchronize::is_synchronizing() && + !SafepointMechanism::local_poll_armed(java_thread)) { + os::naked_yield(); + } + } else { + os::naked_yield(); + } + } else { + os::naked_yield(); + } + } +} + ShenandoahSimpleLock::ShenandoahSimpleLock() { assert(os::mutex_init_done(), "Too early!"); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp index 62376376195..4d7eefd460c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp @@ -35,34 +35,41 @@ class ShenandoahLock { enum LockState { unlocked = 0, locked = 1 }; shenandoah_padding(0); - volatile int _state; + volatile LockState _state; shenandoah_padding(1); - volatile Thread* _owner; + Thread* volatile _owner; shenandoah_padding(2); + template + void contended_lock_internal(JavaThread* java_thread); public: ShenandoahLock() : _state(unlocked), _owner(nullptr) {}; - void lock() { -#ifdef ASSERT - assert(_owner != Thread::current(), "reentrant locking attempt, would deadlock"); -#endif - Thread::SpinAcquire(&_state, "Shenandoah Heap Lock"); -#ifdef ASSERT - assert(_state == locked, "must be locked"); - assert(_owner == nullptr, "must not be owned"); - _owner = Thread::current(); -#endif + void lock(bool allow_block_for_safepoint) { + assert(Atomic::load(&_owner) != Thread::current(), "reentrant locking attempt, would deadlock"); + + if ((allow_block_for_safepoint && SafepointSynchronize::is_synchronizing()) || + (Atomic::cmpxchg(&_state, unlocked, locked) != unlocked)) { + // 1. Java thread, and there is a pending safepoint. Dive into contended locking + // immediately without trying anything else, and block. + // 2. Fast lock fails, dive into contended lock handling. + contended_lock(allow_block_for_safepoint); + } + + assert(Atomic::load(&_state) == locked, "must be locked"); + assert(Atomic::load(&_owner) == nullptr, "must not be owned"); + DEBUG_ONLY(Atomic::store(&_owner, Thread::current());) } void unlock() { -#ifdef ASSERT - assert (_owner == Thread::current(), "sanity"); - _owner = nullptr; -#endif - Thread::SpinRelease(&_state); + assert(Atomic::load(&_owner) == Thread::current(), "sanity"); + DEBUG_ONLY(Atomic::store(&_owner, (Thread*)nullptr);) + OrderAccess::fence(); + Atomic::store(&_state, unlocked); } + void contended_lock(bool allow_block_for_safepoint); + bool owned_by_self() { #ifdef ASSERT return _state == locked && _owner == Thread::current(); @@ -77,9 +84,9 @@ class ShenandoahLocker : public StackObj { private: ShenandoahLock* const _lock; public: - ShenandoahLocker(ShenandoahLock* lock) : _lock(lock) { + ShenandoahLocker(ShenandoahLock* lock, bool allow_block_for_safepoint = false) : _lock(lock) { if (_lock != nullptr) { - _lock->lock(); + _lock->lock(allow_block_for_safepoint); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp index 980050b8b00..ebf2d729930 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2022, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,6 +31,7 @@ #include "gc/shenandoah/shenandoahOopClosures.inline.hpp" #include "memory/resourceArea.hpp" #include "runtime/continuation.hpp" +#include "runtime/safepointVerifiers.hpp" ShenandoahNMethod::ShenandoahNMethod(nmethod* nm, GrowableArray& oops, bool non_immediate_oops) : _nm(nm), _oops(nullptr), _oops_count(0), _unregistered(false) { @@ -474,21 +476,40 @@ void ShenandoahNMethodTableSnapshot::concurrent_nmethods_do(NMethodClosure* cl) } ShenandoahConcurrentNMethodIterator::ShenandoahConcurrentNMethodIterator(ShenandoahNMethodTable* table) : - _table(table), _table_snapshot(nullptr) { -} - -void ShenandoahConcurrentNMethodIterator::nmethods_do_begin() { - assert(CodeCache_lock->owned_by_self(), "Lock must be held"); - _table_snapshot = _table->snapshot_for_iteration(); -} + _table(table), + _table_snapshot(nullptr), + _started_workers(0), + _finished_workers(0) {} void ShenandoahConcurrentNMethodIterator::nmethods_do(NMethodClosure* cl) { - assert(_table_snapshot != nullptr, "Must first call nmethod_do_begin()"); - _table_snapshot->concurrent_nmethods_do(cl); -} + // Cannot safepoint when iteration is running, because this can cause deadlocks + // with other threads waiting on iteration to be over. + NoSafepointVerifier nsv; -void ShenandoahConcurrentNMethodIterator::nmethods_do_end() { - assert(CodeCache_lock->owned_by_self(), "Lock must be held"); - _table->finish_iteration(_table_snapshot); - CodeCache_lock->notify_all(); + MutexLocker ml(CodeCache_lock, Mutex::_no_safepoint_check_flag); + + if (_finished_workers > 0) { + // Some threads have already finished. We are now in rampdown: we are now + // waiting for all currently recorded workers to finish. No new workers + // should start. + return; + } + + // Record a new worker and initialize the snapshot if it is a first visitor. + if (_started_workers++ == 0) { + _table_snapshot = _table->snapshot_for_iteration(); + } + + // All set, relinquish the lock and go concurrent. + { + MutexUnlocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + _table_snapshot->concurrent_nmethods_do(cl); + } + + // Record completion. Last worker shuts down the iterator and notifies any waiters. + uint count = ++_finished_workers; + if (count == _started_workers) { + _table->finish_iteration(_table_snapshot); + CodeCache_lock->notify_all(); + } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp index 6a856e68403..9cc36fbb11b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp @@ -178,13 +178,13 @@ class ShenandoahConcurrentNMethodIterator { private: ShenandoahNMethodTable* const _table; ShenandoahNMethodTableSnapshot* _table_snapshot; + uint _started_workers; + uint _finished_workers; public: ShenandoahConcurrentNMethodIterator(ShenandoahNMethodTable* table); - void nmethods_do_begin(); void nmethods_do(NMethodClosure* cl); - void nmethods_do_end(); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHNMETHOD_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp index af32a20013a..15f0ee61407 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp @@ -132,7 +132,7 @@ class ShenandoahGCPauseMark : public StackObj { ShenandoahHeap* const _heap; const GCIdMark _gc_id_mark; const SvcGCMarker _svc_gc_mark; - const IsGCActiveMark _is_gc_active_mark; + const IsSTWGCActiveMark _is_gc_active_mark; TraceMemoryManagerStats _trace_pause; public: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp index eeeb1dcad19..9d2782502fe 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp @@ -42,6 +42,9 @@ bool VM_ShenandoahOperation::doit_prologue() { void VM_ShenandoahOperation::doit_epilogue() { assert(!ShenandoahHeap::heap()->has_gc_state_changed(), "GC State was not synchronized to java threads."); + // GC thread root traversal likely used OopMapCache a lot, which + // might have created lots of old entries. Trigger the cleanup now. + OopMapCache::try_trigger_cleanup(); } bool VM_ShenandoahReferenceOperation::doit_prologue() { @@ -52,7 +55,6 @@ bool VM_ShenandoahReferenceOperation::doit_prologue() { void VM_ShenandoahReferenceOperation::doit_epilogue() { VM_ShenandoahOperation::doit_epilogue(); - OopMapCache::cleanup_old_entries(); if (Universe::has_reference_pending_list()) { Heap_lock->notify_all(); } diff --git a/src/hotspot/share/gc/x/xDriver.cpp b/src/hotspot/share/gc/x/xDriver.cpp index f76d9f4e586..3e6fd03134e 100644 --- a/src/hotspot/share/gc/x/xDriver.cpp +++ b/src/hotspot/share/gc/x/xDriver.cpp @@ -35,6 +35,7 @@ #include "gc/x/xServiceability.hpp" #include "gc/x/xStat.hpp" #include "gc/x/xVerify.hpp" +#include "interpreter/oopMapCache.hpp" #include "logging/log.hpp" #include "memory/universe.hpp" #include "runtime/threads.hpp" @@ -116,7 +117,7 @@ class VM_XOperation : public VM_Operation { // Setup GC id and active marker GCIdMark gc_id_mark(_gc_id); - IsGCActiveMark gc_active_mark; + IsSTWGCActiveMark gc_active_mark; // Verify before operation XVerify::before_zoperation(); @@ -130,6 +131,10 @@ class VM_XOperation : public VM_Operation { virtual void doit_epilogue() { Heap_lock->unlock(); + + // GC thread root traversal likely used OopMapCache a lot, which + // might have created lots of old entries. Trigger the cleanup now. + OopMapCache::try_trigger_cleanup(); } bool gc_locked() const { diff --git a/src/hotspot/share/gc/x/xMark.cpp b/src/hotspot/share/gc/x/xMark.cpp index e4e5c25f34f..016c5702615 100644 --- a/src/hotspot/share/gc/x/xMark.cpp +++ b/src/hotspot/share/gc/x/xMark.cpp @@ -367,8 +367,10 @@ void XMark::mark_and_follow(XMarkContext* context, XMarkStackEntry entry) { const oop obj = XOop::from_address(addr); follow_object(obj, finalizable); - // Try deduplicate - try_deduplicate(context, obj); + if (!finalizable) { + // Try deduplicate + try_deduplicate(context, obj); + } } } } diff --git a/src/hotspot/share/gc/z/zDirector.cpp b/src/hotspot/share/gc/z/zDirector.cpp index 417ac33a6f8..ae9a9fa404a 100644 --- a/src/hotspot/share/gc/z/zDirector.cpp +++ b/src/hotspot/share/gc/z/zDirector.cpp @@ -524,6 +524,10 @@ static bool rule_major_allocation_rate(const ZDirectorStats& stats) { } static double calculate_young_to_old_worker_ratio(const ZDirectorStats& stats) { + if (!stats._old_stats._cycle._is_time_trustable) { + return 1.0; + } + const double young_gc_time = gc_time(stats._young_stats); const double old_gc_time = gc_time(stats._old_stats); const size_t reclaimed_per_young_gc = stats._young_stats._stat_heap._reclaimed_avg; diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 0b131c65248..a8114bce71a 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -52,6 +52,7 @@ #include "gc/z/zUncoloredRoot.inline.hpp" #include "gc/z/zVerify.hpp" #include "gc/z/zWorkers.hpp" +#include "interpreter/oopMapCache.hpp" #include "logging/log.hpp" #include "memory/universe.hpp" #include "prims/jvmtiTagMap.hpp" @@ -438,7 +439,7 @@ class VM_ZOperation : public VM_Operation { virtual void doit() { // Setup GC id and active marker GCIdMark gc_id_mark(_gc_id); - IsGCActiveMark gc_active_mark; + IsSTWGCActiveMark gc_active_mark; // Verify before operation ZVerify::before_zoperation(); @@ -452,6 +453,10 @@ class VM_ZOperation : public VM_Operation { virtual void doit_epilogue() { Heap_lock->unlock(); + + // GC thread root traversal likely used OopMapCache a lot, which + // might have created lots of old entries. Trigger the cleanup now. + OopMapCache::try_trigger_cleanup(); } bool success() const { diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp index 8bfca55a6b4..eb342495f57 100644 --- a/src/hotspot/share/gc/z/zMark.cpp +++ b/src/hotspot/share/gc/z/zMark.cpp @@ -457,8 +457,10 @@ void ZMark::mark_and_follow(ZMarkContext* context, ZMarkStackEntry entry) { const oop obj = to_oop(addr); follow_object(obj, finalizable); - // Try deduplicate - try_deduplicate(context, obj); + if (!finalizable) { + // Try deduplicate + try_deduplicate(context, obj); + } } } } diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index b168610db3a..4b48da7d73c 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -493,9 +493,6 @@ void ZVerify::after_mark() { roots_strong(true /* verify_after_old_mark */); } if (ZVerifyObjects) { - // Workaround OopMapCacheAlloc_lock reordering with the StackWatermark_lock - DisableIsGCActiveMark mark; - objects(false /* verify_weaks */); guarantee(zverify_broken_object == zaddress::null, "Verification failed"); } diff --git a/src/hotspot/share/gc/z/z_globals.hpp b/src/hotspot/share/gc/z/z_globals.hpp index 01fb0e0a91f..06b7cc49133 100644 --- a/src/hotspot/share/gc/z/z_globals.hpp +++ b/src/hotspot/share/gc/z/z_globals.hpp @@ -37,6 +37,7 @@ \ product(double, ZYoungCompactionLimit, 25.0, \ "Maximum allowed garbage in young pages") \ + range(0, 100) \ \ product(double, ZCollectionIntervalMinor, -1, \ "Force Minor GC at a fixed time interval (in seconds)") \ diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp index 533f6d62a8e..e386ab42fb8 100644 --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -1795,7 +1795,7 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHan // the interpreter or runtime performs a serialized check of // the relevant ResolvedIndyEntry::method field. This is done by the caller // of this method, via CPC::set_dynamic_call, which uses - // a lock to do the final serialization of updates + // an ObjectLocker to do the final serialization of updates // to ResolvedIndyEntry state, including method. // Log dynamic info to CDS classlist. diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 1aa3415b4ab..27446eaa4fe 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/signature.hpp" +#include "utilities/globalCounter.inline.hpp" class OopMapCacheEntry: private InterpreterOopMap { friend class InterpreterOopMap; @@ -53,6 +54,8 @@ class OopMapCacheEntry: private InterpreterOopMap { // Deallocate bit masks and initialize fields void flush(); + static void deallocate(OopMapCacheEntry* const entry); + private: void allocate_bit_mask(); // allocates the bit mask on C heap f necessary void deallocate_bit_mask(); // allocates the bit mask on C heap f necessary @@ -61,9 +64,6 @@ class OopMapCacheEntry: private InterpreterOopMap { public: OopMapCacheEntry() : InterpreterOopMap() { _next = nullptr; -#ifdef ASSERT - _resource_allocate_bit_mask = false; -#endif } }; @@ -172,20 +172,12 @@ class VerifyClosure : public OffsetClosure { InterpreterOopMap::InterpreterOopMap() { initialize(); -#ifdef ASSERT - _resource_allocate_bit_mask = true; -#endif } InterpreterOopMap::~InterpreterOopMap() { - // The expectation is that the bit mask was allocated - // last in this resource area. That would make the free of the - // bit_mask effective (see how FREE_RESOURCE_ARRAY does a free). - // If it was not allocated last, there is not a correctness problem - // but the space for the bit_mask is not freed. - assert(_resource_allocate_bit_mask, "Trying to free C heap space"); - if (mask_size() > small_mask_limit) { - FREE_RESOURCE_ARRAY(uintptr_t, _bit_mask[0], mask_word_size()); + if (has_valid_mask() && mask_size() > small_mask_limit) { + assert(_bit_mask[0] != 0, "should have pointer to C heap"); + FREE_C_HEAP_ARRAY(uintptr_t, _bit_mask[0]); } } @@ -399,38 +391,31 @@ void OopMapCacheEntry::flush() { initialize(); } +void OopMapCacheEntry::deallocate(OopMapCacheEntry* const entry) { + entry->flush(); + FREE_C_HEAP_OBJ(entry); +} // Implementation of OopMapCache -void InterpreterOopMap::resource_copy(OopMapCacheEntry* from) { - assert(_resource_allocate_bit_mask, - "Should not resource allocate the _bit_mask"); +void InterpreterOopMap::copy_from(const OopMapCacheEntry* src) { + // The expectation is that this InterpreterOopMap is recently created + // and empty. It is used to get a copy of a cached entry. + assert(!has_valid_mask(), "InterpreterOopMap object can only be filled once"); + assert(src->has_valid_mask(), "Cannot copy entry with an invalid mask"); - set_method(from->method()); - set_bci(from->bci()); - set_mask_size(from->mask_size()); - set_expression_stack_size(from->expression_stack_size()); - _num_oops = from->num_oops(); + set_method(src->method()); + set_bci(src->bci()); + set_mask_size(src->mask_size()); + set_expression_stack_size(src->expression_stack_size()); + _num_oops = src->num_oops(); // Is the bit mask contained in the entry? - if (from->mask_size() <= small_mask_limit) { - memcpy((void *)_bit_mask, (void *)from->_bit_mask, - mask_word_size() * BytesPerWord); + if (src->mask_size() <= small_mask_limit) { + memcpy(_bit_mask, src->_bit_mask, mask_word_size() * BytesPerWord); } else { - // The expectation is that this InterpreterOopMap is a recently created - // and empty. It is used to get a copy of a cached entry. - // If the bit mask has a value, it should be in the - // resource area. - assert(_bit_mask[0] == 0 || - Thread::current()->resource_area()->contains((void*)_bit_mask[0]), - "The bit mask should have been allocated from a resource area"); - // Allocate the bit_mask from a Resource area for performance. Allocating - // from the C heap as is done for OopMapCache has a significant - // performance impact. - _bit_mask[0] = (uintptr_t) NEW_RESOURCE_ARRAY(uintptr_t, mask_word_size()); - assert(_bit_mask[0] != 0, "bit mask was not allocated"); - memcpy((void*) _bit_mask[0], (void*) from->_bit_mask[0], - mask_word_size() * BytesPerWord); + _bit_mask[0] = (uintptr_t) NEW_C_HEAP_ARRAY(uintptr_t, mask_word_size(), mtClass); + memcpy((void*) _bit_mask[0], (void*) src->_bit_mask[0], mask_word_size() * BytesPerWord); } } @@ -446,41 +431,36 @@ inline unsigned int OopMapCache::hash_value_for(const methodHandle& method, int OopMapCacheEntry* volatile OopMapCache::_old_entries = nullptr; OopMapCache::OopMapCache() { - _array = NEW_C_HEAP_ARRAY(OopMapCacheEntry*, _size, mtClass); - for(int i = 0; i < _size; i++) _array[i] = nullptr; + for(int i = 0; i < size; i++) _array[i] = nullptr; } OopMapCache::~OopMapCache() { - assert(_array != nullptr, "sanity check"); // Deallocate oop maps that are allocated out-of-line flush(); - // Deallocate array - FREE_C_HEAP_ARRAY(OopMapCacheEntry*, _array); } OopMapCacheEntry* OopMapCache::entry_at(int i) const { - return Atomic::load_acquire(&(_array[i % _size])); + return Atomic::load_acquire(&(_array[i % size])); } bool OopMapCache::put_at(int i, OopMapCacheEntry* entry, OopMapCacheEntry* old) { - return Atomic::cmpxchg(&_array[i % _size], old, entry) == old; + return Atomic::cmpxchg(&_array[i % size], old, entry) == old; } void OopMapCache::flush() { - for (int i = 0; i < _size; i++) { + for (int i = 0; i < size; i++) { OopMapCacheEntry* entry = _array[i]; if (entry != nullptr) { _array[i] = nullptr; // no barrier, only called in OopMapCache destructor - entry->flush(); - FREE_C_HEAP_OBJ(entry); + OopMapCacheEntry::deallocate(entry); } } } void OopMapCache::flush_obsolete_entries() { assert(SafepointSynchronize::is_at_safepoint(), "called by RedefineClasses in a safepoint"); - for (int i = 0; i < _size; i++) { + for (int i = 0; i < size; i++) { OopMapCacheEntry* entry = _array[i]; if (entry != nullptr && !entry->is_empty() && entry->method()->is_old()) { // Cache entry is occupied by an old redefined method and we don't want @@ -492,21 +472,16 @@ void OopMapCache::flush_obsolete_entries() { entry->method()->name()->as_C_string(), entry->method()->signature()->as_C_string(), i); } _array[i] = nullptr; - entry->flush(); - FREE_C_HEAP_OBJ(entry); + OopMapCacheEntry::deallocate(entry); } } } -// Called by GC for thread root scan during a safepoint only. The other interpreted frame oopmaps -// are generated locally and not cached. +// Lookup or compute/cache the entry. void OopMapCache::lookup(const methodHandle& method, int bci, InterpreterOopMap* entry_for) { - assert(SafepointSynchronize::is_at_safepoint(), "called by GC in a safepoint"); int probe = hash_value_for(method, bci); - int i; - OopMapCacheEntry* entry = nullptr; if (log_is_enabled(Debug, interpreter, oopmap)) { static int count = 0; @@ -516,14 +491,18 @@ void OopMapCache::lookup(const methodHandle& method, method()->name_and_sig_as_C_string(), probe); } - // Search hashtable for match - for(i = 0; i < _probe_depth; i++) { - entry = entry_at(probe + i); - if (entry != nullptr && !entry->is_empty() && entry->match(method, bci)) { - entry_for->resource_copy(entry); - assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); - log_debug(interpreter, oopmap)("- found at hash %d", probe + i); - return; + // Search hashtable for match. + // Need a critical section to avoid race against concurrent reclamation. + { + GlobalCounter::CriticalSection cs(Thread::current()); + for (int i = 0; i < probe_depth; i++) { + OopMapCacheEntry *entry = entry_at(probe + i); + if (entry != nullptr && !entry->is_empty() && entry->match(method, bci)) { + entry_for->copy_from(entry); + assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); + log_debug(interpreter, oopmap)("- found at hash %d", probe + i); + return; + } } } @@ -533,21 +512,20 @@ void OopMapCache::lookup(const methodHandle& method, OopMapCacheEntry* tmp = NEW_C_HEAP_OBJ(OopMapCacheEntry, mtClass); tmp->initialize(); tmp->fill(method, bci); - entry_for->resource_copy(tmp); + entry_for->copy_from(tmp); if (method->should_not_be_cached()) { // It is either not safe or not a good idea to cache this Method* // at this time. We give the caller of lookup() a copy of the // interesting info via parameter entry_for, but we don't add it to // the cache. See the gory details in Method*.cpp. - tmp->flush(); - FREE_C_HEAP_OBJ(tmp); + OopMapCacheEntry::deallocate(tmp); return; } // First search for an empty slot - for(i = 0; i < _probe_depth; i++) { - entry = entry_at(probe + i); + for (int i = 0; i < probe_depth; i++) { + OopMapCacheEntry* entry = entry_at(probe + i); if (entry == nullptr) { if (put_at(probe + i, tmp, nullptr)) { assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); @@ -562,9 +540,13 @@ void OopMapCache::lookup(const methodHandle& method, // where the first entry in the collision array is replaced with the new one. OopMapCacheEntry* old = entry_at(probe + 0); if (put_at(probe + 0, tmp, old)) { + // Cannot deallocate old entry on the spot: it can still be used by readers + // that got a reference to it before we were able to replace it in the map. + // Instead of synchronizing on GlobalCounter here and incurring heavy thread + // walk, we do this clean up out of band. enqueue_for_cleanup(old); } else { - enqueue_for_cleanup(tmp); + OopMapCacheEntry::deallocate(tmp); } assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); @@ -572,13 +554,14 @@ void OopMapCache::lookup(const methodHandle& method, } void OopMapCache::enqueue_for_cleanup(OopMapCacheEntry* entry) { - bool success = false; - OopMapCacheEntry* head; - do { - head = _old_entries; + while (true) { + OopMapCacheEntry* head = Atomic::load(&_old_entries); entry->_next = head; - success = Atomic::cmpxchg(&_old_entries, head, entry) == head; - } while (!success); + if (Atomic::cmpxchg(&_old_entries, head, entry) == head) { + // Enqueued successfully. + break; + } + } if (log_is_enabled(Debug, interpreter, oopmap)) { ResourceMark rm; @@ -587,11 +570,31 @@ void OopMapCache::enqueue_for_cleanup(OopMapCacheEntry* entry) { } } -// This is called after GC threads are done and nothing is accessing the old_entries -// list, so no synchronization needed. -void OopMapCache::cleanup_old_entries() { - OopMapCacheEntry* entry = _old_entries; - _old_entries = nullptr; +bool OopMapCache::has_cleanup_work() { + return Atomic::load(&_old_entries) != nullptr; +} + +void OopMapCache::try_trigger_cleanup() { + // See we can take the lock for the notification without blocking. + // This allows triggering the cleanup from GC paths, that can hold + // the service lock for e.g. oop iteration in service thread. + if (has_cleanup_work() && Service_lock->try_lock_without_rank_check()) { + Service_lock->notify_all(); + Service_lock->unlock(); + } +} + +void OopMapCache::cleanup() { + OopMapCacheEntry* entry = Atomic::xchg(&_old_entries, (OopMapCacheEntry*)nullptr); + if (entry == nullptr) { + // No work. + return; + } + + // About to delete the entries than might still be accessed by other threads + // on lookup path. Need to sync up with them before proceeding. + GlobalCounter::write_synchronize(); + while (entry != nullptr) { if (log_is_enabled(Debug, interpreter, oopmap)) { ResourceMark rm; @@ -599,8 +602,7 @@ void OopMapCache::cleanup_old_entries() { entry->method()->name_and_sig_as_C_string(), entry->bci()); } OopMapCacheEntry* next = entry->_next; - entry->flush(); - FREE_C_HEAP_OBJ(entry); + OopMapCacheEntry::deallocate(entry); entry = next; } } @@ -610,7 +612,8 @@ void OopMapCache::compute_one_oop_map(const methodHandle& method, int bci, Inter OopMapCacheEntry* tmp = NEW_C_HEAP_OBJ(OopMapCacheEntry, mtClass); tmp->initialize(); tmp->fill(method, bci); - entry->resource_copy(tmp); - tmp->flush(); - FREE_C_HEAP_OBJ(tmp); + if (tmp->has_valid_mask()) { + entry->copy_from(tmp); + } + OopMapCacheEntry::deallocate(tmp); } diff --git a/src/hotspot/share/interpreter/oopMapCache.hpp b/src/hotspot/share/interpreter/oopMapCache.hpp index 80efe351437..711924ea412 100644 --- a/src/hotspot/share/interpreter/oopMapCache.hpp +++ b/src/hotspot/share/interpreter/oopMapCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * 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 @@ // OopMapCache's are allocated lazily per InstanceKlass. // The oopMap (InterpreterOopMap) is stored as a bit mask. If the -// bit_mask can fit into two words it is stored in +// bit_mask can fit into four words it is stored in // the _bit_mask array, otherwise it is allocated on the heap. // For OopMapCacheEntry the bit_mask is allocated in the C heap // because these entries persist between garbage collections. -// For InterpreterOopMap the bit_mask is allocated in -// a resource area for better performance. InterpreterOopMap -// should only be created and deleted during same garbage collection. +// For InterpreterOopMap the bit_mask is allocated in the C heap +// to avoid issues with allocations from the resource area that have +// to live accross the oop closure. InterpreterOopMap should only be +// created and deleted during the same garbage collection. // // If ENABBLE_ZAP_DEAD_LOCALS is defined, two bits are used // per entry instead of one. In all cases, @@ -82,7 +83,7 @@ class InterpreterOopMap: ResourceObj { private: Method* _method; // the method for which the mask is valid unsigned short _bci; // the bci for which the mask is valid - int _mask_size; // the mask size in bits + int _mask_size; // the mask size in bits (USHRT_MAX if invalid) int _expression_stack_size; // the size of the expression stack in slots protected: @@ -128,11 +129,11 @@ class InterpreterOopMap: ResourceObj { InterpreterOopMap(); ~InterpreterOopMap(); - // Copy the OopMapCacheEntry in parameter "from" into this - // InterpreterOopMap. If the _bit_mask[0] in "from" points to - // allocated space (i.e., the bit mask was to large to hold - // in-line), allocate the space from a Resource area. - void resource_copy(OopMapCacheEntry* from); + // Copy the OopMapCacheEntry in parameter "src" into this + // InterpreterOopMap. If the _bit_mask[0] in "src" points to + // allocated space (i.e., the bit mask was too large to hold + // in-line), allocate the space from the C heap. + void copy_from(const OopMapCacheEntry* src); void iterate_oop(OffsetClosure* oop_closure) const; void print() const; @@ -144,16 +145,17 @@ class InterpreterOopMap: ResourceObj { int expression_stack_size() const { return _expression_stack_size; } + // Determines if a valid mask has been computed + bool has_valid_mask() const { return _mask_size != USHRT_MAX; } }; class OopMapCache : public CHeapObj { static OopMapCacheEntry* volatile _old_entries; private: - enum { _size = 32, // Use fixed size for now - _probe_depth = 3 // probe depth in case of collisions - }; + static constexpr int size = 32; // Use fixed size for now + static constexpr int probe_depth = 3; // probe depth in case of collisions - OopMapCacheEntry* volatile * _array; + OopMapCacheEntry* volatile _array[size]; unsigned int hash_value_for(const methodHandle& method, int bci) const; OopMapCacheEntry* entry_at(int i) const; @@ -176,7 +178,15 @@ class OopMapCache : public CHeapObj { // Compute an oop map without updating the cache or grabbing any locks (for debugging) static void compute_one_oop_map(const methodHandle& method, int bci, InterpreterOopMap* entry); - static void cleanup_old_entries(); + + // Check if we need to clean up old entries + static bool has_cleanup_work(); + + // Request cleanup if work is needed and notification is currently possible + static void try_trigger_cleanup(); + + // Clean up the old entries + static void cleanup(); }; #endif // SHARE_INTERPRETER_OOPMAPCACHE_HPP diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index 132f1368649..fefcdd8c33d 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1989,11 +1989,9 @@ void BytecodeInterpreter::run(interpreterState istate) { size_t obj_size = ik->size_helper(); HeapWord* result = THREAD->tlab().allocate(obj_size); if (result != nullptr) { - // Initialize object field block: - // - if TLAB is pre-zeroed, we can skip this path - // - in debug mode, ThreadLocalAllocBuffer::allocate mangles - // this area, and we still need to initialize it - if (DEBUG_ONLY(true ||) !ZeroTLAB) { + // Initialize object field block. + if (!ZeroTLAB) { + // The TLAB was not pre-zeroed, we need to clear the memory here. size_t hdr_size = oopDesc::header_size(); Copy::fill_to_words(result + hdr_size, obj_size - hdr_size, 0); } diff --git a/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp b/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp index f2007231c22..882d468a4a3 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp @@ -156,6 +156,8 @@ void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, return; } ResourceMark rm(THREAD); + // WXWrite is needed before entering the vm below and in callee methods. + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, THREAD)); jclass* const classes = create_classes_array(classes_count, CHECK); assert(classes != nullptr, "invariant"); for (jint i = 0; i < classes_count; i++) { diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index c037e8bd525..7157c346db0 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -112,7 +112,9 @@ NO_TRANSITION_END NO_TRANSITION(void, jfr_set_enabled(JNIEnv* env, jobject jvm, jlong event_type_id, jboolean enabled)) JfrEventSetting::set_enabled(event_type_id, JNI_TRUE == enabled); if (EventOldObjectSample::eventId == event_type_id) { - ThreadInVMfromNative transition(JavaThread::thread_from_jni_environment(env)); + JavaThread* thread = JavaThread::thread_from_jni_environment(env); + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, thread)); + ThreadInVMfromNative transition(thread); if (JNI_TRUE == enabled) { LeakProfiler::start(JfrOptionSet::old_object_queue_size()); } else { diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp index ffd973696f1..7d372d9725f 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp @@ -214,9 +214,6 @@ class StackTraceBlobInstaller { StackTraceBlobInstaller() : _cache(JfrOptionSet::old_object_queue_size()) { prepare_for_resolution(); } - ~StackTraceBlobInstaller() { - JfrStackTraceRepository::clear_leak_profiler(); - } void sample_do(ObjectSample* sample) { if (stack_trace_precondition(sample)) { install(sample); @@ -270,11 +267,14 @@ void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler) { assert(LeakProfiler::is_running(), "invariant"); JavaThread* const thread = JavaThread::current(); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread);) - // can safepoint here - ThreadInVMfromNative transition(thread); - MutexLocker lock(ClassLoaderDataGraph_lock); - // the lock is needed to ensure the unload lists do not grow in the middle of inspection. - install_stack_traces(sampler); + { + // can safepoint here + ThreadInVMfromNative transition(thread); + MutexLocker lock(ClassLoaderDataGraph_lock); + // the lock is needed to ensure the unload lists do not grow in the middle of inspection. + install_stack_traces(sampler); + } + JfrStackTraceRepository::clear_leak_profiler(); } static bool is_klass_unloaded(traceid klass_id) { diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp index 9627259e264..57b29a09d01 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -248,12 +248,6 @@ bool ReferenceToThreadRootClosure::do_thread_stack_detailed(JavaThread* jt) { ReferenceLocateClosure rcl(_callback, OldObjectRoot::_threads, OldObjectRoot::_stack_variable, jt); if (jt->has_last_Java_frame()) { - // Traverse the monitor chunks - MonitorChunk* chunk = jt->monitor_chunks(); - for (; chunk != nullptr; chunk = chunk->next()) { - chunk->oops_do(&rcl); - } - if (rcl.complete()) { return true; } diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 47245923da4..80ea101a7c9 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -1104,7 +1104,7 @@ - + diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index 8da6600f89e..5f86fd4bcd2 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -109,6 +109,9 @@ bool JfrCheckpointManager::initialize() { // preallocate buffer count to each of the epoch live lists for (size_t i = 0; i < global_buffer_prealloc_count * 2; ++i) { Buffer* const buffer = mspace_allocate(global_buffer_size, _global_mspace); + if (buffer == nullptr) { + return false; + } _global_mspace->add_to_live_list(buffer, i % 2 == 0); } assert(_global_mspace->free_list_is_empty(), "invariant"); diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 2c0f74d13ed..762e4d441e9 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -219,7 +219,7 @@ static int write_klass(JfrCheckpointWriter* writer, KlassPtr klass, bool leakp) writer->write(cld != nullptr ? cld_id(cld, leakp) : 0); writer->write(mark_symbol(klass, leakp)); writer->write(package_id(klass, leakp)); - writer->write(get_flags(klass)); + writer->write(klass->modifier_flags()); writer->write(klass->is_hidden()); return 1; } diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index d2402ccbcd0..3c6d004650b 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -569,9 +569,7 @@ void JfrRecorderService::pre_safepoint_write() { ObjectSampleCheckpoint::on_rotation(ObjectSampler::acquire()); } write_storage(_storage, _chunkwriter); - if (_stack_trace_repository.is_modified()) { - write_stacktrace(_stack_trace_repository, _chunkwriter, false); - } + write_stacktrace(_stack_trace_repository, _chunkwriter, true); } void JfrRecorderService::invoke_safepoint_write() { diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp index f4f9628d60a..7caada5ab33 100644 --- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp +++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp @@ -98,11 +98,10 @@ bool JfrStackTraceRepository::is_modified() const { } size_t JfrStackTraceRepository::write(JfrChunkWriter& sw, bool clear) { + MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); if (_entries == 0) { return 0; } - MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); - assert(_entries > 0, "invariant"); int count = 0; for (u4 i = 0; i < TABLE_SIZE; ++i) { JfrStackTrace* stacktrace = _table[i]; diff --git a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp index 49f7719d00d..d9f90ee1153 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp @@ -291,6 +291,7 @@ void JfrStorage::register_full(BufferPtr buffer, Thread* thread) { JavaThread* jt = JavaThread::cast(thread); if (jt->thread_state() == _thread_in_native) { // Transition java thread to vm so it can issue a notify. + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt)); ThreadInVMfromNative transition(jt); _post_box.post(MSG_FULLBUFFER); return; diff --git a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp index 47cfca6b892..217b6dbddc3 100644 --- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp +++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp @@ -131,6 +131,9 @@ bool JfrStringPool::initialize() { // preallocate buffer count to each of the epoch live lists for (size_t i = 0; i < string_pool_cache_count * 2; ++i) { Buffer* const buffer = mspace_allocate(string_pool_buffer_size, _mspace); + if (buffer == nullptr) { + return false; + } _mspace->add_to_live_list(buffer, i % 2 == 0); } assert(_mspace->free_list_is_empty(), "invariant"); diff --git a/src/hotspot/share/jfr/support/jfrIntrinsics.cpp b/src/hotspot/share/jfr/support/jfrIntrinsics.cpp index acc640077d4..4b7c6c8aee9 100644 --- a/src/hotspot/share/jfr/support/jfrIntrinsics.cpp +++ b/src/hotspot/share/jfr/support/jfrIntrinsics.cpp @@ -56,6 +56,7 @@ void* JfrIntrinsicSupport::write_checkpoint(JavaThread* jt) { assert(JfrThreadLocal::is_vthread(jt), "invariant"); const u2 vthread_thread_local_epoch = JfrThreadLocal::vthread_epoch(jt); const u2 current_epoch = ThreadIdAccess::current_epoch(); + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt)); if (vthread_thread_local_epoch == current_epoch) { // After the epoch test in the intrinsic, the thread sampler interleaved // and suspended the thread. As part of taking a sample, it updated diff --git a/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp b/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp index 5ff319782b2..7634814b171 100644 --- a/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp +++ b/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp @@ -123,6 +123,7 @@ void JfrJavaEventWriter::flush(jobject writer, jint used, jint requested, JavaTh u1* const new_current_position = is_valid ? buffer->pos() + used : buffer->pos(); assert(start_pos_offset != invalid_offset, "invariant"); // can safepoint here + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt)); ThreadInVMfromNative transition(jt); oop const w = JNIHandles::resolve_non_null(writer); assert(w != nullptr, "invariant"); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index 73a19d01173..70ff2370f99 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -859,7 +859,7 @@ static OopStorage* object_handles() { } jlong JVMCIRuntime::make_oop_handle(const Handle& obj) { - assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC"); + assert(!Universe::heap()->is_stw_gc_active(), "can't extend the root set during GC pause"); assert(oopDesc::is_oop(obj()), "not an oop"); oop* ptr = OopHandle(object_handles(), obj()).ptr_raw(); diff --git a/src/hotspot/share/memory/guardedMemory.cpp b/src/hotspot/share/memory/guardedMemory.cpp index 25a50f8ffb3..fbc72638a79 100644 --- a/src/hotspot/share/memory/guardedMemory.cpp +++ b/src/hotspot/share/memory/guardedMemory.cpp @@ -33,7 +33,9 @@ void* GuardedMemory::wrap_copy(const void* ptr, const size_t len, const void* ta if (outerp != nullptr) { GuardedMemory guarded(outerp, len, tag); void* innerp = guarded.get_user_ptr(); - memcpy(innerp, ptr, len); + if (ptr != nullptr) { + memcpy(innerp, ptr, len); + } return innerp; } return nullptr; // OOM diff --git a/src/hotspot/share/memory/resourceArea.cpp b/src/hotspot/share/memory/resourceArea.cpp index bc01a7baaaa..386e09b4ce8 100644 --- a/src/hotspot/share/memory/resourceArea.cpp +++ b/src/hotspot/share/memory/resourceArea.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,18 @@ void ResourceArea::bias_to(MEMFLAGS new_flags) { #ifdef ASSERT +ResourceMark::ResourceMark(ResourceArea* area, Thread* thread) : + _impl(area), + _thread(thread), + _previous_resource_mark(nullptr) +{ + if (_thread != nullptr) { + assert(_thread == Thread::current(), "not the current thread"); + _previous_resource_mark = _thread->current_resource_mark(); + _thread->set_current_resource_mark(this); + } +} + void ResourceArea::verify_has_resource_mark() { if (_nesting <= 0 && !VMError::is_error_reported()) { // Only report the first occurrence of an allocating thread that diff --git a/src/hotspot/share/memory/resourceArea.hpp b/src/hotspot/share/memory/resourceArea.hpp index a10e3105c6b..02cf1e1feb7 100644 --- a/src/hotspot/share/memory/resourceArea.hpp +++ b/src/hotspot/share/memory/resourceArea.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -191,17 +191,7 @@ class ResourceMark: public StackObj { #ifndef ASSERT ResourceMark(ResourceArea* area, Thread* thread) : _impl(area) {} #else - ResourceMark(ResourceArea* area, Thread* thread) : - _impl(area), - _thread(thread), - _previous_resource_mark(nullptr) - { - if (_thread != nullptr) { - assert(_thread == Thread::current(), "not the current thread"); - _previous_resource_mark = _thread->current_resource_mark(); - _thread->set_current_resource_mark(this); - } - } + ResourceMark(ResourceArea* area, Thread* thread); #endif // ASSERT public: diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index b6d4f14493c..2a535d2a089 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -1296,8 +1296,8 @@ bool Universe::release_fullgc_alot_dummy() { return true; } -bool Universe::is_gc_active() { - return heap()->is_gc_active(); +bool Universe::is_stw_gc_active() { + return heap()->is_stw_gc_active(); } bool Universe::is_in_heap(const void* p) { diff --git a/src/hotspot/share/memory/universe.hpp b/src/hotspot/share/memory/universe.hpp index aee154a98bc..83e8ac2707a 100644 --- a/src/hotspot/share/memory/universe.hpp +++ b/src/hotspot/share/memory/universe.hpp @@ -320,7 +320,7 @@ class Universe: AllStatic { // The particular choice of collected heap. static CollectedHeap* heap() { return _collectedHeap; } - DEBUG_ONLY(static bool is_gc_active();) + DEBUG_ONLY(static bool is_stw_gc_active();) DEBUG_ONLY(static bool is_in_heap(const void* p);) DEBUG_ONLY(static bool is_in_heap_or_null(const void* p) { return p == nullptr || is_in_heap(p); }) diff --git a/src/hotspot/share/oops/compressedOops.inline.hpp b/src/hotspot/share/oops/compressedOops.inline.hpp index 3f33926aa6d..298b1e9dae9 100644 --- a/src/hotspot/share/oops/compressedOops.inline.hpp +++ b/src/hotspot/share/oops/compressedOops.inline.hpp @@ -156,7 +156,7 @@ inline narrowKlass CompressedKlassPointers::encode_not_null(Klass* v, address na assert(KlassEncodingMetaspaceMax > pd, "change encoding max if new encoding"); uint64_t result = pd >> shift(); assert((result & CONST64(0xffffffff00000000)) == 0, "narrow klass pointer overflow"); - assert(decode_not_null(result, narrow_base) == v, "reversibility"); + assert(decode_not_null((narrowKlass)result, narrow_base) == v, "reversibility"); return (narrowKlass)result; } diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index 2d3285bb982..d26f1b66c0e 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -51,6 +51,7 @@ #include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" +#include "runtime/synchronizer.hpp" #include "runtime/vm_version.hpp" #include "utilities/macros.hpp" @@ -251,7 +252,7 @@ void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_co } if (invoke_code == Bytecodes::_invokestatic) { assert(method->method_holder()->is_initialized() || - method->method_holder()->is_init_thread(JavaThread::current()), + method->method_holder()->is_reentrant_initialization(JavaThread::current()), "invalid class initialization state for invoke_static"); if (!VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) { @@ -354,8 +355,16 @@ void ConstantPoolCacheEntry::set_method_handle_common(const constantPoolHandle& // A losing writer waits on the lock until the winner writes f1 and leaves // the lock, so that when the losing writer returns, he can use the linked // cache entry. + // Lock fields to write - MutexLocker ml(cpool->pool_holder()->init_monitor()); + JavaThread* current = JavaThread::current(); + objArrayHandle resolved_references(current, cpool->resolved_references()); + // Use the resolved_references() lock for this cpCache entry. + // resolved_references are created for all classes with Invokedynamic, MethodHandle + // or MethodType constant pool cache entries. + assert(resolved_references() != nullptr, + "a resolved_references array should have been created for this class"); + ObjectLocker ol(resolved_references, current); if (!is_f1_null()) { return; @@ -838,7 +847,14 @@ bool ConstantPoolCache::save_and_throw_indy_exc( assert(PENDING_EXCEPTION->is_a(vmClasses::LinkageError_klass()), "No LinkageError exception"); - MutexLocker ml(THREAD, cpool->pool_holder()->init_monitor()); + // Use the resolved_references() lock for this cpCache entry. + // resolved_references are created for all classes with Invokedynamic, MethodHandle + // or MethodType constant pool cache entries. + JavaThread* current = THREAD; + objArrayHandle resolved_references(current, cpool->resolved_references()); + assert(resolved_references() != nullptr, + "a resolved_references array should have been created for this class"); + ObjectLocker ol(resolved_references, current); // if the indy_info is resolved or the indy_resolution_failed flag is set then another // thread either succeeded in resolving the method or got a LinkageError @@ -862,11 +878,21 @@ bool ConstantPoolCache::save_and_throw_indy_exc( oop ConstantPoolCache::set_dynamic_call(const CallInfo &call_info, int index) { ResourceMark rm; - MutexLocker ml(constant_pool()->pool_holder()->init_monitor()); + + // Use the resolved_references() lock for this cpCache entry. + // resolved_references are created for all classes with Invokedynamic, MethodHandle + // or MethodType constant pool cache entries. + JavaThread* current = JavaThread::current(); + constantPoolHandle cp(current, constant_pool()); + + objArrayHandle resolved_references(current, cp->resolved_references()); + assert(resolved_references() != nullptr, + "a resolved_references array should have been created for this class"); + ObjectLocker ol(resolved_references, current); assert(index >= 0, "Indy index must be positive at this point"); if (resolved_indy_entry_at(index)->method() != nullptr) { - return constant_pool()->resolved_reference_from_indy(index); + return cp->resolved_reference_from_indy(index); } if (resolved_indy_entry_at(index)->resolution_failed()) { @@ -875,9 +901,7 @@ oop ConstantPoolCache::set_dynamic_call(const CallInfo &call_info, int index) { guarantee(index >= 0, "Invalid indy index"); int encoded_index = ResolutionErrorTable::encode_cpcache_index( ConstantPool::encode_invokedynamic_index(index)); - JavaThread* THREAD = JavaThread::current(); // For exception macros. - constantPoolHandle cp(THREAD, constant_pool()); - ConstantPool::throw_resolution_error(cp, encoded_index, THREAD); + ConstantPool::throw_resolution_error(cp, encoded_index, current); return nullptr; } @@ -901,7 +925,6 @@ oop ConstantPoolCache::set_dynamic_call(const CallInfo &call_info, int index) { if (has_appendix) { const int appendix_index = resolved_indy_entry_at(index)->resolved_references_index(); - objArrayOop resolved_references = constant_pool()->resolved_references(); assert(appendix_index >= 0 && appendix_index < resolved_references->length(), "oob"); assert(resolved_references->obj_at(appendix_index) == nullptr, "init just once"); resolved_references->obj_at_put(appendix_index, appendix()); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 6f0d521b9d4..7cb7d5beb28 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -83,6 +83,7 @@ #include "runtime/mutexLocker.hpp" #include "runtime/orderAccess.hpp" #include "runtime/reflectionUtils.hpp" +#include "runtime/synchronizer.hpp" #include "runtime/threads.hpp" #include "services/classLoadingService.hpp" #include "services/finalizerService.hpp" @@ -494,10 +495,6 @@ Array* InstanceKlass::create_new_default_vtable_indices(int len, TRAPS) { return vtable_indices; } -static Monitor* create_init_monitor(const char* name) { - return new Monitor(Mutex::safepoint, name); -} - InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind, ReferenceType reference_type) : Klass(kind), _nest_members(nullptr), @@ -510,7 +507,6 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind, Refe _nest_host_index(0), _init_state(allocated), _reference_type(reference_type), - _init_monitor(create_init_monitor("InstanceKlassInitMonitor_lock")), _init_thread(nullptr) { set_vtable_length(parser.vtable_size()); @@ -738,6 +734,28 @@ objArrayOop InstanceKlass::signers() const { return java_lang_Class::signers(java_mirror()); } +oop InstanceKlass::init_lock() const { + // return the init lock from the mirror + oop lock = java_lang_Class::init_lock(java_mirror()); + // Prevent reordering with any access of initialization state + OrderAccess::loadload(); + assert(lock != nullptr || !is_not_initialized(), // initialized or in_error state + "only fully initialized state can have a null lock"); + return lock; +} + +// Set the initialization lock to null so the object can be GC'ed. Any racing +// threads to get this lock will see a null lock and will not lock. +// That's okay because they all check for initialized state after getting +// the lock and return. +void InstanceKlass::fence_and_clear_init_lock() { + // make sure previous stores are all done, notably the init_state. + OrderAccess::storestore(); + java_lang_Class::clear_init_lock(java_mirror()); + assert(!is_not_initialized(), "class must be initialized now"); +} + + // See "The Virtual Machine Specification" section 2.16.5 for a detailed explanation of the class initialization // process. The step comments refers to the procedure described in that section. // Note: implementation moved to static method to expose the this pointer. @@ -765,49 +783,6 @@ void InstanceKlass::link_class(TRAPS) { } } -void InstanceKlass::check_link_state_and_wait(JavaThread* current) { - MonitorLocker ml(current, _init_monitor); - - bool debug_logging_enabled = log_is_enabled(Debug, class, init); - - // Another thread is linking this class, wait. - while (is_being_linked() && !is_init_thread(current)) { - if (debug_logging_enabled) { - ResourceMark rm(current); - log_debug(class, init)("Thread \"%s\" waiting for linking of %s by thread \"%s\"", - current->name(), external_name(), init_thread_name()); - } - ml.wait(); - } - - // This thread is recursively linking this class, continue - if (is_being_linked() && is_init_thread(current)) { - if (debug_logging_enabled) { - ResourceMark rm(current); - log_debug(class, init)("Thread \"%s\" recursively linking %s", - current->name(), external_name()); - } - return; - } - - // If this class wasn't linked already, set state to being_linked - if (!is_linked()) { - if (debug_logging_enabled) { - ResourceMark rm(current); - log_debug(class, init)("Thread \"%s\" linking %s", - current->name(), external_name()); - } - set_init_state(being_linked); - set_init_thread(current); - } else { - if (debug_logging_enabled) { - ResourceMark rm(current); - log_debug(class, init)("Thread \"%s\" found %s already linked", - current->name(), external_name()); - } - } -} - // Called to verify that a class can link during initialization, without // throwing a VerifyError. bool InstanceKlass::link_class_or_fail(TRAPS) { @@ -886,8 +861,9 @@ bool InstanceKlass::link_class_impl(TRAPS) { // verification & rewriting { - LockLinkState init_lock(this, jt); - + HandleMark hm(THREAD); + Handle h_init_lock(THREAD, init_lock()); + ObjectLocker ol(h_init_lock, jt); // rewritten will have been set if loader constraint error found // on an earlier link attempt // don't verify or rewrite if already rewritten @@ -945,7 +921,21 @@ bool InstanceKlass::link_class_impl(TRAPS) { // In case itable verification is ever added. // itable().verify(tty, true); #endif - set_initialization_state_and_notify(linked, THREAD); + if (UseVtableBasedCHA && Universe::is_fully_initialized()) { + DeoptimizationScope deopt_scope; + { + // Now mark all code that assumes the class is not linked. + // Set state under the Compile_lock also. + MutexLocker ml(THREAD, Compile_lock); + + set_init_state(linked); + CodeCache::mark_dependents_on(&deopt_scope, this); + } + // Perform the deopt handshake outside Compile_lock. + deopt_scope.deoptimize_marked(); + } else { + set_init_state(linked); + } if (JvmtiExport::should_post_class_prepare()) { JvmtiExport::post_class_prepare(THREAD, this); } @@ -1066,7 +1056,6 @@ void InstanceKlass::initialize_impl(TRAPS) { DTRACE_CLASSINIT_PROBE(required, -1); bool wait = false; - bool throw_error = false; JavaThread* jt = THREAD; @@ -1075,10 +1064,14 @@ void InstanceKlass::initialize_impl(TRAPS) { // refer to the JVM book page 47 for description of steps // Step 1 { - MonitorLocker ml(jt, _init_monitor); + Handle h_init_lock(THREAD, init_lock()); + ObjectLocker ol(h_init_lock, jt); // Step 2 - while (is_being_initialized() && !is_init_thread(jt)) { + // If we were to use wait() instead of waitInterruptibly() then + // we might end up throwing IE from link/symbol resolution sites + // that aren't expected to throw. This would wreak havoc. See 6320309. + while (is_being_initialized() && !is_reentrant_initialization(jt)) { if (debug_logging_enabled) { ResourceMark rm(jt); log_debug(class, init)("Thread \"%s\" waiting for initialization of %s by thread \"%s\"", @@ -1087,12 +1080,12 @@ void InstanceKlass::initialize_impl(TRAPS) { wait = true; jt->set_class_to_be_initialized(this); - ml.wait(); + ol.wait_uninterruptibly(jt); jt->set_class_to_be_initialized(nullptr); } // Step 3 - if (is_being_initialized() && is_init_thread(jt)) { + if (is_being_initialized() && is_reentrant_initialization(jt)) { if (debug_logging_enabled) { ResourceMark rm(jt); log_debug(class, init)("Thread \"%s\" recursively initializing %s", @@ -1120,7 +1113,19 @@ void InstanceKlass::initialize_impl(TRAPS) { log_debug(class, init)("Thread \"%s\" found %s is in error state", jt->name(), external_name()); } - throw_error = true; + + DTRACE_CLASSINIT_PROBE_WAIT(erroneous, -1, wait); + ResourceMark rm(THREAD); + Handle cause(THREAD, get_initialization_error(THREAD)); + + stringStream ss; + ss.print("Could not initialize class %s", external_name()); + if (cause.is_null()) { + THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), ss.as_string()); + } else { + THROW_MSG_CAUSE(vmSymbols::java_lang_NoClassDefFoundError(), + ss.as_string(), cause); + } } else { // Step 6 @@ -1134,22 +1139,6 @@ void InstanceKlass::initialize_impl(TRAPS) { } } - // Throw error outside lock - if (throw_error) { - DTRACE_CLASSINIT_PROBE_WAIT(erroneous, -1, wait); - ResourceMark rm(THREAD); - Handle cause(THREAD, get_initialization_error(THREAD)); - - stringStream ss; - ss.print("Could not initialize class %s", external_name()); - if (cause.is_null()) { - THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), ss.as_string()); - } else { - THROW_MSG_CAUSE(vmSymbols::java_lang_NoClassDefFoundError(), - ss.as_string(), cause); - } - } - // Step 7 // Next, if C is a class rather than an interface, initialize it's super class and super // interfaces. @@ -1207,7 +1196,7 @@ void InstanceKlass::initialize_impl(TRAPS) { // Step 9 if (!HAS_PENDING_EXCEPTION) { - set_initialization_state_and_notify(fully_initialized, THREAD); + set_initialization_state_and_notify(fully_initialized, CHECK); debug_only(vtable().verify(tty, true);) } else { @@ -1240,43 +1229,26 @@ void InstanceKlass::initialize_impl(TRAPS) { } -void InstanceKlass::set_initialization_state_and_notify(ClassState state, JavaThread* current) { - MonitorLocker ml(current, _init_monitor); - - if (state == linked && UseVtableBasedCHA && Universe::is_fully_initialized()) { - DeoptimizationScope deopt_scope; - { - // Now mark all code that assumes the class is not linked. - // Set state under the Compile_lock also. - MutexLocker ml(current, Compile_lock); - - set_init_thread(nullptr); // reset _init_thread before changing _init_state - set_init_state(state); - - CodeCache::mark_dependents_on(&deopt_scope, this); - } - // Perform the deopt handshake outside Compile_lock. - deopt_scope.deoptimize_marked(); +void InstanceKlass::set_initialization_state_and_notify(ClassState state, TRAPS) { + Handle h_init_lock(THREAD, init_lock()); + if (h_init_lock() != nullptr) { + ObjectLocker ol(h_init_lock, THREAD); + set_init_thread(nullptr); // reset _init_thread before changing _init_state + set_init_state(state); + fence_and_clear_init_lock(); + ol.notify_all(CHECK); } else { + assert(h_init_lock() != nullptr, "The initialization state should never be set twice"); set_init_thread(nullptr); // reset _init_thread before changing _init_state set_init_state(state); } - ml.notify_all(); } // Update hierarchy. This is done before the new klass has been added to the SystemDictionary. The Compile_lock // is grabbed, to ensure that the compiler is not using the class hierarchy. -void InstanceKlass::add_to_hierarchy(JavaThread* current) { +void InstanceKlass::add_to_hierarchy_impl(JavaThread* current) { assert(!SafepointSynchronize::is_at_safepoint(), "must NOT be at safepoint"); - // In case we are not using CHA based vtables we need to make sure the loaded - // deopt is completed before anyone links this class. - // Linking is done with _init_monitor held, by loading and deopting with it - // held we make sure the deopt is completed before linking. - if (!UseVtableBasedCHA) { - init_monitor()->lock(); - } - DeoptimizationScope deopt_scope; { MutexLocker ml(current, Compile_lock); @@ -1298,12 +1270,26 @@ void InstanceKlass::add_to_hierarchy(JavaThread* current) { } // Perform the deopt handshake outside Compile_lock. deopt_scope.deoptimize_marked(); +} + +void InstanceKlass::add_to_hierarchy(JavaThread* current) { + + if (UseVtableBasedCHA || !Universe::is_fully_initialized()) { + add_to_hierarchy_impl(current); + } else { + // In case we are not using CHA based vtables we need to make sure the loaded + // deopt is completed before anyone links this class. + // Linking is done with init_lock held, by loading and deopting with it + // held we make sure the deopt is completed before linking. + Handle h_init_lock(current, init_lock()); + ObjectLocker ol(h_init_lock, current); + add_to_hierarchy_impl(current); - if (!UseVtableBasedCHA) { - init_monitor()->unlock(); + // This doesn't need a notify because the wait is only on the class initialization path. } } + InstanceKlass* InstanceKlass::implementor() const { InstanceKlass* volatile* ik = adr_implementor(); if (ik == nullptr) { @@ -1618,16 +1604,17 @@ void InstanceKlass::call_class_initializer(TRAPS) { void InstanceKlass::mask_for(const methodHandle& method, int bci, InterpreterOopMap* entry_for) { - // Lazily create the _oop_map_cache at first request - // Lock-free access requires load_acquire. + // Lazily create the _oop_map_cache at first request. + // Load_acquire is needed to safely get instance published with CAS by another thread. OopMapCache* oop_map_cache = Atomic::load_acquire(&_oop_map_cache); if (oop_map_cache == nullptr) { - MutexLocker x(OopMapCacheAlloc_lock); - // Check if _oop_map_cache was allocated while we were waiting for this lock - if ((oop_map_cache = _oop_map_cache) == nullptr) { - oop_map_cache = new OopMapCache(); - // Ensure _oop_map_cache is stable, since it is examined without a lock - Atomic::release_store(&_oop_map_cache, oop_map_cache); + // Try to install new instance atomically. + oop_map_cache = new OopMapCache(); + OopMapCache* other = Atomic::cmpxchg(&_oop_map_cache, (OopMapCache*)nullptr, oop_map_cache); + if (other != nullptr) { + // Someone else managed to install before us, ditch local copy and use the existing one. + delete oop_map_cache; + oop_map_cache = other; } } // _oop_map_cache is constant after init; lookup below does its own locking. @@ -2654,7 +2641,6 @@ void InstanceKlass::remove_unshareable_info() { _nest_host = nullptr; init_shared_package_entry(); _dep_context_last_cleaned = 0; - _init_monitor = nullptr; remove_unshareable_flags(); } @@ -2756,9 +2742,6 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl if (DiagnoseSyncOnValueBasedClasses && has_value_based_class_annotation()) { set_is_value_based(); } - - // restore the monitor - _init_monitor = create_init_monitor("InstanceKlassInitMonitorRestored_lock"); } // Check if a class or any of its supertypes has a version older than 50. @@ -2854,9 +2837,6 @@ void InstanceKlass::release_C_heap_structures(bool release_sub_metadata) { methods_do(method_release_C_heap_structures); } - // Destroy the init_monitor - delete _init_monitor; - // Deallocate oop map cache if (_oop_map_cache != nullptr) { delete _oop_map_cache; @@ -3522,7 +3502,7 @@ nmethod* InstanceKlass::lookup_osr_nmethod(const Method* m, int bci, int comp_le #define BULLET " - " static const char* state_names[] = { - "allocated", "loaded", "being_linked", "linked", "being_initialized", "fully_initialized", "initialization_error" + "allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error" }; static void print_vtable(intptr_t* start, int len, outputStream* st) { @@ -3587,38 +3567,31 @@ void InstanceKlass::print_on(outputStream* st) const { } } st->print(BULLET"method ordering: "); method_ordering()->print_value_on(st); st->cr(); - st->print(BULLET"default_methods: "); default_methods()->print_value_on(st); st->cr(); - if (Verbose && default_methods() != nullptr) { - Array* method_array = default_methods(); - for (int i = 0; i < method_array->length(); i++) { - st->print("%d : ", i); method_array->at(i)->print_value(); st->cr(); + if (default_methods() != nullptr) { + st->print(BULLET"default_methods: "); default_methods()->print_value_on(st); st->cr(); + if (Verbose) { + Array* method_array = default_methods(); + for (int i = 0; i < method_array->length(); i++) { + st->print("%d : ", i); method_array->at(i)->print_value(); st->cr(); + } } } - if (default_vtable_indices() != nullptr) { - st->print(BULLET"default vtable indices: "); default_vtable_indices()->print_value_on(st); st->cr(); - } + print_on_maybe_null(st, BULLET"default vtable indices: ", default_vtable_indices()); st->print(BULLET"local interfaces: "); local_interfaces()->print_value_on(st); st->cr(); st->print(BULLET"trans. interfaces: "); transitive_interfaces()->print_value_on(st); st->cr(); st->print(BULLET"constants: "); constants()->print_value_on(st); st->cr(); - if (class_loader_data() != nullptr) { - st->print(BULLET"class loader data: "); - class_loader_data()->print_value_on(st); - st->cr(); - } - if (source_file_name() != nullptr) { - st->print(BULLET"source file: "); - source_file_name()->print_value_on(st); - st->cr(); - } + + print_on_maybe_null(st, BULLET"class loader data: ", class_loader_data()); + print_on_maybe_null(st, BULLET"source file: ", source_file_name()); if (source_debug_extension() != nullptr) { st->print(BULLET"source debug extension: "); st->print("%s", source_debug_extension()); st->cr(); } - st->print(BULLET"class annotations: "); class_annotations()->print_value_on(st); st->cr(); - st->print(BULLET"class type annotations: "); class_type_annotations()->print_value_on(st); st->cr(); - st->print(BULLET"field annotations: "); fields_annotations()->print_value_on(st); st->cr(); - st->print(BULLET"field type annotations: "); fields_type_annotations()->print_value_on(st); st->cr(); + print_on_maybe_null(st, BULLET"class annotations: ", class_annotations()); + print_on_maybe_null(st, BULLET"class type annotations: ", class_type_annotations()); + print_on_maybe_null(st, BULLET"field annotations: ", fields_annotations()); + print_on_maybe_null(st, BULLET"field type annotations: ", fields_type_annotations()); { bool have_pv = false; // previous versions are linked together through the InstanceKlass @@ -3633,16 +3606,10 @@ void InstanceKlass::print_on(outputStream* st) const { if (have_pv) st->cr(); } - if (generic_signature() != nullptr) { - st->print(BULLET"generic signature: "); - generic_signature()->print_value_on(st); - st->cr(); - } + print_on_maybe_null(st, BULLET"generic signature: ", generic_signature()); st->print(BULLET"inner classes: "); inner_classes()->print_value_on(st); st->cr(); st->print(BULLET"nest members: "); nest_members()->print_value_on(st); st->cr(); - if (record_components() != nullptr) { - st->print(BULLET"record components: "); record_components()->print_value_on(st); st->cr(); - } + print_on_maybe_null(st, BULLET"record components: ", record_components()); st->print(BULLET"permitted subclasses: "); permitted_subclasses()->print_value_on(st); st->cr(); if (java_mirror() != nullptr) { st->print(BULLET"java mirror: "); @@ -4077,17 +4044,13 @@ void JNIid::verify(Klass* holder) { } void InstanceKlass::set_init_state(ClassState state) { - if (state > loaded) { - assert_lock_strong(_init_monitor); - } #ifdef ASSERT bool good_state = is_shared() ? (_init_state <= state) : (_init_state < state); - bool link_failed = _init_state == being_linked && state == loaded; - assert(good_state || state == allocated || link_failed, "illegal state transition"); + assert(good_state || state == allocated, "illegal state transition"); #endif assert(_init_thread == nullptr, "should be cleared before state change"); - Atomic::store(&_init_state, state); + _init_state = state; } #if INCLUDE_JVMTI diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 30269602211..08fc2b49cc5 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -149,7 +149,6 @@ class InstanceKlass: public Klass { enum ClassState : u1 { allocated, // allocated (but not yet linked) loaded, // loaded and inserted in class hierarchy (but not linked yet) - being_linked, // currently running verifier and rewriter linked, // successfully linked/verified (but not initialized yet) being_initialized, // currently running class initializer fully_initialized, // initialized (successful final state) @@ -223,14 +222,20 @@ class InstanceKlass: public Klass { volatile u2 _idnum_allocated_count; // JNI/JVMTI: increments with the addition of methods, old ids don't change + // _is_marked_dependent can be set concurrently, thus cannot be part of the + // _misc_flags. + bool _is_marked_dependent; // used for marking during flushing and deoptimization + + // Class states are defined as ClassState (see above). + // Place the _init_state here to utilize the unused 2-byte after + // _idnum_allocated_count. volatile ClassState _init_state; // state of class - u1 _reference_type; // reference type + u1 _reference_type; // reference type // State is set either at parse time or while executing, atomically to not disturb other state InstanceKlassFlags _misc_flags; - Monitor* _init_monitor; // mutual exclusion to _init_state and _init_thread. JavaThread* volatile _init_thread; // Pointer to current thread doing initialization (to handle recursive initialization) OopMapCache* volatile _oop_map_cache; // OopMapCache for all methods in the klass (allocated lazily) @@ -493,41 +498,23 @@ class InstanceKlass: public Klass { TRAPS); JavaThread* init_thread() { return Atomic::load(&_init_thread); } - // We can safely access the name as long as we hold the _init_monitor. const char* init_thread_name() { - assert(_init_monitor->owned_by_self(), "Must hold _init_monitor here"); return init_thread()->name_raw(); } public: // initialization state - bool is_loaded() const { return init_state() >= loaded; } - bool is_linked() const { return init_state() >= linked; } - bool is_being_linked() const { return init_state() == being_linked; } - bool is_initialized() const { return init_state() == fully_initialized; } - bool is_not_initialized() const { return init_state() < being_initialized; } - bool is_being_initialized() const { return init_state() == being_initialized; } - bool is_in_error_state() const { return init_state() == initialization_error; } - bool is_init_thread(JavaThread *thread) { return thread == init_thread(); } - ClassState init_state() const { return Atomic::load(&_init_state); } + bool is_loaded() const { return _init_state >= loaded; } + bool is_linked() const { return _init_state >= linked; } + bool is_initialized() const { return _init_state == fully_initialized; } + bool is_not_initialized() const { return _init_state < being_initialized; } + bool is_being_initialized() const { return _init_state == being_initialized; } + bool is_in_error_state() const { return _init_state == initialization_error; } + bool is_reentrant_initialization(Thread *thread) { return thread == _init_thread; } + ClassState init_state() const { return _init_state; } const char* init_state_name() const; bool is_rewritten() const { return _misc_flags.rewritten(); } - class LockLinkState : public StackObj { - InstanceKlass* _ik; - JavaThread* _current; - public: - LockLinkState(InstanceKlass* ik, JavaThread* current) : _ik(ik), _current(current) { - ik->check_link_state_and_wait(current); - } - ~LockLinkState() { - if (!_ik->is_linked()) { - // Reset to loaded if linking failed. - _ik->set_initialization_state_and_notify(loaded, _current); - } - } - }; - // is this a sealed class bool is_sealed() const; @@ -839,7 +826,7 @@ class InstanceKlass: public Klass { // initialization void call_class_initializer(TRAPS); - void set_initialization_state_and_notify(ClassState state, JavaThread* current); + void set_initialization_state_and_notify(ClassState state, TRAPS); // OopMapCache support OopMapCache* oop_map_cache() { return _oop_map_cache; } @@ -851,6 +838,10 @@ class InstanceKlass: public Klass { void set_jni_ids(JNIid* ids) { _jni_ids = ids; } JNIid* jni_id_for(int offset); + private: + void add_to_hierarchy_impl(JavaThread* current); + + public: // maintenance of deoptimization dependencies inline DependencyContext dependencies(); void mark_dependent_nmethods(DeoptimizationScope* deopt_scope, KlassDepChange& changes); @@ -1068,7 +1059,7 @@ class InstanceKlass: public Klass { public: u2 idnum_allocated_count() const { return _idnum_allocated_count; } - private: +private: // initialization state void set_init_state(ClassState state); void set_rewritten() { _misc_flags.set_rewritten(true); } @@ -1090,6 +1081,12 @@ class InstanceKlass: public Klass { // Lock during initialization public: + // Lock for (1) initialization; (2) access to the ConstantPool of this class. + // Must be one per class and it has to be a VM internal object so java code + // cannot lock it (like the mirror). + // It has to be an object not a Mutex because it's held through java calls. + oop init_lock() const; + // Returns the array class for the n'th dimension virtual Klass* array_klass(int n, TRAPS); virtual Klass* array_klass_or_null(int n); @@ -1099,10 +1096,9 @@ class InstanceKlass: public Klass { virtual Klass* array_klass_or_null(); static void clean_initialization_error_table(); - - Monitor* init_monitor() const { return _init_monitor; } private: - void check_link_state_and_wait(JavaThread* current); + void fence_and_clear_init_lock(); + bool link_class_impl (TRAPS); bool verify_code (TRAPS); void initialize_impl (TRAPS); diff --git a/src/hotspot/share/oops/instanceStackChunkKlass.cpp b/src/hotspot/share/oops/instanceStackChunkKlass.cpp index 9f1b4d7253d..5c9b5ae5f92 100644 --- a/src/hotspot/share/oops/instanceStackChunkKlass.cpp +++ b/src/hotspot/share/oops/instanceStackChunkKlass.cpp @@ -244,8 +244,8 @@ void InstanceStackChunkKlass::print_chunk(const stackChunkOop c, bool verbose, o st->print_cr(" barriers: %d gc_mode: %d bitmap: %d parent: " PTR_FORMAT, c->requires_barriers(), c->is_gc_mode(), c->has_bitmap(), p2i(c->parent())); st->print_cr(" flags mixed: %d", c->has_mixed_frames()); - st->print_cr(" size: %d argsize: %d max_size: %d sp: %d pc: " PTR_FORMAT, - c->stack_size(), c->argsize(), c->max_thawing_size(), c->sp(), p2i(c->pc())); + st->print_cr(" size: %d bottom: %d max_size: %d sp: %d pc: " PTR_FORMAT, + c->stack_size(), c->bottom(), c->max_thawing_size(), c->sp(), p2i(c->pc())); if (verbose) { st->cr(); diff --git a/src/hotspot/share/oops/metadata.hpp b/src/hotspot/share/oops/metadata.hpp index c118ade8586..f5aee34c80d 100644 --- a/src/hotspot/share/oops/metadata.hpp +++ b/src/hotspot/share/oops/metadata.hpp @@ -76,4 +76,13 @@ class Metadata : public MetaspaceObj { static void mark_on_stack(Metadata* m) { m->set_on_stack(true); } }; +template +static void print_on_maybe_null(outputStream* st, const char* str, const M* m) { + if (nullptr != m) { + st->print_raw(str); + m->print_value_on(st); + st->cr(); + } +} + #endif // SHARE_OOPS_METADATA_HPP diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index c5693b02b05..4423cbde830 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -308,16 +308,13 @@ int Method::fast_exception_handler_bci_for(const methodHandle& mh, Klass* ex_kla void Method::mask_for(int bci, InterpreterOopMap* mask) { methodHandle h_this(Thread::current(), this); - // Only GC uses the OopMapCache during thread stack root scanning - // any other uses generate an oopmap but do not save it in the cache. - if (Universe::heap()->is_gc_active()) { - method_holder()->mask_for(h_this, bci, mask); - } else { - OopMapCache::compute_one_oop_map(h_this, bci, mask); - } - return; + mask_for(h_this, bci, mask); } +void Method::mask_for(const methodHandle& this_mh, int bci, InterpreterOopMap* mask) { + assert(this_mh() == this, "Sanity"); + method_holder()->mask_for(this_mh, bci, mask); +} int Method::bci_from(address bcp) const { if (is_native() && bcp == 0) { diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 1e2234e103b..af5b9b1a443 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -443,10 +443,6 @@ class Method : public Metadata { void unlink_method() NOT_CDS_RETURN; void remove_unshareable_flags() NOT_CDS_RETURN; - // the number of argument reg slots that the compiled method uses on the stack. - int num_stack_arg_slots(bool rounded = true) const { - return rounded ? align_up(constMethod()->num_stack_arg_slots(), 2) : constMethod()->num_stack_arg_slots(); } - virtual void metaspace_pointers_do(MetaspaceClosure* iter); virtual MetaspaceObj::Type type() const { return MethodType; } @@ -499,8 +495,10 @@ class Method : public Metadata { address signature_handler() const { return *(signature_handler_addr()); } void set_signature_handler(address handler); - // Interpreter oopmap support + // Interpreter oopmap support. + // If handle is already available, call with it for better performance. void mask_for(int bci, InterpreterOopMap* mask); + void mask_for(const methodHandle& this_mh, int bci, InterpreterOopMap* mask); // operations on invocation counter void print_invocation_count(); diff --git a/src/hotspot/share/oops/methodCounters.hpp b/src/hotspot/share/oops/methodCounters.hpp index 2c3fe8e43dd..d1b2207961f 100644 --- a/src/hotspot/share/oops/methodCounters.hpp +++ b/src/hotspot/share/oops/methodCounters.hpp @@ -75,17 +75,17 @@ class MethodCounters : public Metadata { _interpreter_throwout_count++; } } - int interpreter_throwout_count() const { + u2 interpreter_throwout_count() const { return _interpreter_throwout_count; } - void set_interpreter_throwout_count(int count) { + void set_interpreter_throwout_count(u2 count) { _interpreter_throwout_count = count; } #else // COMPILER2_OR_JVMCI - int interpreter_throwout_count() const { + u2 interpreter_throwout_count() const { return 0; } - void set_interpreter_throwout_count(int count) { + void set_interpreter_throwout_count(u2 count) { assert(count == 0, "count must be 0"); } #endif // COMPILER2_OR_JVMCI diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp index 0bb7d1b96a4..9d9d4c095a9 100644 --- a/src/hotspot/share/oops/oop.cpp +++ b/src/hotspot/share/oops/oop.cpp @@ -241,6 +241,6 @@ bool oopDesc::size_might_change() { // the grey portion of an already copied array. This will cause the first // disjunct below to fail if the two comparands are computed across such // a concurrent change. - return Universe::heap()->is_gc_active() && is_objArray() && is_forwarded() && (UseParallelGC || UseG1GC); + return Universe::heap()->is_stw_gc_active() && is_objArray() && is_forwarded() && (UseParallelGC || UseG1GC); } #endif diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index b7b9f6aeb6c..576ed6026ca 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -232,6 +232,8 @@ class oopDesc { jboolean bool_field_acquire(int offset) const; void release_bool_field_put(int offset, jboolean contents); + jint int_field_relaxed(int offset) const; + void int_field_put_relaxed(int offset, jint contents); jint int_field_acquire(int offset) const; void release_int_field_put(int offset, jint contents); diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index 57526dc58f7..62b8a85016f 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -333,6 +333,8 @@ inline void oopDesc::short_field_put(int offset, jshort value) { *field_add inline jint oopDesc::int_field(int offset) const { return *field_addr(offset); } inline void oopDesc::int_field_put(int offset, jint value) { *field_addr(offset) = value; } +inline jint oopDesc::int_field_relaxed(int offset) const { return Atomic::load(field_addr(offset)); } +inline void oopDesc::int_field_put_relaxed(int offset, jint value) { Atomic::store(field_addr(offset), value); } inline jlong oopDesc::long_field(int offset) const { return *field_addr(offset); } inline void oopDesc::long_field_put(int offset, jlong value) { *field_addr(offset) = value; } diff --git a/src/hotspot/share/oops/stackChunkOop.cpp b/src/hotspot/share/oops/stackChunkOop.cpp index 4e771939dc9..7a8044311e4 100644 --- a/src/hotspot/share/oops/stackChunkOop.cpp +++ b/src/hotspot/share/oops/stackChunkOop.cpp @@ -125,7 +125,7 @@ static int num_java_frames(const StackChunkFrameStream& f) { int stackChunkOopDesc::num_java_frames() const { int n = 0; for (StackChunkFrameStream f(const_cast(this)); !f.is_done(); - f.next(SmallRegisterMap::instance)) { + f.next(SmallRegisterMap::instance())) { if (!f.is_stub()) { n += ::num_java_frames(f); } @@ -535,12 +535,12 @@ bool stackChunkOopDesc::verify(size_t* out_size, int* out_oops, int* out_frames, assert(oopDesc::is_oop(this), ""); assert(stack_size() >= 0, ""); - assert(argsize() >= 0, ""); assert(!has_bitmap() || is_gc_mode(), ""); if (is_empty()) { - assert(argsize() == 0, ""); assert(max_thawing_size() == 0, ""); + } else { + assert(argsize() >= 0, ""); } assert(oopDesc::is_oop_or_null(parent()), ""); @@ -549,7 +549,7 @@ bool stackChunkOopDesc::verify(size_t* out_size, int* out_oops, int* out_frames, // If argsize == 0 and the chunk isn't mixed, the chunk contains the metadata (pc, fp -- frame::sender_sp_offset) // for the top frame (below sp), and *not* for the bottom frame. - int size = stack_size() - argsize() - sp(); + int size = bottom() - sp(); assert(size >= 0, ""); assert((size == 0) == is_empty(), ""); @@ -564,20 +564,23 @@ bool stackChunkOopDesc::verify(size_t* out_size, int* out_oops, int* out_frames, assert(!is_empty() || closure._cb == nullptr, ""); if (closure._cb != nullptr && closure._cb->is_compiled()) { assert(argsize() == - (closure._cb->as_compiled_method()->method()->num_stack_arg_slots()*VMRegImpl::stack_slot_size) >>LogBytesPerWord, + (closure._cb->as_nmethod()->num_stack_arg_slots()*VMRegImpl::stack_slot_size) >>LogBytesPerWord, "chunk argsize: %d bottom frame argsize: %d", argsize(), - (closure._cb->as_compiled_method()->method()->num_stack_arg_slots()*VMRegImpl::stack_slot_size) >>LogBytesPerWord); + (closure._cb->as_nmethod()->num_stack_arg_slots()*VMRegImpl::stack_slot_size) >>LogBytesPerWord); } assert(closure._num_interpreted_frames == 0 || has_mixed_frames(), ""); if (!concurrent) { - assert(closure._size <= size + argsize() + frame::metadata_words, - "size: %d argsize: %d closure.size: %d end sp: " PTR_FORMAT " start sp: %d chunk size: %d", - size, argsize(), closure._size, closure._sp - start_address(), sp(), stack_size()); - assert(argsize() == closure._argsize - (closure._num_frames > 0 ? frame::metadata_words_at_top : 0), - "argsize(): %d closure.argsize: %d closure.callee_interpreted: %d", - argsize(), closure._argsize, closure._callee_interpreted); + assert(closure._size <= size + (stack_size() - bottom()), + "size: %d bottom: %d closure.size: %d end sp: " PTR_FORMAT " start sp: %d chunk size: %d", + size, bottom(), closure._size, closure._sp - start_address(), sp(), stack_size()); + if (closure._num_frames > 0) { + assert(closure._argsize >= frame::metadata_words_at_top, "should be set up"); + assert(argsize() == closure._argsize - frame::metadata_words_at_top, + "argsize(): %d closure.argsize: %d closure.callee_interpreted: %d", + argsize(), closure._argsize, closure._callee_interpreted); + } int calculated_max_size = closure._size + closure._num_i2c * frame::align_wiggle diff --git a/src/hotspot/share/oops/stackChunkOop.hpp b/src/hotspot/share/oops/stackChunkOop.hpp index abfe47ad3f1..250acc8d165 100644 --- a/src/hotspot/share/oops/stackChunkOop.hpp +++ b/src/hotspot/share/oops/stackChunkOop.hpp @@ -101,6 +101,7 @@ class stackChunkOopDesc : public instanceOopDesc { inline void set_cont_access(oop value); inline int bottom() const; + inline void set_bottom(int value); inline HeapWord* start_of_stack() const; diff --git a/src/hotspot/share/oops/stackChunkOop.inline.hpp b/src/hotspot/share/oops/stackChunkOop.inline.hpp index 9bde7e255d2..eac86b8d0ec 100644 --- a/src/hotspot/share/oops/stackChunkOop.inline.hpp +++ b/src/hotspot/share/oops/stackChunkOop.inline.hpp @@ -60,15 +60,15 @@ inline void stackChunkOopDesc::set_parent_access(oop value) { jdk_internal_vm inline int stackChunkOopDesc::stack_size() const { return jdk_internal_vm_StackChunk::size(as_oop()); } +inline int stackChunkOopDesc::bottom() const { return jdk_internal_vm_StackChunk::bottom(as_oop()); } +inline void stackChunkOopDesc::set_bottom(int value) { jdk_internal_vm_StackChunk::set_bottom(this, value); } + inline int stackChunkOopDesc::sp() const { return jdk_internal_vm_StackChunk::sp(as_oop()); } inline void stackChunkOopDesc::set_sp(int value) { jdk_internal_vm_StackChunk::set_sp(this, value); } inline address stackChunkOopDesc::pc() const { return jdk_internal_vm_StackChunk::pc(as_oop()); } inline void stackChunkOopDesc::set_pc(address value) { jdk_internal_vm_StackChunk::set_pc(this, value); } -inline int stackChunkOopDesc::argsize() const { return jdk_internal_vm_StackChunk::argsize(as_oop()); } -inline void stackChunkOopDesc::set_argsize(int value) { jdk_internal_vm_StackChunk::set_argsize(as_oop(), value); } - inline uint8_t stackChunkOopDesc::flags() const { return jdk_internal_vm_StackChunk::flags(as_oop()); } inline void stackChunkOopDesc::set_flags(uint8_t value) { jdk_internal_vm_StackChunk::set_flags(this, value); } @@ -108,7 +108,10 @@ inline void stackChunkOopDesc::set_cont_raw(oop value) { jdk_internal_vm_Stac template inline void stackChunkOopDesc::set_cont_access(oop value) { jdk_internal_vm_StackChunk::set_cont_access(this, value); } -inline int stackChunkOopDesc::bottom() const { return stack_size() - argsize() - frame::metadata_words_at_top; } +inline int stackChunkOopDesc::argsize() const { + assert(!is_empty(), "should not ask for argsize in empty chunk"); + return stack_size() - bottom() - frame::metadata_words_at_top; +} inline HeapWord* stackChunkOopDesc::start_of_stack() const { return (HeapWord*)(cast_from_oop(as_oop()) + InstanceStackChunkKlass::offset_of_stack()); @@ -132,10 +135,8 @@ inline intptr_t* stackChunkOopDesc::from_offset(int offset) const { } inline bool stackChunkOopDesc::is_empty() const { - assert(sp() <= stack_size(), ""); - assert((sp() == stack_size()) == (sp() >= stack_size() - argsize() - frame::metadata_words_at_top), - "sp: %d size: %d argsize: %d", sp(), stack_size(), argsize()); - return sp() == stack_size(); + assert(sp() <= bottom(), ""); + return sp() == bottom(); } inline bool stackChunkOopDesc::is_in_chunk(void* p) const { @@ -200,7 +201,7 @@ inline void stackChunkOopDesc::iterate_stack(StackChunkFrameClosureType* closure template inline void stackChunkOopDesc::iterate_stack(StackChunkFrameClosureType* closure) { - const SmallRegisterMap* map = SmallRegisterMap::instance; + const SmallRegisterMap* map = SmallRegisterMap::instance(); assert(!map->in_cont(), ""); StackChunkFrameStream f(this); @@ -388,7 +389,7 @@ inline int stackChunkOopDesc::relativize_address(intptr_t* p) const { assert(start_address() <= p && p <= base, "start_address: " PTR_FORMAT " p: " PTR_FORMAT " base: " PTR_FORMAT, p2i(start_address()), p2i(p), p2i(base)); assert(0 <= offset && offset <= std::numeric_limits::max(), "offset: " PTR_FORMAT, offset); - return offset; + return (int)offset; } inline void stackChunkOopDesc::relativize_frame(frame& fr) const { diff --git a/src/hotspot/share/opto/arraycopynode.cpp b/src/hotspot/share/opto/arraycopynode.cpp index 71b7a7e5024..4e2b159bf8e 100644 --- a/src/hotspot/share/opto/arraycopynode.cpp +++ b/src/hotspot/share/opto/arraycopynode.cpp @@ -152,7 +152,10 @@ int ArrayCopyNode::get_count(PhaseGVN *phase) const { } Node* ArrayCopyNode::load(BarrierSetC2* bs, PhaseGVN *phase, Node*& ctl, MergeMemNode* mem, Node* adr, const TypePtr* adr_type, const Type *type, BasicType bt) { - DecoratorSet decorators = C2_READ_ACCESS | C2_CONTROL_DEPENDENT_LOAD | IN_HEAP | C2_ARRAY_COPY; + // Pin the load: if this is an array load, it's going to be dependent on a condition that's not a range check for that + // access. If that condition is replaced by an identical dominating one, then an unpinned load would risk floating + // above runtime checks that guarantee it is within bounds. + DecoratorSet decorators = C2_READ_ACCESS | C2_CONTROL_DEPENDENT_LOAD | IN_HEAP | C2_ARRAY_COPY | C2_UNKNOWN_CONTROL_LOAD; C2AccessValuePtr addr(adr, adr_type); C2OptAccess access(*phase, ctl, mem, decorators, bt, adr->in(AddPNode::Base), addr); Node* res = bs->load_at(access, type); diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index c88d5db5488..0579ce515f1 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -1082,13 +1082,14 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* const int receiver_skip = target->is_static() ? 0 : 1; // Cast receiver to its type. if (!target->is_static()) { - Node* arg = kit.argument(0); - const TypeOopPtr* arg_type = arg->bottom_type()->isa_oopptr(); - const Type* sig_type = TypeOopPtr::make_from_klass(signature->accessing_klass()); - if (arg_type != nullptr && !arg_type->higher_equal(sig_type)) { - const Type* recv_type = arg_type->filter_speculative(sig_type); // keep speculative part - Node* cast_obj = gvn.transform(new CheckCastPPNode(kit.control(), arg, recv_type)); - kit.set_argument(0, cast_obj); + Node* recv = kit.argument(0); + Node* casted_recv = kit.maybe_narrow_object_type(recv, signature->accessing_klass()); + if (casted_recv->is_top()) { + print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(), + "argument types mismatch"); + return nullptr; // FIXME: effectively dead; issue a halt node instead + } else if (casted_recv != recv) { + kit.set_argument(0, casted_recv); } } // Cast reference arguments to its type. @@ -1096,12 +1097,13 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* ciType* t = signature->type_at(i); if (t->is_klass()) { Node* arg = kit.argument(receiver_skip + j); - const TypeOopPtr* arg_type = arg->bottom_type()->isa_oopptr(); - const Type* sig_type = TypeOopPtr::make_from_klass(t->as_klass()); - if (arg_type != nullptr && !arg_type->higher_equal(sig_type)) { - const Type* narrowed_arg_type = arg_type->filter_speculative(sig_type); // keep speculative part - Node* cast_obj = gvn.transform(new CheckCastPPNode(kit.control(), arg, narrowed_arg_type)); - kit.set_argument(receiver_skip + j, cast_obj); + Node* casted_arg = kit.maybe_narrow_object_type(arg, t->as_klass()); + if (casted_arg->is_top()) { + print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(), + "argument types mismatch"); + return nullptr; // FIXME: effectively dead; issue a halt node instead + } else if (casted_arg != arg) { + kit.set_argument(receiver_skip + j, casted_arg); } } j += t->size(); // long and double take two slots diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index 1c84e77b6d9..f11311493b6 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1465,9 +1465,11 @@ SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp, Node* alloc, #endif uint first_index, + uint depth, uint n_fields) : TypeNode(tp, 1), // 1 control input -- seems required. Get from root. _first_index(first_index), + _depth(depth), _n_fields(n_fields) #ifdef ASSERT , _alloc(alloc) @@ -1913,6 +1915,22 @@ bool AbstractLockNode::find_unlocks_for_region(const RegionNode* region, LockNod } +// Check that all locks/unlocks associated with object come from balanced regions. +bool AbstractLockNode::is_balanced() { + Node* obj = obj_node(); + for (uint j = 0; j < obj->outcnt(); j++) { + Node* n = obj->raw_out(j); + if (n->is_AbstractLock() && + n->as_AbstractLock()->obj_node()->eqv_uncast(obj)) { + BoxLockNode* n_box = n->as_AbstractLock()->box_node()->as_BoxLock(); + if (n_box->is_unbalanced()) { + return false; + } + } + } + return true; +} + const char* AbstractLockNode::_kind_names[] = {"Regular", "NonEscObj", "Coarsened", "Nested"}; const char * AbstractLockNode::kind_as_string() const { @@ -1965,7 +1983,7 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) { // If we are locking an non-escaped object, the lock/unlock is unnecessary // ConnectionGraph *cgr = phase->C->congraph(); - if (cgr != nullptr && cgr->not_global_escape(obj_node())) { + if (cgr != nullptr && cgr->can_eliminate_lock(this)) { assert(!is_eliminated() || is_coarsened(), "sanity"); // The lock could be marked eliminated by lock coarsening // code during first IGVN before EA. Replace coarsened flag @@ -2019,6 +2037,8 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) { int unlocks = 0; if (Verbose) { tty->print_cr("=== Locks coarsening ==="); + tty->print("Obj: "); + obj_node()->dump(); } for (int i = 0; i < lock_ops.length(); i++) { AbstractLockNode* lock = lock_ops.at(i); @@ -2027,6 +2047,8 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) { else unlocks++; if (Verbose) { + tty->print("Box %d: ", i); + box_node()->dump(); tty->print(" %d: ", i); lock->dump(); } @@ -2128,6 +2150,7 @@ bool LockNode::is_nested_lock_region(Compile * c) { obj_node = bs->step_over_gc_barrier(obj_node); BoxLockNode* box_node = sfn->monitor_box(jvms, idx)->as_BoxLock(); if ((box_node->stack_slot() < stk_slot) && obj_node->eqv_uncast(obj)) { + box->set_nested(); return true; } } @@ -2161,7 +2184,7 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) { // If we are unlocking an non-escaped object, the lock/unlock is unnecessary. // ConnectionGraph *cgr = phase->C->congraph(); - if (cgr != nullptr && cgr->not_global_escape(obj_node())) { + if (cgr != nullptr && cgr->can_eliminate_lock(this)) { assert(!is_eliminated() || is_coarsened(), "sanity"); // The lock could be marked eliminated by lock coarsening // code during first IGVN before EA. Replace coarsened flag diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index e96c14411e3..3ac509859b6 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -509,7 +509,7 @@ class SafePointNode : public MultiNode { class SafePointScalarObjectNode: public TypeNode { uint _first_index; // First input edge relative index of a SafePoint node where // states of the scalarized object fields are collected. - // It is relative to the last (youngest) jvms->_scloff. + uint _depth; // Depth of the JVM state the _first_index field refers to uint _n_fields; // Number of non-static fields of the scalarized object. DEBUG_ONLY(Node* _alloc;) @@ -523,7 +523,7 @@ class SafePointScalarObjectNode: public TypeNode { #ifdef ASSERT Node* alloc, #endif - uint first_index, uint n_fields); + uint first_index, uint depth, uint n_fields); virtual int Opcode() const; virtual uint ideal_reg() const; virtual const RegMask &in_RegMask(uint) const; @@ -532,7 +532,7 @@ class SafePointScalarObjectNode: public TypeNode { uint first_index(JVMState* jvms) const { assert(jvms != nullptr, "missed JVMS"); - return jvms->scloff() + _first_index; + return jvms->of_depth(_depth)->scloff() + _first_index; } uint n_fields() const { return _n_fields; } @@ -1070,6 +1070,10 @@ class AbstractLockNode: public CallNode { void set_coarsened() { _kind = Coarsened; set_eliminated_lock_counter(); } void set_nested() { _kind = Nested; set_eliminated_lock_counter(); } + // Check that all locks/unlocks associated with object come from balanced regions. + // They can become unbalanced after coarsening optimization or on OSR entry. + bool is_balanced(); + // locking does not modify its arguments virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase){ return false; } diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 8a26d514b68..f46dda557c8 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -322,6 +322,15 @@ void CastIINode::dump_spec(outputStream* st) const { } #endif +CastIINode* CastIINode::pin_array_access_node() const { + assert(_dependency == RegularDependency, "already pinned"); + if (has_range_check()) { + return new CastIINode(in(0), in(1), bottom_type(), StrongDependency, has_range_check()); + } + return nullptr; +} + + const Type* CastLLNode::Value(PhaseGVN* phase) const { const Type* res = ConstraintCastNode::Value(phase); if (res == Type::TOP) { diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp index cbb1c5fe521..5de94f6963b 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -137,7 +137,7 @@ class CastIINode: public ConstraintCastNode { virtual Node* Identity(PhaseGVN* phase); virtual const Type* Value(PhaseGVN* phase) const; virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - const bool has_range_check() { + const bool has_range_check() const { #ifdef _LP64 return _range_check_dependency; #else @@ -146,6 +146,8 @@ class CastIINode: public ConstraintCastNode { #endif } + CastIINode* pin_array_access_node() const; + #ifndef PRODUCT virtual void dump_spec(outputStream* st) const; #endif diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index d71e7ff758a..2fc09b94288 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -428,7 +428,7 @@ class IfNode : public MultiBranchNode { virtual const RegMask &out_RegMask() const; Node* fold_compares(PhaseIterGVN* phase); static Node* up_one_dom(Node* curr, bool linear_only = false); - Node* dominated_by(Node* prev_dom, PhaseIterGVN* igvn); + Node* dominated_by(Node* prev_dom, PhaseIterGVN* igvn, bool pin_array_access_nodes); // Takes the type of val and filters it through the test represented // by if_proj and returns a more refined type if one is produced. @@ -479,6 +479,8 @@ class IfProjNode : public CProjNode { IfProjNode(IfNode *ifnode, uint idx) : CProjNode(ifnode,idx) {} virtual Node* Identity(PhaseGVN* phase); + void pin_array_access_nodes(PhaseIterGVN* igvn); + protected: // Type of If input when this branch is always taken virtual bool always_taken(const TypeTuple* t) const = 0; diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index e4a21db3a72..4dc0f31aba6 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -53,6 +53,7 @@ #include "opto/divnode.hpp" #include "opto/escape.hpp" #include "opto/idealGraphPrinter.hpp" +#include "opto/locknode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/macro.hpp" @@ -4811,10 +4812,26 @@ void Compile::add_coarsened_locks(GrowableArray& locks) { if (length > 0) { // Have to keep this list until locks elimination during Macro nodes elimination. Lock_List* locks_list = new (comp_arena()) Lock_List(comp_arena(), length); + AbstractLockNode* alock = locks.at(0); + BoxLockNode* box = alock->box_node()->as_BoxLock(); for (int i = 0; i < length; i++) { AbstractLockNode* lock = locks.at(i); assert(lock->is_coarsened(), "expecting only coarsened AbstractLock nodes, but got '%s'[%d] node", lock->Name(), lock->_idx); locks_list->push(lock); + BoxLockNode* this_box = lock->box_node()->as_BoxLock(); + if (this_box != box) { + // Locking regions (BoxLock) could be Unbalanced here: + // - its coarsened locks were eliminated in earlier + // macro nodes elimination followed by loop unroll + // - it is OSR locking region (no Lock node) + // Preserve Unbalanced status in such cases. + if (!this_box->is_unbalanced()) { + this_box->set_coarsened(); + } + if (!box->is_unbalanced()) { + box->set_coarsened(); + } + } } _coarsened_locks.append(locks_list); } @@ -4892,6 +4909,38 @@ bool Compile::coarsened_locks_consistent() { return true; } +// Mark locking regions (identified by BoxLockNode) as unbalanced if +// locks coarsening optimization removed Lock/Unlock nodes from them. +// Such regions become unbalanced because coarsening only removes part +// of Lock/Unlock nodes in region. As result we can't execute other +// locks elimination optimizations which assume all code paths have +// corresponding pair of Lock/Unlock nodes - they are balanced. +void Compile::mark_unbalanced_boxes() const { + int count = coarsened_count(); + for (int i = 0; i < count; i++) { + Node_List* locks_list = _coarsened_locks.at(i); + uint size = locks_list->size(); + if (size > 0) { + AbstractLockNode* alock = locks_list->at(0)->as_AbstractLock(); + BoxLockNode* box = alock->box_node()->as_BoxLock(); + if (alock->is_coarsened()) { + // coarsened_locks_consistent(), which is called before this method, verifies + // that the rest of Lock/Unlock nodes on locks_list are also coarsened. + assert(!box->is_eliminated(), "regions with coarsened locks should not be marked as eliminated"); + for (uint j = 1; j < size; j++) { + assert(locks_list->at(j)->as_AbstractLock()->is_coarsened(), "only coarsened locks are expected here"); + BoxLockNode* this_box = locks_list->at(j)->as_AbstractLock()->box_node()->as_BoxLock(); + if (box != this_box) { + assert(!this_box->is_eliminated(), "regions with coarsened locks should not be marked as eliminated"); + box->set_unbalanced(); + this_box->set_unbalanced(); + } + } + } + } + } +} + /** * Remove the speculative part of types and clean up the graph */ diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index c843ed27faf..0c8df77cce2 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -742,6 +742,7 @@ class Compile : public Phase { void add_coarsened_locks(GrowableArray& locks); void remove_coarsened_lock(Node* n); bool coarsened_locks_consistent(); + void mark_unbalanced_boxes() const; bool post_loop_opts_phase() { return _post_loop_opts_phase; } void set_post_loop_opts_phase() { _post_loop_opts_phase = true; } diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index 401cb35e227..c852316f85e 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -790,46 +790,47 @@ void Parse::catch_call_exceptions(ciExceptionHandlerStream& handlers) { Node* i_o = this->i_o(); // Add a CatchNode. - GrowableArray* bcis = new (C->node_arena()) GrowableArray(C->node_arena(), 8, 0, -1); - GrowableArray* extypes = new (C->node_arena()) GrowableArray(C->node_arena(), 8, 0, nullptr); - GrowableArray* saw_unloaded = new (C->node_arena()) GrowableArray(C->node_arena(), 8, 0, 0); + Arena tmp_mem{mtCompiler}; + GrowableArray bcis(&tmp_mem, 8, 0, -1); + GrowableArray extypes(&tmp_mem, 8, 0, nullptr); + GrowableArray saw_unloaded(&tmp_mem, 8, 0, -1); bool default_handler = false; for (; !handlers.is_done(); handlers.next()) { - ciExceptionHandler* h = handlers.handler(); - int h_bci = h->handler_bci(); - ciInstanceKlass* h_klass = h->is_catch_all() ? env()->Throwable_klass() : h->catch_klass(); + ciExceptionHandler* h = handlers.handler(); + int h_bci = h->handler_bci(); + ciInstanceKlass* h_klass = h->is_catch_all() ? env()->Throwable_klass() : h->catch_klass(); // Do not introduce unloaded exception types into the graph: if (!h_klass->is_loaded()) { - if (saw_unloaded->contains(h_bci)) { + if (saw_unloaded.contains(h_bci)) { /* We've already seen an unloaded exception with h_bci, so don't duplicate. Duplication will cause the CatchNode to be unnecessarily large. See 4713716. */ continue; } else { - saw_unloaded->append(h_bci); + saw_unloaded.append(h_bci); } } - const Type* h_extype = TypeOopPtr::make_from_klass(h_klass); + const Type* h_extype = TypeOopPtr::make_from_klass(h_klass); // (We use make_from_klass because it respects UseUniqueSubclasses.) h_extype = h_extype->join(TypeInstPtr::NOTNULL); assert(!h_extype->empty(), "sanity"); - // Note: It's OK if the BCIs repeat themselves. - bcis->append(h_bci); - extypes->append(h_extype); + // Note: It's OK if the BCIs repeat themselves. + bcis.append(h_bci); + extypes.append(h_extype); if (h_bci == -1) { default_handler = true; } } if (!default_handler) { - bcis->append(-1); + bcis.append(-1); const Type* extype = TypeOopPtr::make_from_klass(env()->Throwable_klass())->is_instptr(); extype = extype->join(TypeInstPtr::NOTNULL); - extypes->append(extype); + extypes.append(extype); } - int len = bcis->length(); + int len = bcis.length(); CatchNode *cn = new CatchNode(control(), i_o, len+1); Node *catch_ = _gvn.transform(cn); @@ -840,18 +841,18 @@ void Parse::catch_call_exceptions(ciExceptionHandlerStream& handlers) { PreserveJVMState pjvms(this); // Locals are just copied from before the call. // Get control from the CatchNode. - int handler_bci = bcis->at(i); + int handler_bci = bcis.at(i); Node* ctrl = _gvn.transform( new CatchProjNode(catch_, i+1,handler_bci)); // This handler cannot happen? if (ctrl == top()) continue; set_control(ctrl); // Create exception oop - const TypeInstPtr* extype = extypes->at(i)->is_instptr(); - Node *ex_oop = _gvn.transform(new CreateExNode(extypes->at(i), ctrl, i_o)); + const TypeInstPtr* extype = extypes.at(i)->is_instptr(); + Node* ex_oop = _gvn.transform(new CreateExNode(extypes.at(i), ctrl, i_o)); // Handle unloaded exception classes. - if (saw_unloaded->contains(handler_bci)) { + if (saw_unloaded.contains(handler_bci)) { // An unloaded exception type is coming here. Do an uncommon trap. #ifndef PRODUCT // We do not expect the same handler bci to take both cold unloaded diff --git a/src/hotspot/share/opto/domgraph.cpp b/src/hotspot/share/opto/domgraph.cpp index db7181697e8..42cd5f4a58c 100644 --- a/src/hotspot/share/opto/domgraph.cpp +++ b/src/hotspot/share/opto/domgraph.cpp @@ -384,6 +384,25 @@ struct NTarjan { #endif }; +void remove_single_entry_region(NTarjan* t, NTarjan*& tdom, Node*& dom, PhaseIterGVN& igvn) { + // remove phis: + for (DUIterator_Fast jmax, j = dom->fast_outs(jmax); j < jmax; j++) { + Node* use = dom->fast_out(j); + if (use->is_Phi()) { + igvn.replace_node(use, use->in(1)); + --j; --jmax; + } + } + // Disconnect region from dominator tree + assert(dom->unique_ctrl_out() == t->_control, "expect a single dominated node"); + tdom = tdom->_dom; + t->_dom = tdom; + assert(tdom->_control == dom->in(1), "dominator of region with single input should be that input"); + // and remove it + igvn.replace_node(dom, dom->in(1)); + dom = tdom->_control; +} + // Compute the dominator tree of the sea of nodes. This version walks all CFG // nodes (using the is_CFG() call) and places them in a dominator tree. Thus, // it needs a count of the CFG nodes for the mapping table. This is the @@ -486,7 +505,14 @@ void PhaseIdealLoop::Dominators() { assert(t->_control != nullptr,"Bad DFS walk"); NTarjan *tdom = t->_dom; // Handy access to immediate dominator if( tdom ) { // Root has no immediate dominator - _idom[t->_control->_idx] = tdom->_control; // Set immediate dominator + Node* dom = tdom->_control; + // The code that removes unreachable loops above could have left a region with a single input. Remove it. Do it + // now that we iterate over cfg nodes for the last time (doing it earlier would have left a dead cfg node behind + // that code that goes over the dfs list would have had to handle). + if (dom != C->root() && dom->is_Region() && dom->req() == 2) { + remove_single_entry_region(t, tdom, dom, _igvn); + } + _idom[t->_control->_idx] = dom; // Set immediate dominator t->_dom_next = tdom->_dom_child; // Make me a sibling of parent's child tdom->_dom_child = t; // Make me a child of my parent } else diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 0b4b7ff43f2..21d32f76c2b 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -36,6 +36,7 @@ #include "opto/cfgnode.hpp" #include "opto/compile.hpp" #include "opto/escape.hpp" +#include "opto/locknode.hpp" #include "opto/phaseX.hpp" #include "opto/movenode.hpp" #include "opto/rootnode.hpp" @@ -2097,7 +2098,7 @@ void ConnectionGraph::optimize_ideal_graph(GrowableArray& ptr_cmp_worklis if (n->is_AbstractLock()) { // Lock and Unlock nodes AbstractLockNode* alock = n->as_AbstractLock(); if (!alock->is_non_esc_obj()) { - if (not_global_escape(alock->obj_node())) { + if (can_eliminate_lock(alock)) { assert(!alock->is_eliminated() || alock->is_coarsened(), "sanity"); // The lock could be marked eliminated by lock coarsening // code during first IGVN before EA. Replace coarsened flag @@ -2430,6 +2431,20 @@ bool ConnectionGraph::not_global_escape(Node *n) { return true; } +// Return true if locked object does not escape globally +// and locked code region (identified by BoxLockNode) is balanced: +// all compiled code paths have corresponding Lock/Unlock pairs. +bool ConnectionGraph::can_eliminate_lock(AbstractLockNode* alock) { + if (alock->is_balanced() && not_global_escape(alock->obj_node())) { + if (EliminateNestedLocks) { + // We can mark whole locking region as Local only when only + // one object is used for locking. + alock->box_node()->as_BoxLock()->set_local(); + } + return true; + } + return false; +} // Helper functions @@ -3515,6 +3530,13 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, if (n == nullptr) { continue; } + } else if (n->is_CallLeaf()) { + // Runtime calls with narrow memory input (no MergeMem node) + // get the memory projection + n = n->as_Call()->proj_out_or_null(TypeFunc::Memory); + if (n == nullptr) { + continue; + } } else if (n->Opcode() == Op_StrCompressedCopy || n->Opcode() == Op_EncodeISOArray) { // get the memory projection @@ -3557,7 +3579,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, continue; } memnode_worklist.append_if_missing(use); - } else if (use->is_MemBar()) { + } else if (use->is_MemBar() || use->is_CallLeaf()) { if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge memnode_worklist.append_if_missing(use); } diff --git a/src/hotspot/share/opto/escape.hpp b/src/hotspot/share/opto/escape.hpp index 7f11d3ac9ca..e6e8b0d9a20 100644 --- a/src/hotspot/share/opto/escape.hpp +++ b/src/hotspot/share/opto/escape.hpp @@ -112,6 +112,7 @@ class Compile; class Node; +class AbstractLockNode; class CallNode; class PhiNode; class PhaseTransform; @@ -607,6 +608,8 @@ class ConnectionGraph: public ArenaObj { bool not_global_escape(Node *n); + bool can_eliminate_lock(AbstractLockNode* alock); + // To be used by, e.g., BarrierSetC2 impls Node* get_addp_base(Node* addp); diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 53454cfdece..391995139f2 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3432,7 +3432,10 @@ FastLockNode* GraphKit::shared_lock(Node* obj) { assert(dead_locals_are_killed(), "should kill locals before sync. point"); // Box the stack location - Node* box = _gvn.transform(new BoxLockNode(next_monitor())); + Node* box = new BoxLockNode(next_monitor()); + // Check for bailout after new BoxLockNode + if (failing()) { return nullptr; } + box = _gvn.transform(box); Node* mem = reset_memory(); FastLockNode * flock = _gvn.transform(new FastLockNode(0, obj, box) )->as_FastLock(); @@ -4218,3 +4221,14 @@ Node* GraphKit::make_constant_from_field(ciField* field, Node* obj) { } return nullptr; } + +Node* GraphKit::maybe_narrow_object_type(Node* obj, ciKlass* type) { + const TypeOopPtr* obj_type = obj->bottom_type()->isa_oopptr(); + const TypeOopPtr* sig_type = TypeOopPtr::make_from_klass(type); + if (obj_type != nullptr && sig_type->is_loaded() && !obj_type->higher_equal(sig_type)) { + const Type* narrow_obj_type = obj_type->filter_speculative(sig_type); // keep speculative part + Node* casted_obj = gvn().transform(new CheckCastPPNode(control(), obj, narrow_obj_type)); + return casted_obj; + } + return obj; +} diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index 92180371c06..399aa9ac07f 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -441,6 +441,8 @@ class GraphKit : public Phase { // Replace all occurrences of one node by another. void replace_in_map(Node* old, Node* neww); + Node* maybe_narrow_object_type(Node* obj, ciKlass* type); + void push(Node* n) { map_not_null(); _map->set_stack(_map->_jvms, _sp++ , n); } Node* pop() { map_not_null(); return _map->stack( _map->_jvms, --_sp ); } Node* peek(int off = 0) { map_not_null(); return _map->stack( _map->_jvms, _sp - off - 1 ); } diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index bd2e7e36262..f9875d5ef9f 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -143,21 +143,24 @@ void IdealGraphPrinter::init(const char* file_name, bool use_multiple_files, boo _depth = 0; _current_method = nullptr; _network_stream = nullptr; + _append = append; if (file_name != nullptr) { - init_file_stream(file_name, use_multiple_files, append); + init_file_stream(file_name, use_multiple_files); } else { init_network_stream(); } _xml = new (mtCompiler) xmlStream(_output); - if (!append) { + if (!_append) { head(TOP_ELEMENT); } } // Destructor, close file or network stream IdealGraphPrinter::~IdealGraphPrinter() { - tail(TOP_ELEMENT); + if (!_append) { + tail(TOP_ELEMENT); + } // tty->print_cr("Walk time: %d", (int)_walk_time.milliseconds()); // tty->print_cr("Output time: %d", (int)_output_time.milliseconds()); @@ -830,10 +833,10 @@ void IdealGraphPrinter::print(const char *name, Node *node) { _xml->flush(); } -void IdealGraphPrinter::init_file_stream(const char* file_name, bool use_multiple_files, bool append) { +void IdealGraphPrinter::init_file_stream(const char* file_name, bool use_multiple_files) { ThreadCritical tc; if (use_multiple_files && _file_count != 0) { - assert(!append, "append should only be used for debugging with a single file"); + assert(!_append, "append should only be used for debugging with a single file"); ResourceMark rm; stringStream st; const char* dot = strrchr(file_name, '.'); @@ -845,10 +848,10 @@ void IdealGraphPrinter::init_file_stream(const char* file_name, bool use_multipl } _output = new (mtCompiler) fileStream(st.as_string(), "w"); } else { - _output = new (mtCompiler) fileStream(file_name, append ? "a" : "w"); + _output = new (mtCompiler) fileStream(file_name, _append ? "a" : "w"); } if (use_multiple_files) { - assert(!append, "append should only be used for debugging with a single file"); + assert(!_append, "append should only be used for debugging with a single file"); _file_count++; } } @@ -879,9 +882,16 @@ void IdealGraphPrinter::update_compiled_method(ciMethod* current_method) { assert(C != nullptr, "must already be set"); if (current_method != _current_method) { // If a different method, end the old and begin with the new one. - end_method(); - _current_method = nullptr; - begin_method(); + if (_append) { + // Do not call `end_method` if we are appending, just update `_current_method`, + // because `begin_method` is not called in the constructor in append mode. + _current_method = current_method; + } else { + // End the old method and begin a new one. + // Don't worry about `_current_method`, `end_method` will clear it. + end_method(); + begin_method(); + } } } diff --git a/src/hotspot/share/opto/idealGraphPrinter.hpp b/src/hotspot/share/opto/idealGraphPrinter.hpp index 091560d9231..fdc3e4881f5 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.hpp +++ b/src/hotspot/share/opto/idealGraphPrinter.hpp @@ -95,6 +95,7 @@ class IdealGraphPrinter : public CHeapObj { bool _traverse_outs; Compile *C; double _max_freq; + bool _append; void print_method(ciMethod *method, int bci, InlineTree *tree); void print_inline_tree(InlineTree *tree); @@ -116,7 +117,7 @@ class IdealGraphPrinter : public CHeapObj { void head(const char *name); void text(const char *s); void init(const char* file_name, bool use_multiple_files, bool append); - void init_file_stream(const char* file_name, bool use_multiple_files, bool append); + void init_file_stream(const char* file_name, bool use_multiple_files); void init_network_stream(); IdealGraphPrinter(); ~IdealGraphPrinter(); diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index dc03ebe31ac..f63f4ae8002 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -537,7 +537,7 @@ int RangeCheckNode::is_range_check(Node* &range, Node* &index, jint &offset) { //------------------------------adjust_check----------------------------------- // Adjust (widen) a prior range check -static void adjust_check(Node* proj, Node* range, Node* index, +static void adjust_check(IfProjNode* proj, Node* range, Node* index, int flip, jint off_lo, PhaseIterGVN* igvn) { PhaseGVN *gvn = igvn; // Break apart the old check @@ -545,25 +545,31 @@ static void adjust_check(Node* proj, Node* range, Node* index, Node *bol = iff->in(1); if( bol->is_top() ) return; // In case a partially dead range check appears // bail (or bomb[ASSERT/DEBUG]) if NOT projection-->IfNode-->BoolNode - DEBUG_ONLY( if( !bol->is_Bool() ) { proj->dump(3); fatal("Expect projection-->IfNode-->BoolNode"); } ) - if( !bol->is_Bool() ) return; + DEBUG_ONLY( if (!bol->is_Bool()) { proj->dump(3); fatal("Expect projection-->IfNode-->BoolNode"); } ) + if (!bol->is_Bool()) return; Node *cmp = bol->in(1); // Compute a new check Node *new_add = gvn->intcon(off_lo); - if( index ) { - new_add = off_lo ? gvn->transform(new AddINode( index, new_add )) : index; + if (index) { + new_add = off_lo ? gvn->transform(new AddINode(index, new_add)) : index; } Node *new_cmp = (flip == 1) - ? new CmpUNode( new_add, range ) - : new CmpUNode( range, new_add ); + ? new CmpUNode(new_add, range) + : new CmpUNode(range, new_add); new_cmp = gvn->transform(new_cmp); // See if no need to adjust the existing check - if( new_cmp == cmp ) return; + if (new_cmp == cmp) return; // Else, adjust existing check - Node *new_bol = gvn->transform( new BoolNode( new_cmp, bol->as_Bool()->_test._test ) ); - igvn->rehash_node_delayed( iff ); - iff->set_req_X( 1, new_bol, igvn ); + Node* new_bol = gvn->transform(new BoolNode(new_cmp, bol->as_Bool()->_test._test)); + igvn->rehash_node_delayed(iff); + iff->set_req_X(1, new_bol, igvn); + // As part of range check smearing, this range check is widened. Loads and range check Cast nodes that are control + // dependent on this range check now depend on multiple dominating range checks. These control dependent nodes end up + // at the lowest/nearest dominating check in the graph. To ensure that these Loads/Casts do not float above any of the + // dominating checks (even when the lowest dominating check is later replaced by yet another dominating check), we + // need to pin them at the lowest dominating check. + proj->pin_array_access_nodes(igvn); } //------------------------------up_one_dom------------------------------------- @@ -1030,6 +1036,10 @@ bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* f } hook->destruct(igvn); + if (adjusted_val->is_top() || adjusted_lim->is_top()) { + return false; + } + int lo = igvn->type(adjusted_lim)->is_int()->_lo; if (lo < 0) { // If range check elimination applies to this comparison, it includes code to protect from overflows that may @@ -1417,7 +1427,7 @@ static Node *remove_useless_bool(IfNode *iff, PhaseGVN *phase) { static IfNode* idealize_test(PhaseGVN* phase, IfNode* iff); struct RangeCheck { - Node* ctl; + IfProjNode* ctl; jint off; }; @@ -1485,14 +1495,14 @@ Node* IfNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (prev_dom != nullptr) { // Replace dominated IfNode - return dominated_by(prev_dom, igvn); + return dominated_by(prev_dom, igvn, false); } return simple_subsuming(igvn); } //------------------------------dominated_by----------------------------------- -Node* IfNode::dominated_by(Node* prev_dom, PhaseIterGVN *igvn) { +Node* IfNode::dominated_by(Node* prev_dom, PhaseIterGVN* igvn, bool pin_array_access_nodes) { #ifndef PRODUCT if (TraceIterativeGVN) { tty->print(" Removing IfNode: "); this->dump(); @@ -1505,15 +1515,6 @@ Node* IfNode::dominated_by(Node* prev_dom, PhaseIterGVN *igvn) { int prev_op = prev_dom->Opcode(); Node *top = igvn->C->top(); // Shortcut to top - // Loop predicates may have depending checks which should not - // be skipped. For example, range check predicate has two checks - // for lower and upper bounds. - ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj(); - if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != nullptr || - unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_profile_predicate) != nullptr) { - prev_dom = idom; - } - // Now walk the current IfNode's projections. // Loop ends when 'this' has no more uses. for (DUIterator_Last imin, i = last_outs(imin); i >= imin; --i) { @@ -1536,6 +1537,19 @@ Node* IfNode::dominated_by(Node* prev_dom, PhaseIterGVN *igvn) { // For control producers. // Do not rewire Div and Mod nodes which could have a zero divisor to avoid skipping their zero check. igvn->replace_input_of(s, 0, data_target); // Move child to data-target + if (pin_array_access_nodes && data_target != top) { + // As a result of range check smearing, Loads and range check Cast nodes that are control dependent on this + // range check (that is about to be removed) now depend on multiple dominating range checks. After the removal + // of this range check, these control dependent nodes end up at the lowest/nearest dominating check in the + // graph. To ensure that these Loads/Casts do not float above any of the dominating checks (even when the + // lowest dominating check is later replaced by yet another dominating check), we need to pin them at the + // lowest dominating check. + Node* clone = s->pin_array_access_node(); + if (clone != nullptr) { + clone = igvn->transform(clone); + igvn->replace_node(s, clone); + } + } } else { // Find the control input matching this def-use edge. // For Regions it may not be in slot 0. @@ -1743,6 +1757,22 @@ Node* IfProjNode::Identity(PhaseGVN* phase) { return this; } +void IfProjNode::pin_array_access_nodes(PhaseIterGVN* igvn) { + for (DUIterator i = outs(); has_out(i); i++) { + Node* u = out(i); + if (!u->depends_only_on_test()) { + continue; + } + Node* clone = u->pin_array_access_node(); + if (clone != nullptr) { + clone = igvn->transform(clone); + assert(clone != u, "shouldn't common"); + igvn->replace_node(u, clone); + --i; + } + } +} + #ifndef PRODUCT //------------------------------dump_spec-------------------------------------- void IfNode::dump_spec(outputStream *st) const { @@ -1916,7 +1946,7 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { off_lo = MIN2(off_lo, offset2); off_hi = MAX2(off_hi, offset2); // Record top NRC range checks - prev_checks[nb_checks % NRC].ctl = prev_dom; + prev_checks[nb_checks % NRC].ctl = prev_dom->as_IfProj(); prev_checks[nb_checks % NRC].off = offset2; nb_checks++; } @@ -1934,6 +1964,15 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { // the interpreter. If we see range-check deopt's, do not widen! if (!phase->C->allow_range_check_smearing()) return nullptr; + if (can_reshape && !phase->C->post_loop_opts_phase()) { + // We are about to perform range check smearing (i.e. remove this RangeCheck if it is dominated by + // a series of RangeChecks which have a range that covers this RangeCheck). This can cause array access nodes to + // be pinned. We want to avoid that and first allow range check elimination a chance to remove the RangeChecks + // from loops. Hence, we delay range check smearing until after loop opts. + phase->C->record_for_post_loop_opts_igvn(this); + return nullptr; + } + // Didn't find prior covering check, so cannot remove anything. if (nb_checks == 0) { return nullptr; @@ -2007,6 +2046,26 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { // Test is now covered by prior checks, dominate it out prev_dom = rc0.ctl; } + // The last RangeCheck is found to be redundant with a sequence of n (n >= 2) preceding RangeChecks. + // If an array load is control dependent on the eliminated range check, the array load nodes (CastII and Load) + // become control dependent on the last range check of the sequence, but they are really dependent on the entire + // sequence of RangeChecks. If RangeCheck#n is later replaced by a dominating identical check, the array load + // nodes must not float above the n-1 other RangeCheck in the sequence. We pin the array load nodes here to + // guarantee it doesn't happen. + // + // RangeCheck#1 RangeCheck#1 + // | \ | \ + // | uncommon trap | uncommon trap + // .. .. + // RangeCheck#n -> RangeCheck#n + // | \ | \ + // | uncommon trap CastII uncommon trap + // RangeCheck Load + // | \ + // CastII uncommon trap + // Load + + return dominated_by(prev_dom, igvn, true); } } else { prev_dom = search_identical(4); @@ -2017,7 +2076,7 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { } // Replace dominated IfNode - return dominated_by(prev_dom, igvn); + return dominated_by(prev_dom, igvn, false); } ParsePredicateNode::ParsePredicateNode(Node* control, Node* bol, Deoptimization::DeoptReason deopt_reason) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 0b1d0f5b0f2..5f95b96fa43 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4272,12 +4272,16 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) { length = _gvn.transform(new SubINode(end, start)); } - // Bail out if length is negative. + // Bail out if length is negative (i.e., if start > end). // Without this the new_array would throw // NegativeArraySizeException but IllegalArgumentException is what // should be thrown generate_negative_guard(length, bailout, &length); + // Bail out if start is larger than the original length + Node* orig_tail = _gvn.transform(new SubINode(orig_length, start)); + generate_negative_guard(orig_tail, bailout, &orig_tail); + if (bailout->req() > 1) { PreserveJVMState pjvms(this); set_control(_gvn.transform(bailout)); @@ -4287,8 +4291,7 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) { if (!stopped()) { // How many elements will we copy from the original? - // The answer is MinI(orig_length - start, length). - Node* orig_tail = _gvn.transform(new SubINode(orig_length, start)); + // The answer is MinI(orig_tail, length). Node* moved = generate_min_max(vmIntrinsics::_min, orig_tail, length); // Generate a direct call to the right arraycopy function(s). @@ -4336,7 +4339,7 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) { if (!stopped()) { newcopy = new_array(klass_node, length, 0); // no arguments to push - ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, true, false, + ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, true, true, load_object_klass(original), klass_node); if (!is_copyOfRange) { ac->set_copyof(validated); @@ -4516,14 +4519,22 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { Node* no_ctrl = nullptr; Node* header = make_load(no_ctrl, header_addr, TypeX_X, TypeX_X->basic_type(), MemNode::unordered); - // Test the header to see if it is unlocked. + // Test the header to see if it is safe to read w.r.t. locking. Node *lock_mask = _gvn.MakeConX(markWord::lock_mask_in_place); Node *lmasked_header = _gvn.transform(new AndXNode(header, lock_mask)); - Node *unlocked_val = _gvn.MakeConX(markWord::unlocked_value); - Node *chk_unlocked = _gvn.transform(new CmpXNode( lmasked_header, unlocked_val)); - Node *test_unlocked = _gvn.transform(new BoolNode( chk_unlocked, BoolTest::ne)); + if (LockingMode == LM_LIGHTWEIGHT) { + Node *monitor_val = _gvn.MakeConX(markWord::monitor_value); + Node *chk_monitor = _gvn.transform(new CmpXNode(lmasked_header, monitor_val)); + Node *test_monitor = _gvn.transform(new BoolNode(chk_monitor, BoolTest::eq)); + + generate_slow_guard(test_monitor, slow_region); + } else { + Node *unlocked_val = _gvn.MakeConX(markWord::unlocked_value); + Node *chk_unlocked = _gvn.transform(new CmpXNode(lmasked_header, unlocked_val)); + Node *test_not_unlocked = _gvn.transform(new BoolNode(chk_unlocked, BoolTest::ne)); - generate_slow_guard(test_unlocked, slow_region); + generate_slow_guard(test_not_unlocked, slow_region); + } // Get the hash value and check to see that it has been properly assigned. // We depend on hash_mask being at most 32 bits and avoid the use of @@ -4892,7 +4903,13 @@ void LibraryCallKit::copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, b assert(alloc_obj->is_CheckCastPP() && raw_obj->is_Proj() && raw_obj->in(0)->is_Allocate(), ""); AllocateNode* alloc = nullptr; - if (ReduceBulkZeroing) { + if (ReduceBulkZeroing && + // If we are implementing an array clone without knowing its source type + // (can happen when compiling the array-guarded branch of a reflective + // Object.clone() invocation), initialize the array within the allocation. + // This is needed because some GCs (e.g. ZGC) might fall back in this case + // to a runtime clone call that assumes fully initialized source arrays. + (!is_array || obj->get_ptr_type()->isa_aryptr() != nullptr)) { // We will be completely responsible for initializing this object - // mark Initialize node as complete. alloc = AllocateNode::Ideal_allocation(alloc_obj, &_gvn); diff --git a/src/hotspot/share/opto/locknode.cpp b/src/hotspot/share/opto/locknode.cpp index 640109e6c42..71b4efec7f7 100644 --- a/src/hotspot/share/opto/locknode.cpp +++ b/src/hotspot/share/opto/locknode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,26 +40,59 @@ const RegMask &BoxLockNode::out_RegMask() const { uint BoxLockNode::size_of() const { return sizeof(*this); } BoxLockNode::BoxLockNode( int slot ) : Node( Compile::current()->root() ), - _slot(slot), _is_eliminated(false) { + _slot(slot), _kind(BoxLockNode::Regular) { init_class_id(Class_BoxLock); init_flags(Flag_rematerialize); OptoReg::Name reg = OptoReg::stack2reg(_slot); + if (!RegMask::can_represent(reg, Compile::current()->sync_stack_slots())) { + Compile::current()->record_method_not_compilable("must be able to represent all monitor slots in reg mask"); + return; + } _inmask.Insert(reg); } -//-----------------------------hash-------------------------------------------- uint BoxLockNode::hash() const { - if (EliminateNestedLocks) + if (EliminateNestedLocks) { return NO_HASH; // Each locked region has own BoxLock node - return Node::hash() + _slot + (_is_eliminated ? Compile::current()->fixed_slots() : 0); + } + return Node::hash() + _slot + (is_eliminated() ? Compile::current()->fixed_slots() : 0); } -//------------------------------cmp-------------------------------------------- bool BoxLockNode::cmp( const Node &n ) const { - if (EliminateNestedLocks) + if (EliminateNestedLocks) { return (&n == this); // Always fail except on self + } const BoxLockNode &bn = (const BoxLockNode &)n; - return bn._slot == _slot && bn._is_eliminated == _is_eliminated; + return (bn._slot == _slot) && (bn.is_eliminated() == is_eliminated()); +} + +Node* BoxLockNode::Identity(PhaseGVN* phase) { + if (!EliminateNestedLocks && !this->is_eliminated()) { + Node* n = phase->hash_find(this); + if (n == nullptr || n == this) { + return this; + } + BoxLockNode* old_box = n->as_BoxLock(); + // Set corresponding status (_kind) when commoning BoxLock nodes. + if (this->_kind != old_box->_kind) { + if (this->is_unbalanced()) { + old_box->set_unbalanced(); + } + if (!old_box->is_unbalanced()) { + // Only Regular or Coarsened status should be here: + // Nested and Local are set only when EliminateNestedLocks is on. + if (old_box->is_regular()) { + assert(this->is_coarsened(),"unexpected kind: %s", _kind_name[(int)this->_kind]); + old_box->set_coarsened(); + } else { + assert(this->is_regular(),"unexpected kind: %s", _kind_name[(int)this->_kind]); + assert(old_box->is_coarsened(),"unexpected kind: %s", _kind_name[(int)old_box->_kind]); + } + } + } + return old_box; + } + return this; } BoxLockNode* BoxLockNode::box_node(Node* box) { @@ -86,6 +119,9 @@ OptoReg::Name BoxLockNode::reg(Node* box) { // Is BoxLock node used for one simple lock region (same box and obj)? bool BoxLockNode::is_simple_lock_region(LockNode** unique_lock, Node* obj, Node** bad_lock) { + if (is_unbalanced()) { + return false; + } LockNode* lock = nullptr; bool has_one_lock = false; for (uint i = 0; i < this->outcnt(); i++) { diff --git a/src/hotspot/share/opto/locknode.hpp b/src/hotspot/share/opto/locknode.hpp index 4a74e50425f..05e87a93b39 100644 --- a/src/hotspot/share/opto/locknode.hpp +++ b/src/hotspot/share/opto/locknode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,37 @@ class RTMLockingCounters; //------------------------------BoxLockNode------------------------------------ class BoxLockNode : public Node { +private: const int _slot; // stack slot RegMask _inmask; // OptoReg corresponding to stack slot - bool _is_eliminated; // Associated locks were safely eliminated + enum { + Regular = 0, // Normal locking region + Local, // EA found that local not escaping object is used for locking + Nested, // This region is inside other region which use the same object + Coarsened, // Some lock/unlock in region were marked as coarsened + Unbalanced, // This region become unbalanced after coarsened lock/unlock were eliminated + // or it is locking region from OSR when locking is done in Interpreter + Eliminated // All lock/unlock in region were eliminated + } _kind; + +#ifndef PRODUCT + const char* _kind_name[6] = { + "Regular", + "Local", + "Nested", + "Coarsened", + "Unbalanced", + "Eliminated" + }; +#endif + + // Allowed transitions of _kind: + // Regular -> Local, Nested, Coarsened + // Local -> Eliminated + // Nested -> Eliminated + // Coarsened -> Local, Nested, Unbalanced + // EA and nested lock elimination can overwrite Coarsened kind. + // Also allow transition to the same kind. public: BoxLockNode( int lock ); @@ -49,6 +77,7 @@ class BoxLockNode : public Node { virtual bool cmp( const Node &n ) const; virtual const class Type *bottom_type() const { return TypeRawPtr::BOTTOM; } virtual uint ideal_reg() const { return Op_RegP; } + virtual Node* Identity(PhaseGVN* phase); static OptoReg::Name reg(Node* box_node); static BoxLockNode* box_node(Node* box_node); @@ -57,16 +86,47 @@ class BoxLockNode : public Node { } int stack_slot() const { return _slot; } - bool is_eliminated() const { return _is_eliminated; } - // mark lock as eliminated. - void set_eliminated() { _is_eliminated = true; } + bool is_regular() const { return _kind == Regular; } + bool is_local() const { return _kind == Local; } + bool is_nested() const { return _kind == Nested; } + bool is_coarsened() const { return _kind == Coarsened; } + bool is_eliminated() const { return _kind == Eliminated; } + bool is_unbalanced() const { return _kind == Unbalanced; } + + void set_local() { + assert((_kind == Regular || _kind == Local || _kind == Coarsened), + "incorrect kind for Local transitioni: %s", _kind_name[(int)_kind]); + _kind = Local; + } + void set_nested() { + assert((_kind == Regular || _kind == Nested || _kind == Coarsened), + "incorrect kind for Nested transition: %s", _kind_name[(int)_kind]); + _kind = Nested; + } + void set_coarsened() { + assert((_kind == Regular || _kind == Coarsened), + "incorrect kind for Coarsened transition: %s", _kind_name[(int)_kind]); + _kind = Coarsened; + } + void set_eliminated() { + assert((_kind == Local || _kind == Nested), + "incorrect kind for Eliminated transition: %s", _kind_name[(int)_kind]); + _kind = Eliminated; + } + void set_unbalanced() { + assert((_kind == Coarsened || _kind == Unbalanced), + "incorrect kind for Unbalanced transition: %s", _kind_name[(int)_kind]); + _kind = Unbalanced; + } // Is BoxLock node used for one simple lock region? bool is_simple_lock_region(LockNode** unique_lock, Node* obj, Node** bad_lock); #ifndef PRODUCT virtual void format( PhaseRegAlloc *, outputStream *st ) const; - virtual void dump_spec(outputStream *st) const { st->print(" Lock %d",_slot); } + virtual void dump_spec(outputStream *st) const { + st->print(" Lock slot: %d, Kind: %s", _slot, _kind_name[(int)_kind]); + } #endif }; diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index fa39301cbef..9dae5d83df9 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -1371,6 +1371,7 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod return false; } BoolNode* bol = test->as_Bool(); + bool range_check_predicate = false; if (invar.is_invariant(bol)) { // Invariant test new_predicate_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, @@ -1399,6 +1400,7 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod } #endif } else if (cl != nullptr && loop->is_range_check_if(if_success_proj, this, invar DEBUG_ONLY(COMMA parse_predicate_proj))) { + range_check_predicate = true; // Range check for counted loops assert(if_success_proj->is_IfTrue(), "trap must be on false projection for a range check"); const Node* cmp = bol->in(1)->as_Cmp(); @@ -1478,7 +1480,10 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod invar.map_ctrl(if_success_proj, new_predicate_proj); // so that invariance test can be appropriate // Eliminate the old If in the loop body - dominated_by(new_predicate_proj, iff, if_success_proj->_con != new_predicate_proj->_con); + // If a range check is eliminated, data dependent nodes (Load and range check CastII nodes) are now dependent on 2 + // Hoisted Check Predicates (one for the start of the loop, one for the end) but we can only keep track of one control + // dependency: pin the data dependent nodes. + dominated_by(new_predicate_proj, iff, if_success_proj->_con != new_predicate_proj->_con, range_check_predicate); C->set_major_progress(); return true; diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index bc1140d4673..e35657cd16a 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -2046,6 +2046,12 @@ bool IdealLoopTree::is_invariant(Node* n) const { // to the new stride. void PhaseIdealLoop::update_main_loop_assertion_predicates(Node* ctrl, CountedLoopNode* loop_head, Node* init, const int stride_con) { + if (init->is_CastII()) { + // skip over the cast added by PhaseIdealLoop::cast_incr_before_loop() when pre/post/main loops are created because + // it can get in the way of type propagation + assert(init->as_CastII()->carry_dependency() && loop_head->skip_predicates() == init->in(0), "casted iv phi from pre loop expected"); + init = init->in(1); + } Node* entry = ctrl; Node* prev_proj = ctrl; LoopNode* outer_loop_head = loop_head->skip_strip_mined(); @@ -2326,6 +2332,8 @@ void PhaseIdealLoop::do_unroll(IdealLoopTree *loop, Node_List &old_new, bool adj // can edit it's inputs directly. Hammer in the new limit for the // minimum-trip guard. assert(opaq->outcnt() == 1, ""); + // Notify limit -> opaq -> CmpI, it may constant fold. + _igvn.add_users_to_worklist(opaq->in(1)); _igvn.replace_input_of(opaq, 1, new_limit); } @@ -3413,7 +3421,6 @@ void IdealLoopTree::adjust_loop_exit_prob(PhaseIdealLoop *phase) { } } -#ifdef ASSERT static CountedLoopNode* locate_pre_from_main(CountedLoopNode* main_loop) { assert(!main_loop->is_main_no_pre_loop(), "Does not have a pre loop"); Node* ctrl = main_loop->skip_predicates(); @@ -3426,7 +3433,6 @@ static CountedLoopNode* locate_pre_from_main(CountedLoopNode* main_loop) { assert(pre_loop->is_pre_loop(), "No pre loop found"); return pre_loop; } -#endif // Remove the main and post loops and make the pre loop execute all // iterations. Useful when the pre loop is found empty. @@ -3454,7 +3460,11 @@ void IdealLoopTree::remove_main_post_loops(CountedLoopNode *cl, PhaseIdealLoop * return; } - assert(locate_pre_from_main(main_head) == cl, "bad main loop"); + // We found a main-loop after this pre-loop, but they might not belong together. + if (locate_pre_from_main(main_head) != cl) { + return; + } + Node* main_iff = main_head->skip_predicates()->in(0); // Remove the Opaque1Node of the pre loop and make it execute all iterations diff --git a/src/hotspot/share/opto/loopUnswitch.cpp b/src/hotspot/share/opto/loopUnswitch.cpp index e2d62965418..53b727d54a7 100644 --- a/src/hotspot/share/opto/loopUnswitch.cpp +++ b/src/hotspot/share/opto/loopUnswitch.cpp @@ -198,11 +198,11 @@ void PhaseIdealLoop::do_unswitching(IdealLoopTree *loop, Node_List &old_new) { // Hardwire the control paths in the loops into if(true) and if(false) _igvn.rehash_node_delayed(unswitch_iff); - dominated_by(proj_true->as_IfProj(), unswitch_iff, false, false); + dominated_by(proj_true->as_IfProj(), unswitch_iff); IfNode* unswitch_iff_clone = old_new[unswitch_iff->_idx]->as_If(); _igvn.rehash_node_delayed(unswitch_iff_clone); - dominated_by(proj_false->as_IfProj(), unswitch_iff_clone, false, false); + dominated_by(proj_false->as_IfProj(), unswitch_iff_clone); // Reoptimize loops loop->record_for_igvn(); diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 52467e75010..3e9d9113e52 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -928,12 +928,20 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { // inner_iters_max may not fit in a signed integer (iterating from // Long.MIN_VALUE to Long.MAX_VALUE for instance). Use an unsigned // min. - Node* inner_iters_actual = MaxNode::unsigned_min(inner_iters_max, inner_iters_limit, TypeInteger::make(0, iters_limit, Type::WidenMin, bt), _igvn); + const TypeInteger* inner_iters_actual_range = TypeInteger::make(0, iters_limit, Type::WidenMin, bt); + Node* inner_iters_actual = MaxNode::unsigned_min(inner_iters_max, inner_iters_limit, inner_iters_actual_range, _igvn); Node* inner_iters_actual_int; if (bt == T_LONG) { inner_iters_actual_int = new ConvL2INode(inner_iters_actual); _igvn.register_new_node_with_optimizer(inner_iters_actual_int); + // When the inner loop is transformed to a counted loop, a loop limit check is not expected to be needed because + // the loop limit is less or equal to max_jint - stride - 1 (if stride is positive but a similar argument exists for + // a negative stride). We add a CastII here to guarantee that, when the counted loop is created in a subsequent loop + // opts pass, an accurate range of values for the limits is found. + const TypeInt* inner_iters_actual_int_range = TypeInt::make(0, iters_limit, Type::WidenMin); + inner_iters_actual_int = new CastIINode(outer_head, inner_iters_actual_int, inner_iters_actual_int_range, ConstraintCastNode::UnconditionalDependency); + _igvn.register_new_node_with_optimizer(inner_iters_actual_int); } else { inner_iters_actual_int = inner_iters_actual; } diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 868a4fd153c..d90e5e2bd41 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1525,7 +1525,7 @@ class PhaseIdealLoop : public PhaseTransform { Node *has_local_phi_input( Node *n ); // Mark an IfNode as being dominated by a prior test, // without actually altering the CFG (and hence IDOM info). - void dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip = false, bool exclude_loop_predicate = false); + void dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip = false, bool pin_array_access_nodes = false); // Split Node 'n' through merge point RegionNode* split_thru_region(Node* n, RegionNode* region); @@ -1743,6 +1743,8 @@ class PhaseIdealLoop : public PhaseTransform { bool at_relevant_ctrl(Node* n, const Node* blk1, const Node* blk2); void update_addp_chain_base(Node* x, Node* old_base, Node* new_base); + + void pin_array_access_nodes_dependent_on(Node* ctrl); }; diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index be9f5599d53..bc1644b59a2 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -48,8 +48,9 @@ //------------------------------split_thru_phi--------------------------------- // Split Node 'n' through merge point if there is enough win. Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { - if (n->Opcode() == Op_ConvI2L && n->bottom_type() != TypeLong::LONG) { - // ConvI2L may have type information on it which is unsafe to push up + if ((n->Opcode() == Op_ConvI2L && n->bottom_type() != TypeLong::LONG) || + (n->Opcode() == Op_ConvL2I && n->bottom_type() != TypeInt::INT)) { + // ConvI2L/ConvL2I may have type information on it which is unsafe to push up // so disable this for now return nullptr; } @@ -259,7 +260,7 @@ bool PhaseIdealLoop::loop_phi_backedge_type_contains_zero(const Node* phi_diviso // Replace the dominated test with an obvious true or false. Place it on the // IGVN worklist for later cleanup. Move control-dependent data Nodes on the // live path up to the dominating control. -void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, bool exclude_loop_predicate) { +void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, bool pin_array_access_nodes) { if (VerifyLoopOptimizations && PrintOpto) { tty->print_cr("dominating test"); } // prevdom is the dominating projection of the dominating test. @@ -284,7 +285,7 @@ void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, b // Hack the dominated test _igvn.replace_input_of(iff, 1, con); - // If I dont have a reachable TRUE and FALSE path following the IfNode then + // If I don't have a reachable TRUE and FALSE path following the IfNode then // I can assume this path reaches an infinite loop. In this case it's not // important to optimize the data Nodes - either the whole compilation will // be tossed or this path (and all data Nodes) will go dead. @@ -295,24 +296,9 @@ void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, b // dominating projection. Node* dp = iff->proj_out_or_null(pop == Op_IfTrue); - // Loop predicates may have depending checks which should not - // be skipped. For example, range check predicate has two checks - // for lower and upper bounds. if (dp == nullptr) return; - ProjNode* dp_proj = dp->as_Proj(); - ProjNode* unc_proj = iff->proj_out(1 - dp_proj->_con)->as_Proj(); - if (exclude_loop_predicate && - (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != nullptr || - unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_profile_predicate) != nullptr || - unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_range_check) != nullptr)) { - // If this is a range check (IfNode::is_range_check), do not - // reorder because Compile::allow_range_check_smearing might have - // changed the check. - return; // Let IGVN transformation change control dependence. - } - IdealLoopTree* old_loop = get_loop(dp); for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { @@ -321,6 +307,20 @@ void PhaseIdealLoop::dominated_by(IfProjNode* prevdom, IfNode* iff, bool flip, b if (cd->depends_only_on_test() && _igvn.no_dependent_zero_check(cd)) { assert(cd->in(0) == dp, ""); _igvn.replace_input_of(cd, 0, prevdom); + if (pin_array_access_nodes) { + // Because of Loop Predication, Loads and range check Cast nodes that are control dependent on this range + // check (that is about to be removed) now depend on multiple dominating Hoisted Check Predicates. After the + // removal of this range check, these control dependent nodes end up at the lowest/nearest dominating predicate + // in the graph. To ensure that these Loads/Casts do not float above any of the dominating checks (even when the + // lowest dominating check is later replaced by yet another dominating check), we need to pin them at the lowest + // dominating check. + Node* clone = cd->pin_array_access_node(); + if (clone != nullptr) { + clone = _igvn.register_new_node_with_optimizer(clone, cd); + _igvn.replace_node(cd, clone); + cd = clone; + } + } set_early_ctrl(cd, false); IdealLoopTree* new_loop = get_loop(get_ctrl(cd)); if (old_loop != new_loop) { @@ -1441,7 +1441,16 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) { // Replace the dominated test with an obvious true or false. // Place it on the IGVN worklist for later cleanup. C->set_major_progress(); - dominated_by(prevdom->as_IfProj(), n->as_If(), false, true); + // Split if: pin array accesses that are control dependent on a range check and moved to a regular if, + // to prevent an array load from floating above its range check. There are three cases: + // 1. Move from RangeCheck "a" to RangeCheck "b": don't need to pin. If we ever remove b, then we pin + // all its array accesses at that point. + // 2. We move from RangeCheck "a" to regular if "b": need to pin. If we ever remove b, then its array + // accesses would start to float, since we don't pin at that point. + // 3. If we move from regular if: don't pin. All array accesses are already assumed to be pinned. + bool pin_array_access_nodes = n->Opcode() == Op_RangeCheck && + prevdom->in(0)->Opcode() != Op_RangeCheck; + dominated_by(prevdom->as_IfProj(), n->as_If(), false, pin_array_access_nodes); DEBUG_ONLY( if (VerifyLoopOptimizations) { verify(); } ); return; } @@ -1528,10 +1537,10 @@ bool PhaseIdealLoop::try_merge_identical_ifs(Node* n) { // unrelated control dependency. for (uint i = 1; i < new_false_region->req(); i++) { if (is_dominator(dom_proj_true, new_false_region->in(i))) { - dominated_by(dom_proj_true->as_IfProj(), new_false_region->in(i)->in(0)->as_If(), false, false); + dominated_by(dom_proj_true->as_IfProj(), new_false_region->in(i)->in(0)->as_If()); } else { assert(is_dominator(dom_proj_false, new_false_region->in(i)), "bad if"); - dominated_by(dom_proj_false->as_IfProj(), new_false_region->in(i)->in(0)->as_If(), false, false); + dominated_by(dom_proj_false->as_IfProj(), new_false_region->in(i)->in(0)->as_If()); } } return true; @@ -1609,7 +1618,20 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { // n has a control input inside a loop but get_ctrl() is member of an outer loop. This could happen, for example, // for Div nodes inside a loop (control input inside loop) without a use except for an UCT (outside the loop). // Rewire control of n to right outside of the loop, regardless if its input(s) are later sunk or not. - _igvn.replace_input_of(n, 0, place_outside_loop(n_ctrl, loop_ctrl)); + Node* maybe_pinned_n = n; + Node* outside_ctrl = place_outside_loop(n_ctrl, loop_ctrl); + if (n->depends_only_on_test()) { + Node* pinned_clone = n->pin_array_access_node(); + if (pinned_clone != nullptr) { + // Pin array access nodes: if this is an array load, it's going to be dependent on a condition that's not a + // range check for that access. If that condition is replaced by an identical dominating one, then an + // unpinned load would risk floating above its range check. + register_new_node(pinned_clone, n_ctrl); + maybe_pinned_n = pinned_clone; + _igvn.replace_node(n, pinned_clone); + } + } + _igvn.replace_input_of(maybe_pinned_n, 0, outside_ctrl); } } if (n_loop != _ltree_root && n->outcnt() > 1) { @@ -1623,7 +1645,16 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { for (DUIterator_Last jmin, j = n->last_outs(jmin); j >= jmin;) { Node* u = n->last_out(j); // Clone private computation per use _igvn.rehash_node_delayed(u); - Node* x = n->clone(); // Clone computation + Node* x = nullptr; + if (n->depends_only_on_test()) { + // Pin array access nodes: if this is an array load, it's going to be dependent on a condition that's not a + // range check for that access. If that condition is replaced by an identical dominating one, then an + // unpinned load would risk floating above its range check. + x = n->pin_array_access_node(); + } + if (x == nullptr) { + x = n->clone(); + } Node* x_ctrl = nullptr; if (u->is_Phi()) { // Replace all uses of normal nodes. Replace Phi uses @@ -2173,6 +2204,20 @@ void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new, // We notify all uses of old, including use, and the indirect uses, // that may now be optimized because we have replaced old with phi. _igvn.add_users_to_worklist(old); + if (idx == 0 && + use->depends_only_on_test()) { + Node* pinned_clone = use->pin_array_access_node(); + if (pinned_clone != nullptr) { + // Pin array access nodes: control is updated here to a region. If, after some transformations, only one path + // into the region is left, an array load could become dependent on a condition that's not a range check for + // that access. If that condition is replaced by an identical dominating one, then an unpinned load would risk + // floating above its range check. + pinned_clone->set_req(0, phi); + register_new_node(pinned_clone, get_ctrl(use)); + _igvn.replace_node(use, pinned_clone); + continue; + } + } _igvn.replace_input_of(use, idx, phi); if( use->_idx >= new_counter ) { // If updating new phis // Not needed for correctness, but prevents a weak assert @@ -2881,52 +2926,101 @@ RegionNode* PhaseIdealLoop::insert_region_before_proj(ProjNode* proj) { return reg; } -//------------------------------ insert_cmpi_loop_exit ------------------------------------- -// Clone a signed compare loop exit from an unsigned compare and -// insert it before the unsigned cmp on the stay-in-loop path. -// All new nodes inserted in the dominator tree between the original -// if and it's projections. The original if test is replaced with -// a constant to force the stay-in-loop path. +// Idea +// ---- +// Partial Peeling tries to rotate the loop in such a way that it can later be turned into a counted loop. Counted loops +// require a signed loop exit test. When calling this method, we've only found a suitable unsigned test to partial peel +// with. Therefore, we try to split off a signed loop exit test from the unsigned test such that it can be used as new +// loop exit while keeping the unsigned test unchanged and preserving the same behavior as if we've used the unsigned +// test alone instead: // -// This is done to make sure that the original if and it's projections -// still dominate the same set of control nodes, that the ctrl() relation -// from data nodes to them is preserved, and that their loop nesting is -// preserved. +// Before Partial Peeling: +// Loop: +// +// Split off signed loop exit test +// <-- CUT HERE --> +// Unchanged unsigned loop exit test +// +// goto Loop // -// before -// if(i +// Cloned split off signed loop exit test +// Loop: +// Unchanged unsigned loop exit test +// +// +// Split off signed loop exit test +// goto Loop +// +// Details +// ------- +// Before: +// if (i in(1)->as_Bool(); - if (bol->_test._test != BoolTest::lt) return nullptr; + if (bol->_test._test != BoolTest::lt) { + return nullptr; + } CmpNode* cmpu = bol->in(1)->as_Cmp(); - if (cmpu->Opcode() != Op_CmpU) return nullptr; + assert(cmpu->Opcode() == Op_CmpU, "must be unsigned comparison"); + int stride = stride_of_possible_iv(if_cmpu); - if (stride == 0) return nullptr; + if (stride == 0) { + return nullptr; + } Node* lp_proj = stay_in_loop(if_cmpu, loop); guarantee(lp_proj != nullptr, "null loop node"); @@ -2938,14 +3032,93 @@ IfNode* PhaseIdealLoop::insert_cmpi_loop_exit(IfNode* if_cmpu, IdealLoopTree *lo // We therefore can't add a single exit condition. return nullptr; } - // The loop exit condition is !(i (i < 0 || i >= limit). - // Split out the exit condition (i < 0) for stride < 0 or (i >= limit) for stride > 0. - Node* limit = nullptr; + // The unsigned loop exit condition is + // !(i =u limit + // + // First, we note that for any x for which + // 0 <= x <= INT_MAX + // we can convert x to an unsigned int and still get the same guarantee: + // 0 <= (uint) x <= INT_MAX = (uint) INT_MAX + // 0 <=u (uint) x <=u INT_MAX = (uint) INT_MAX (LEMMA) + // + // With that in mind, if + // limit >= 0 (COND) + // then the unsigned loop exit condition + // i >=u limit (ULE) + // is equivalent to + // i < 0 || i >= limit (SLE-full) + // because either i is negative and therefore always greater than MAX_INT when converting to unsigned + // (uint) i >=u MAX_INT >= limit >= 0 + // or otherwise + // i >= limit >= 0 + // holds due to (LEMMA). + // + // For completeness, a counterexample with limit < 0: + // Assume i = -3 and limit = -2: + // i < 0 + // -2 < 0 + // is true and thus also "i < 0 || i >= limit". But + // i >=u limit + // -3 >=u -2 + // is false. + Node* limit = cmpu->in(2); + const TypeInt* type_limit = _igvn.type(limit)->is_int(); + if (type_limit->_lo < 0) { + return nullptr; + } + + // We prove below that we can extract a single signed loop exit condition from (SLE-full), depending on the stride: + // stride < 0: + // i < 0 (SLE = SLE-negative) + // stride > 0: + // i >= limit (SLE = SLE-positive) + // such that we have the following graph before Partial Peeling with stride > 0 (similar for stride < 0): + // + // Loop: + // + // i >= limit (SLE-positive) + // <-- CUT HERE --> + // i >=u limit (ULE) + // + // goto Loop + // + // We exit the loop if: + // (SLE) is true OR (ULE) is true + // However, if (SLE) is true then (ULE) also needs to be true to ensure the exact same behavior. Otherwise, we wrongly + // exit a loop that should not have been exited if we did not apply Partial Peeling. More formally, we need to ensure: + // (SLE) IMPLIES (ULE) + // This indeed holds when (COND) is given: + // - stride > 0: + // i >= limit // (SLE = SLE-positive) + // i >= limit >= 0 // (COND) + // i >=u limit >= 0 // (LEMMA) + // which is the unsigned loop exit condition (ULE). + // - stride < 0: + // i < 0 // (SLE = SLE-negative) + // (uint) i >u MAX_INT // (NEG) all negative values are greater than MAX_INT when converted to unsigned + // MAX_INT >= limit >= 0 // (COND) + // MAX_INT >=u limit >= 0 // (LEMMA) + // and thus from (NEG) and (LEMMA): + // i >=u limit + // which is the unsigned loop exit condition (ULE). + // + // + // After Partial Peeling, we have the following structure for stride > 0 (similar for stride < 0): + // + // i >= limit (SLE-positive) + // Loop: + // i >=u limit (ULE) + // + // + // i >= limit (SLE-positive) + // goto Loop + Node* rhs_cmpi; if (stride > 0) { - limit = cmpu->in(2); + rhs_cmpi = limit; // For i >= limit } else { - limit = _igvn.makecon(TypeInt::ZERO); - set_ctrl(limit, C->root()); + rhs_cmpi = _igvn.makecon(TypeInt::ZERO); // For i < 0 + set_ctrl(rhs_cmpi, C->root()); } // Create a new region on the exit path RegionNode* reg = insert_region_before_proj(lp_exit); @@ -2953,7 +3126,7 @@ IfNode* PhaseIdealLoop::insert_cmpi_loop_exit(IfNode* if_cmpu, IdealLoopTree *lo // Clone the if-cmpu-true-false using a signed compare BoolTest::mask rel_i = stride > 0 ? bol->_test._test : BoolTest::ge; - ProjNode* cmpi_exit = insert_if_before_proj(cmpu->in(1), Signed, rel_i, limit, lp_continue); + ProjNode* cmpi_exit = insert_if_before_proj(cmpu->in(1), Signed, rel_i, rhs_cmpi, lp_continue); reg->add_req(cmpi_exit); // Clone the if-cmpu-true-false @@ -3804,6 +3977,19 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) { if (!n->is_CFG() && n->in(0) != nullptr && not_peel.test(n->_idx) && peel.test(n->in(0)->_idx)) { Node* n_clone = old_new[n->_idx]; + if (n_clone->depends_only_on_test()) { + // Pin array access nodes: control is updated here to the loop head. If, after some transformations, the + // backedge is removed, an array load could become dependent on a condition that's not a range check for that + // access. If that condition is replaced by an identical dominating one, then an unpinned load would risk + // floating above its range check. + Node* pinned_clone = n_clone->pin_array_access_node(); + if (pinned_clone != nullptr) { + register_new_node(pinned_clone, get_ctrl(n_clone)); + old_new.map(n->_idx, pinned_clone); + _igvn.replace_node(n_clone, pinned_clone); + n_clone = pinned_clone; + } + } _igvn.replace_input_of(n_clone, 0, new_head_clone); } } diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 3681617b6d8..beb0d1e18bf 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -725,7 +725,7 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray jvms()->depth(), nfields); sobj->init_req(0, C->root()); transform_later(sobj); @@ -1904,10 +1904,12 @@ void PhaseMacroExpand::expand_allocate_array(AllocateArrayNode *alloc) { // marked for elimination since new obj has no escape information. // Mark all associated (same box and obj) lock and unlock nodes for // elimination if some of them marked already. -void PhaseMacroExpand::mark_eliminated_box(Node* oldbox, Node* obj) { - if (oldbox->as_BoxLock()->is_eliminated()) { +void PhaseMacroExpand::mark_eliminated_box(Node* box, Node* obj) { + BoxLockNode* oldbox = box->as_BoxLock(); + if (oldbox->is_eliminated()) { return; // This BoxLock node was processed already. } + assert(!oldbox->is_unbalanced(), "this should not be called for unbalanced region"); // New implementation (EliminateNestedLocks) has separate BoxLock // node for each locked region so mark all associated locks/unlocks as // eliminated even if different objects are referenced in one locked region @@ -1915,8 +1917,9 @@ void PhaseMacroExpand::mark_eliminated_box(Node* oldbox, Node* obj) { if (EliminateNestedLocks || oldbox->as_BoxLock()->is_simple_lock_region(nullptr, obj, nullptr)) { // Box is used only in one lock region. Mark this box as eliminated. + oldbox->set_local(); // This verifies correct state of BoxLock _igvn.hash_delete(oldbox); - oldbox->as_BoxLock()->set_eliminated(); // This changes box's hash value + oldbox->set_eliminated(); // This changes box's hash value _igvn.hash_insert(oldbox); for (uint i = 0; i < oldbox->outcnt(); i++) { @@ -1943,6 +1946,7 @@ void PhaseMacroExpand::mark_eliminated_box(Node* oldbox, Node* obj) { // Note: BoxLock node is marked eliminated only here and it is used // to indicate that all associated lock and unlock nodes are marked // for elimination. + newbox->set_local(); // This verifies correct state of BoxLock newbox->set_eliminated(); transform_later(newbox); @@ -1998,6 +2002,9 @@ void PhaseMacroExpand::mark_eliminated_box(Node* oldbox, Node* obj) { //-----------------------mark_eliminated_locking_nodes----------------------- void PhaseMacroExpand::mark_eliminated_locking_nodes(AbstractLockNode *alock) { + if (!alock->is_balanced()) { + return; // Can't do any more elimination for this locking region + } if (EliminateNestedLocks) { if (alock->is_nested()) { assert(alock->box_node()->as_BoxLock()->is_eliminated(), "sanity"); @@ -2314,6 +2321,11 @@ void PhaseMacroExpand::eliminate_macro_nodes() { // Re-marking may break consistency of Coarsened locks. if (!C->coarsened_locks_consistent()) { return; // recompile without Coarsened locks if broken + } else { + // After coarsened locks are eliminated locking regions + // become unbalanced. We should not execute any more + // locks elimination optimizations on them. + C->mark_unbalanced_boxes(); } // First, attempt to eliminate locks diff --git a/src/hotspot/share/opto/macroArrayCopy.cpp b/src/hotspot/share/opto/macroArrayCopy.cpp index f80651c2996..94827d1f4fa 100644 --- a/src/hotspot/share/opto/macroArrayCopy.cpp +++ b/src/hotspot/share/opto/macroArrayCopy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1266,7 +1266,7 @@ void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) { generate_arraycopy(ac, alloc, &ctrl, merge_mem, &io, adr_type, T_OBJECT, src, src_offset, dest, dest_offset, length, - true, !ac->is_copyofrange()); + true, ac->has_negative_length_guard()); return; } diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index ad925287b52..91e43dbf46c 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -865,8 +865,12 @@ bool LoadNode::can_remove_control() const { return !has_pinned_control_dependency(); } uint LoadNode::size_of() const { return sizeof(*this); } -bool LoadNode::cmp( const Node &n ) const -{ return !Type::cmp( _type, ((LoadNode&)n)._type ); } +bool LoadNode::cmp(const Node &n) const { + LoadNode& load = (LoadNode &)n; + return !Type::cmp(_type, load._type) && + _control_dependency == load._control_dependency && + _mo == load._mo; +} const Type *LoadNode::bottom_type() const { return _type; } uint LoadNode::ideal_reg() const { return _type->ideal_reg(); @@ -1003,6 +1007,14 @@ static bool skip_through_membars(Compile::AliasType* atp, const TypeInstPtr* tp, return false; } +LoadNode* LoadNode::pin_array_access_node() const { + const TypePtr* adr_type = this->adr_type(); + if (adr_type != nullptr && adr_type->isa_aryptr()) { + return clone_pinned(); + } + return nullptr; +} + // Is the value loaded previously stored by an arraycopy? If so return // a load node that reads from the source array so we may be able to // optimize out the ArrayCopy node later. @@ -1022,7 +1034,8 @@ Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseGVN* phase) const { return nullptr; } - LoadNode* ld = clone()->as_Load(); + // load depends on the tests that validate the arraycopy + LoadNode* ld = clone_pinned(); Node* addp = in(MemNode::Address)->clone(); if (ac->as_ArrayCopy()->is_clonebasic()) { assert(ld_alloc != nullptr, "need an alloc"); @@ -1064,8 +1077,6 @@ Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseGVN* phase) const { ld->set_req(MemNode::Address, addp); ld->set_req(0, ctl); ld->set_req(MemNode::Memory, mem); - // load depends on the tests that validate the arraycopy - ld->_control_dependency = UnknownControl; return ld; } return nullptr; @@ -2513,6 +2524,12 @@ Node* LoadNode::klass_identity_common(PhaseGVN* phase) { return this; } +LoadNode* LoadNode::clone_pinned() const { + LoadNode* ld = clone()->as_Load(); + ld->_control_dependency = UnknownControl; + return ld; +} + //------------------------------Value------------------------------------------ const Type* LoadNKlassNode::Value(PhaseGVN* phase) const { @@ -2789,7 +2806,10 @@ Node* StoreNode::Identity(PhaseGVN* phase) { val->in(MemNode::Address)->eqv_uncast(adr) && val->in(MemNode::Memory )->eqv_uncast(mem) && val->as_Load()->store_Opcode() == Opcode()) { - result = mem; + // Ensure vector type is the same + if (!is_StoreVector() || (mem->is_LoadVector() && as_StoreVector()->vect_type() == mem->as_LoadVector()->vect_type())) { + result = mem; + } } // Two stores in a row of the same value? @@ -2798,7 +2818,24 @@ Node* StoreNode::Identity(PhaseGVN* phase) { mem->in(MemNode::Address)->eqv_uncast(adr) && mem->in(MemNode::ValueIn)->eqv_uncast(val) && mem->Opcode() == Opcode()) { - result = mem; + if (!is_StoreVector()) { + result = mem; + } else { + const StoreVectorNode* store_vector = as_StoreVector(); + const StoreVectorNode* mem_vector = mem->as_StoreVector(); + const Node* store_indices = store_vector->indices(); + const Node* mem_indices = mem_vector->indices(); + const Node* store_mask = store_vector->mask(); + const Node* mem_mask = mem_vector->mask(); + // Ensure types, indices, and masks match + if (store_vector->vect_type() == mem_vector->vect_type() && + ((store_indices == nullptr) == (mem_indices == nullptr) && + (store_indices == nullptr || store_indices->eqv_uncast(mem_indices))) && + ((store_mask == nullptr) == (mem_mask == nullptr) && + (store_mask == nullptr || store_mask->eqv_uncast(mem_mask)))) { + result = mem; + } + } } // Store of zero anywhere into a freshly-allocated object? diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index 3d6cc249b25..8fe5cae0e45 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -294,6 +294,8 @@ class LoadNode : public MemNode { bool has_unknown_control_dependency() const { return _control_dependency == UnknownControl; } bool has_pinned_control_dependency() const { return _control_dependency == Pinned; } + LoadNode* pin_array_access_node() const; + #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif @@ -319,6 +321,8 @@ class LoadNode : public MemNode { virtual bool depends_only_on_test() const { return adr_type() != TypeRawPtr::BOTTOM && _control_dependency == DependsOnlyOnTest; } + + LoadNode* clone_pinned() const; }; //------------------------------LoadBNode-------------------------------------- diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 13bf13cf4a8..794fc2cd120 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -173,8 +173,10 @@ class LoadVectorNode; class LoadVectorMaskedNode; class StoreVectorMaskedNode; class LoadVectorGatherNode; +class LoadVectorGatherMaskedNode; class StoreVectorNode; class StoreVectorScatterNode; +class StoreVectorScatterMaskedNode; class VectorMaskCmpNode; class VectorUnboxNode; class VectorSet; @@ -969,8 +971,12 @@ class Node { DEFINE_CLASS_QUERY(CompressM) DEFINE_CLASS_QUERY(LoadVector) DEFINE_CLASS_QUERY(LoadVectorGather) + DEFINE_CLASS_QUERY(LoadVectorMasked) + DEFINE_CLASS_QUERY(LoadVectorGatherMasked) DEFINE_CLASS_QUERY(StoreVector) DEFINE_CLASS_QUERY(StoreVectorScatter) + DEFINE_CLASS_QUERY(StoreVectorMasked) + DEFINE_CLASS_QUERY(StoreVectorScatterMasked) DEFINE_CLASS_QUERY(ShiftV) DEFINE_CLASS_QUERY(Unlock) @@ -1123,7 +1129,14 @@ class Node { // Set control or add control as precedence edge void ensure_control_or_add_prec(Node* c); -//----------------- Code Generation + // Returns a clone of the current node that's pinned (if the current node is not) for nodes found in array accesses + // (Load and range check CastII nodes). + // This is used when an array access is made dependent on 2 or more range checks (range check smearing or Loop Predication). + virtual Node* pin_array_access_node() const { + return nullptr; + } + + //----------------- Code Generation // Ideal register class for Matching. Zero means unmatched instruction // (these are cloned instead of converted to machine nodes). @@ -1532,8 +1545,8 @@ Node* Node::last_out(DUIterator_Last& i) const { class SimpleDUIterator : public StackObj { private: Node* node; - DUIterator_Fast i; DUIterator_Fast imax; + DUIterator_Fast i; public: SimpleDUIterator(Node* n): node(n), i(n->fast_outs(imax)) {} bool has_next() { return i < imax; } diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 998be5e1225..988e6e42b8c 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -169,6 +169,11 @@ class Scheduling { // Add a node to the current bundle void AddNodeToBundle(Node *n, const Block *bb); + // Return an integer less than, equal to, or greater than zero + // if the stack offset of the first argument is respectively + // less than, equal to, or greater than the second. + int compare_two_spill_nodes(Node* first, Node* second); + // Add a node to the list of available nodes void AddNodeToAvailableList(Node *n); @@ -2219,6 +2224,29 @@ Node * Scheduling::ChooseNodeToBundle() { return _available[0]; } +int Scheduling::compare_two_spill_nodes(Node* first, Node* second) { + assert(first->is_MachSpillCopy() && second->is_MachSpillCopy(), ""); + + OptoReg::Name first_src_lo = _regalloc->get_reg_first(first->in(1)); + OptoReg::Name first_dst_lo = _regalloc->get_reg_first(first); + OptoReg::Name second_src_lo = _regalloc->get_reg_first(second->in(1)); + OptoReg::Name second_dst_lo = _regalloc->get_reg_first(second); + + // Comparison between stack -> reg and stack -> reg + if (OptoReg::is_stack(first_src_lo) && OptoReg::is_stack(second_src_lo) && + OptoReg::is_reg(first_dst_lo) && OptoReg::is_reg(second_dst_lo)) { + return _regalloc->reg2offset(first_src_lo) - _regalloc->reg2offset(second_src_lo); + } + + // Comparison between reg -> stack and reg -> stack + if (OptoReg::is_stack(first_dst_lo) && OptoReg::is_stack(second_dst_lo) && + OptoReg::is_reg(first_src_lo) && OptoReg::is_reg(second_src_lo)) { + return _regalloc->reg2offset(first_dst_lo) - _regalloc->reg2offset(second_dst_lo); + } + + return 0; // Not comparable +} + void Scheduling::AddNodeToAvailableList(Node *n) { assert( !n->is_Proj(), "projections never directly made available" ); #ifndef PRODUCT @@ -2230,11 +2258,20 @@ void Scheduling::AddNodeToAvailableList(Node *n) { int latency = _current_latency[n->_idx]; - // Insert in latency order (insertion sort) + // Insert in latency order (insertion sort). If two MachSpillCopyNodes + // for stack spilling or unspilling have the same latency, we sort + // them in the order of stack offset. Some ports (e.g. aarch64) may also + // have more opportunities to do ld/st merging uint i; - for ( i=0; i < _available.size(); i++ ) - if (_current_latency[_available[i]->_idx] > latency) + for (i = 0; i < _available.size(); i++) { + if (_current_latency[_available[i]->_idx] > latency) { break; + } else if (_current_latency[_available[i]->_idx] == latency && + n->is_MachSpillCopy() && _available[i]->is_MachSpillCopy() && + compare_two_spill_nodes(n, _available[i]) > 0) { + break; + } + } // Special Check for compares following branches if( n->is_Mach() && _scheduled.size() > 0 ) { diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index 4d00a9a3871..40ca838bbfe 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -224,8 +224,20 @@ void Parse::load_interpreter_state(Node* osr_buf) { Node *monitors_addr = basic_plus_adr(osr_buf, osr_buf, (max_locals+mcnt*2-1)*wordSize); for (index = 0; index < mcnt; index++) { // Make a BoxLockNode for the monitor. - Node *box = _gvn.transform(new BoxLockNode(next_monitor())); + BoxLockNode* osr_box = new BoxLockNode(next_monitor()); + // Check for bailout after new BoxLockNode + if (failing()) { return; } + // This OSR locking region is unbalanced because it does not have Lock node: + // locking was done in Interpreter. + // This is similar to Coarsened case when Lock node is eliminated + // and as result the region is marked as Unbalanced. + + // Emulate Coarsened state transition from Regular to Unbalanced. + osr_box->set_coarsened(); + osr_box->set_unbalanced(); + + Node* box = _gvn.transform(osr_box); // Displaced headers and locked objects are interleaved in the // temp OSR buffer. We only copy the locked objects out here. @@ -1262,6 +1274,8 @@ void Parse::do_method_entry() { kill_dead_locals(); // Build the FastLockNode _synch_lock = shared_lock(lock_obj); + // Check for bailout in shared_lock + if (failing()) { return; } } // Feed profiling data for parameters to the type system so it can @@ -1786,11 +1800,24 @@ void Parse::merge_common(Parse::Block* target, int pnum) { const JVMState* jvms = map()->jvms(); if (EliminateNestedLocks && jvms->is_mon(j) && jvms->is_monitor_box(j)) { - // BoxLock nodes are not commoning. + // BoxLock nodes are not commoning when EliminateNestedLocks is on. // Use old BoxLock node as merged box. assert(newin->jvms()->is_monitor_box(j), "sanity"); // This assert also tests that nodes are BoxLock. assert(BoxLockNode::same_slot(n, m), "sanity"); + BoxLockNode* old_box = m->as_BoxLock(); + if (n->as_BoxLock()->is_unbalanced() && !old_box->is_unbalanced()) { + // Preserve Unbalanced status. + // + // `old_box` can have only Regular or Coarsened status + // because this code is executed only during Parse phase and + // Incremental Inlining before EA and Macro nodes elimination. + // + // Incremental Inlining is executed after IGVN optimizations + // during which BoxLock can be marked as Coarsened. + old_box->set_coarsened(); // Verifies state + old_box->set_unbalanced(); + } C->gvn_replace_by(n, m); } else if (!check_elide_phi || !target->can_elide_SEL_phi(j)) { phi = ensure_phi(j, nophi); diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index bb21f48f633..f56c7586711 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2779,6 +2779,7 @@ void Parse::do_one_bytecode() { } #ifndef PRODUCT + if (failing()) { return; } if (C->should_print_igv(1)) { IdealGraphPrinter* printer = C->igv_printer(); char buffer[256]; diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 1e36f015117..e6b52b4ce1b 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1913,8 +1913,9 @@ void PhaseCCP::push_cmpu(Unique_Node_List& worklist, const Node* use) const { if (use_op == Op_AddI || use_op == Op_SubI) { for (DUIterator_Fast imax, i = use->fast_outs(imax); i < imax; i++) { Node* cmpu = use->fast_out(i); - if (cmpu->Opcode() == Op_CmpU) { - // Got a CmpU which might need the new type information from node n. + const uint cmpu_opcode = cmpu->Opcode(); + if (cmpu_opcode == Op_CmpU || cmpu_opcode == Op_CmpU3) { + // Got a CmpU or CmpU3 which might need the new type information from node n. push_if_not_bottom_type(worklist, cmpu); } } diff --git a/src/hotspot/share/opto/regmask.hpp b/src/hotspot/share/opto/regmask.hpp index 75b3b6aa5a2..f77c14e50ea 100644 --- a/src/hotspot/share/opto/regmask.hpp +++ b/src/hotspot/share/opto/regmask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "opto/optoreg.hpp" #include "utilities/count_leading_zeros.hpp" #include "utilities/count_trailing_zeros.hpp" +#include "utilities/globalDefinitions.hpp" class LRG; @@ -359,16 +360,15 @@ class RegMask { static const RegMask Empty; // Common empty mask static const RegMask All; // Common all mask - static bool can_represent(OptoReg::Name reg) { - // NOTE: -1 in computation reflects the usage of the last - // bit of the regmask as an infinite stack flag and - // -7 is to keep mask aligned for largest value (VecZ). - return (int)reg < (int)(CHUNK_SIZE - 1); + static bool can_represent(OptoReg::Name reg, unsigned int size = 1) { + // NOTE: MAX2(1U,size) in computation reflects the usage of the last + // bit of the regmask as an infinite stack flag. + return (int)reg < (int)(CHUNK_SIZE - MAX2(1U,size)); } static bool can_represent_arg(OptoReg::Name reg) { - // NOTE: -SlotsPerVecZ in computation reflects the need + // NOTE: SlotsPerVecZ in computation reflects the need // to keep mask aligned for largest value (VecZ). - return (int)reg < (int)(CHUNK_SIZE - SlotsPerVecZ); + return can_represent(reg, SlotsPerVecZ); } }; diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 440fafd6a3f..53b3770bc8f 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -1566,10 +1566,7 @@ address OptoRuntime::handle_exception_C(JavaThread* current) { // address OptoRuntime::rethrow_C(oopDesc* exception, JavaThread* thread, address ret_pc) { // ret_pc will have been loaded from the stack, so for AArch64 will be signed. - // This needs authenticating, but to do that here requires the fp of the previous frame. - // A better way of doing it would be authenticate in the caller by adding a - // AuthPAuthNode and using it in GraphKit::gen_stub. For now, just strip it. - AARCH64_PORT_ONLY(ret_pc = pauth_strip_pointer(ret_pc)); + AARCH64_PORT_ONLY(ret_pc = pauth_strip_verifiable(ret_pc)); #ifndef PRODUCT SharedRuntime::_rethrow_ctr++; // count rethrows diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp index 5b6462307bb..e90dfa1cc8e 100644 --- a/src/hotspot/share/opto/split_if.cpp +++ b/src/hotspot/share/opto/split_if.cpp @@ -734,6 +734,14 @@ void PhaseIdealLoop::do_split_if(Node* iff, RegionNode** new_false_region, Regio } // End of while merge point has phis _igvn.remove_dead_node(region); + if (iff->Opcode() == Op_RangeCheck) { + // Pin array access nodes: control is updated here to a region. If, after some transformations, only one path + // into the region is left, an array load could become dependent on a condition that's not a range check for + // that access. If that condition is replaced by an identical dominating one, then an unpinned load would risk + // floating above its range check. + pin_array_access_nodes_dependent_on(new_true); + pin_array_access_nodes_dependent_on(new_false); + } if (new_false_region != nullptr) { *new_false_region = new_false; @@ -744,3 +752,18 @@ void PhaseIdealLoop::do_split_if(Node* iff, RegionNode** new_false_region, Regio DEBUG_ONLY( if (VerifyLoopOptimizations) { verify(); } ); } + +void PhaseIdealLoop::pin_array_access_nodes_dependent_on(Node* ctrl) { + for (DUIterator i = ctrl->outs(); ctrl->has_out(i); i++) { + Node* use = ctrl->out(i); + if (!use->depends_only_on_test()) { + continue; + } + Node* pinned_clone = use->pin_array_access_node(); + if (pinned_clone != nullptr) { + register_new_node(pinned_clone, get_ctrl(use)); + _igvn.replace_node(use, pinned_clone); + --i; + } + } +} diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 14185483555..5774fef6670 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -2748,7 +2748,7 @@ bool SuperWord::output() { } vlen_in_bytes = vn->as_StoreVector()->memory_size(); } else if (VectorNode::is_scalar_rotate(n)) { - Node* in1 = first->in(1); + Node* in1 = vector_opd(p, 1); Node* in2 = first->in(2); // If rotation count is non-constant or greater than 8bit value create a vector. if (!in2->is_Con() || !Matcher::supports_vector_constant_rotates(in2->get_int())) { @@ -4206,7 +4206,10 @@ SWPointer::SWPointer(MemNode* mem, SuperWord* slp, Node_Stack *nstack, bool anal break; // stop looking at addp's } } - if (is_loop_member(adr)) { + if (!invariant(adr)) { + // The address must be invariant for the current loop. But if we are in a main-loop, + // it must also be invariant of the pre-loop, otherwise we cannot use this address + // for the pre-loop limit adjustment required for main-loop alignment. assert(!valid(), "adr is loop variant"); return; } diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 24d39b279c9..99faa8fd9c1 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -4173,24 +4173,24 @@ const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst, const T // assert(loaded->ptr() != TypePtr::Null, "insanity check"); // - if (loaded->ptr() == TypePtr::TopPTR) { return unloaded; } + if (loaded->ptr() == TypePtr::TopPTR) { return unloaded->with_speculative(speculative); } else if (loaded->ptr() == TypePtr::AnyNull) { return make(ptr, unloaded->klass(), interfaces, false, nullptr, off, instance_id, speculative, depth); } - else if (loaded->ptr() == TypePtr::BotPTR) { return TypeInstPtr::BOTTOM; } + else if (loaded->ptr() == TypePtr::BotPTR) { return TypeInstPtr::BOTTOM->with_speculative(speculative); } else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) { - if (unloaded->ptr() == TypePtr::BotPTR) { return TypeInstPtr::BOTTOM; } - else { return TypeInstPtr::NOTNULL; } + if (unloaded->ptr() == TypePtr::BotPTR) { return TypeInstPtr::BOTTOM->with_speculative(speculative); } + else { return TypeInstPtr::NOTNULL->with_speculative(speculative); } } - else if (unloaded->ptr() == TypePtr::TopPTR) { return unloaded; } + else if (unloaded->ptr() == TypePtr::TopPTR) { return unloaded->with_speculative(speculative); } - return unloaded->cast_to_ptr_type(TypePtr::AnyNull)->is_instptr(); + return unloaded->cast_to_ptr_type(TypePtr::AnyNull)->is_instptr()->with_speculative(speculative); } // Both are unloaded, not the same class, not Object // Or meet unloaded with a different loaded class, not java/lang/Object if (ptr != TypePtr::BotPTR) { - return TypeInstPtr::NOTNULL; + return TypeInstPtr::NOTNULL->with_speculative(speculative); } - return TypeInstPtr::BOTTOM; + return TypeInstPtr::BOTTOM->with_speculative(speculative); } @@ -4593,6 +4593,10 @@ const TypeInstPtr* TypeInstPtr::remove_speculative() const { _instance_id, nullptr, _inline_depth); } +const TypeInstPtr* TypeInstPtr::with_speculative(const TypePtr* speculative) const { + return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset, _instance_id, speculative, _inline_depth); +} + const TypePtr* TypeInstPtr::with_inline_depth(int depth) const { if (!UseInlineDepthForSpeculativeTypes) { return this; diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index 62f9e27c8f8..f2657fcb4f1 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -1356,6 +1356,7 @@ class TypeInstPtr : public TypeOopPtr { // Speculative type helper methods. virtual const TypeInstPtr* remove_speculative() const; + const TypeInstPtr* with_speculative(const TypePtr* speculative) const; virtual const TypePtr* with_inline_depth(int depth) const; virtual const TypePtr* with_instance_id(int instance_id) const; diff --git a/src/hotspot/share/opto/vector.cpp b/src/hotspot/share/opto/vector.cpp index d74f7f95caa..fb414719289 100644 --- a/src/hotspot/share/opto/vector.cpp +++ b/src/hotspot/share/opto/vector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -280,7 +280,7 @@ void PhaseVector::scalarize_vbox_node(VectorBoxNode* vec_box) { #ifdef ASSERT vec_box, #endif // ASSERT - first_ind, n_fields); + first_ind, sfpt->jvms()->depth(), n_fields); sobj->init_req(0, C->root()); sfpt->add_req(vec_value); diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index 39a5b49454d..9279037cf12 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -877,6 +877,10 @@ class LoadVectorGatherNode : public LoadVectorNode { virtual int Opcode() const; virtual uint match_edge(uint idx) const { return idx == MemNode::Address || idx == MemNode::ValueIn; } + virtual int store_Opcode() const { + // Ensure it is different from any store opcode to avoid folding when indices are used + return -1; + } }; //------------------------------StoreVectorNode-------------------------------- @@ -908,6 +912,8 @@ class StoreVectorNode : public StoreNode { // Needed for proper cloning. virtual uint size_of() const { return sizeof(*this); } + virtual Node* mask() const { return nullptr; } + virtual Node* indices() const { return nullptr; } }; //------------------------------StoreVectorScatterNode------------------------------ @@ -915,6 +921,7 @@ class StoreVectorNode : public StoreNode { class StoreVectorScatterNode : public StoreVectorNode { public: + enum { Indices = 4 }; StoreVectorScatterNode(Node* c, Node* mem, Node* adr, const TypePtr* at, Node* val, Node* indices) : StoreVectorNode(c, mem, adr, at, val) { init_class_id(Class_StoreVectorScatter); @@ -926,12 +933,14 @@ class StoreVectorNode : public StoreNode { virtual uint match_edge(uint idx) const { return idx == MemNode::Address || idx == MemNode::ValueIn || idx == MemNode::ValueIn + 1; } + virtual Node* indices() const { return in(Indices); } }; //------------------------------StoreVectorMaskedNode-------------------------------- // Store Vector to memory under the influence of a predicate register(mask). class StoreVectorMaskedNode : public StoreVectorNode { public: + enum { Mask = 4 }; StoreVectorMaskedNode(Node* c, Node* mem, Node* dst, Node* src, const TypePtr* at, Node* mask) : StoreVectorNode(c, mem, dst, at, src) { init_class_id(Class_StoreVectorMasked); @@ -945,6 +954,7 @@ class StoreVectorMaskedNode : public StoreVectorNode { return idx > 1; } virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + virtual Node* mask() const { return in(Mask); } }; //------------------------------LoadVectorMaskedNode-------------------------------- @@ -965,6 +975,10 @@ class LoadVectorMaskedNode : public LoadVectorNode { return idx > 1; } virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + virtual int store_Opcode() const { + // Ensure it is different from any store opcode to avoid folding when a mask is used + return -1; + } }; //-------------------------------LoadVectorGatherMaskedNode--------------------------------- @@ -985,12 +999,19 @@ class LoadVectorGatherMaskedNode : public LoadVectorNode { virtual uint match_edge(uint idx) const { return idx == MemNode::Address || idx == MemNode::ValueIn || idx == MemNode::ValueIn + 1; } + virtual int store_Opcode() const { + // Ensure it is different from any store opcode to avoid folding when indices and mask are used + return -1; + } }; //------------------------------StoreVectorScatterMaskedNode-------------------------------- // Store Vector into memory via index map under the influence of a predicate register(mask). class StoreVectorScatterMaskedNode : public StoreVectorNode { public: + enum { Indices = 4, + Mask + }; StoreVectorScatterMaskedNode(Node* c, Node* mem, Node* adr, const TypePtr* at, Node* val, Node* indices, Node* mask) : StoreVectorNode(c, mem, adr, at, val) { init_class_id(Class_StoreVectorScatterMasked); @@ -1005,6 +1026,8 @@ class StoreVectorScatterMaskedNode : public StoreVectorNode { idx == MemNode::ValueIn || idx == MemNode::ValueIn + 1 || idx == MemNode::ValueIn + 2; } + virtual Node* mask() const { return in(Mask); } + virtual Node* indices() const { return in(Indices); } }; //------------------------------VectorCmpMaskedNode-------------------------------- diff --git a/src/hotspot/share/prims/forte.cpp b/src/hotspot/share/prims/forte.cpp index 412c1496336..6615ccd2c89 100644 --- a/src/hotspot/share/prims/forte.cpp +++ b/src/hotspot/share/prims/forte.cpp @@ -601,7 +601,7 @@ void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) { return; } - if (Universe::heap()->is_gc_active()) { + if (Universe::heap()->is_stw_gc_active()) { trace->num_frames = ticks_GC_active; // -2 return; } diff --git a/src/hotspot/share/prims/jniCheck.cpp b/src/hotspot/share/prims/jniCheck.cpp index 70598dc7eb7..0da0cbbd639 100644 --- a/src/hotspot/share/prims/jniCheck.cpp +++ b/src/hotspot/share/prims/jniCheck.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2295,7 +2295,7 @@ struct JNINativeInterface_* jni_functions_check() { // make sure the last pointer in the checked table is not null, indicating // an addition to the JNINativeInterface_ structure without initializing // it in the checked table. - debug_only(int *lastPtr = (int *)((char *)&checked_jni_NativeInterface + \ + debug_only(intptr_t *lastPtr = (intptr_t *)((char *)&checked_jni_NativeInterface + \ sizeof(*unchecked_jni_NativeInterface) - sizeof(char *));) assert(*lastPtr != 0, "Mismatched JNINativeInterface tables, check for new entries"); diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 7c67a0eebfa..d4b924b78c6 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -1515,8 +1515,12 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec // Number of waiters may actually be less than the waiter count. // So null out memory so that unused memory will be null. - memset(ret.waiters, 0, ret.waiter_count * sizeof(jthread *)); - memset(ret.notify_waiters, 0, ret.notify_waiter_count * sizeof(jthread *)); + if (ret.waiters != nullptr) { + memset(ret.waiters, 0, ret.waiter_count * sizeof(jthread *)); + } + if (ret.notify_waiters != nullptr) { + memset(ret.notify_waiters, 0, ret.notify_waiter_count * sizeof(jthread *)); + } if (ret.waiter_count > 0) { // we have contending and/or waiting threads diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 0466bf80960..f7a57ab57c6 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -382,6 +382,7 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { if (JvmtiEnv::get_phase() == JVMTI_PHASE_LIVE) { JavaThread* current_thread = JavaThread::current(); // transition code: native to VM + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current_thread)); ThreadInVMfromNative __tiv(current_thread); VM_ENTRY_BASE(jvmtiEnv*, JvmtiExport::get_jvmti_interface, current_thread) debug_only(VMNativeEntryWrapper __vew;) @@ -928,7 +929,9 @@ class JvmtiClassFileLoadHookPoster : public StackObj { _cached_class_file_ptr = cache_ptr; _has_been_modified = false; - assert(!_thread->is_in_any_VTMS_transition(), "CFLH events are not allowed in any VTMS transition"); + if (_thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition + } _state = JvmtiExport::get_jvmti_thread_state(_thread); if (_state != nullptr) { _class_being_redefined = _state->get_class_being_redefined(); @@ -1362,10 +1365,9 @@ void JvmtiExport::post_class_load(JavaThread *thread, Klass* klass) { if (state == nullptr) { return; } - if (thread->is_in_tmp_VTMS_transition()) { - return; // skip ClassLoad events in tmp VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } - assert(!thread->is_in_any_VTMS_transition(), "class load events are not allowed in any VTMS transition"); EVT_TRIG_TRACE(JVMTI_EVENT_CLASS_LOAD, ("[%s] Trg Class Load triggered", JvmtiTrace::safe_get_thread_name(thread))); @@ -1400,10 +1402,9 @@ void JvmtiExport::post_class_prepare(JavaThread *thread, Klass* klass) { if (state == nullptr) { return; } - if (thread->is_in_tmp_VTMS_transition()) { - return; // skip ClassPrepare events in tmp VTMS transition + if (thread->is_in_any_VTMS_transition()) { + return; // no events should be posted if thread is in any VTMS transition } - assert(!thread->is_in_any_VTMS_transition(), "class prepare events are not allowed in any VTMS transition"); EVT_TRIG_TRACE(JVMTI_EVENT_CLASS_PREPARE, ("[%s] Trg Class Prepare triggered", JvmtiTrace::safe_get_thread_name(thread))); diff --git a/src/hotspot/share/prims/jvmtiExtensions.cpp b/src/hotspot/share/prims/jvmtiExtensions.cpp index b40ad7ddbd1..c1767454227 100644 --- a/src/hotspot/share/prims/jvmtiExtensions.cpp +++ b/src/hotspot/share/prims/jvmtiExtensions.cpp @@ -130,6 +130,7 @@ static jvmtiError JNICALL GetCarrierThread(const jvmtiEnv* env, ...) { thread_ptr = va_arg(ap, jthread*); va_end(ap); + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current_thread)); ThreadInVMfromNative tiv(current_thread); JvmtiVTMSTransitionDisabler disabler; diff --git a/src/hotspot/share/prims/jvmtiTagMapTable.hpp b/src/hotspot/share/prims/jvmtiTagMapTable.hpp index 2f8f14be215..d534da07c6f 100644 --- a/src/hotspot/share/prims/jvmtiTagMapTable.hpp +++ b/src/hotspot/share/prims/jvmtiTagMapTable.hpp @@ -54,7 +54,7 @@ class JvmtiTagMapKey : public CHeapObj { static unsigned get_hash(const JvmtiTagMapKey& entry) { assert(entry._obj != nullptr, "must lookup obj to hash"); - return entry._obj->identity_hash(); + return (unsigned)entry._obj->identity_hash(); } static bool equals(const JvmtiTagMapKey& lhs, const JvmtiTagMapKey& rhs) { diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 323f15844dc..ebb82b4abef 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -55,6 +55,7 @@ #include "runtime/threadSMR.hpp" #include "runtime/vmOperations.hpp" #include "runtime/vm_version.hpp" +#include "sanitizers/ub.hpp" #include "services/threadService.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" @@ -131,13 +132,9 @@ static inline void assert_field_offset_sane(oop p, jlong field_offset) { static inline void* index_oop_from_field_offset_long(oop p, jlong field_offset) { assert_field_offset_sane(p, field_offset); - jlong byte_offset = field_offset_to_byte_offset(field_offset); - - if (sizeof(char*) == sizeof(jint)) { // (this constant folds!) - return cast_from_oop
(p) + (jint) byte_offset; - } else { - return cast_from_oop
(p) + byte_offset; - } + uintptr_t base_address = cast_from_oop(p); + uintptr_t byte_offset = (uintptr_t)field_offset_to_byte_offset(field_offset); + return (void*)(base_address + byte_offset); } // Externally callable versions: @@ -223,6 +220,9 @@ class MemoryAccess : StackObj { return normalize_for_read(*addr()); } + // we use this method at some places for writing to 0 e.g. to cause a crash; + // ubsan does not know that this is the desired behavior + ATTRIBUTE_NO_UBSAN void put(T x) { GuardUnsafeAccess guard(_thread); *addr() = normalize_for_write(x); diff --git a/src/hotspot/share/runtime/continuationEntry.cpp b/src/hotspot/share/runtime/continuationEntry.cpp index 4482350ff06..42d4cb12486 100644 --- a/src/hotspot/share/runtime/continuationEntry.cpp +++ b/src/hotspot/share/runtime/continuationEntry.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "oops/method.inline.hpp" #include "runtime/continuation.hpp" #include "runtime/continuationEntry.inline.hpp" +#include "runtime/continuationHelper.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/javaThread.hpp" #include "runtime/stackFrameStream.inline.hpp" @@ -134,7 +135,8 @@ bool ContinuationEntry::assert_entry_frame_laid_out(JavaThread* thread) { assert(sp != nullptr, ""); assert(sp <= entry->entry_sp(), ""); - address pc = *(address*)(sp - frame::sender_sp_ret_address_offset()); + address pc = ContinuationHelper::return_address_at( + sp - frame::sender_sp_ret_address_offset()); if (pc != StubRoutines::cont_returnBarrier()) { CodeBlob* cb = pc != nullptr ? CodeCache::find_blob(pc) : nullptr; diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 0882bc933c2..5de00b77366 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -299,7 +299,8 @@ inline void clear_anchor(JavaThread* thread) { } static void set_anchor(JavaThread* thread, intptr_t* sp) { - address pc = *(address*)(sp - frame::sender_sp_ret_address_offset()); + address pc = ContinuationHelper::return_address_at( + sp - frame::sender_sp_ret_address_offset()); assert(pc != nullptr, ""); JavaFrameAnchor* anchor = thread->frame_anchor(); @@ -402,7 +403,7 @@ class FreezeBase : public StackObj { inline void patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp); // slow path - virtual stackChunkOop allocate_chunk_slow(size_t stack_size) = 0; + virtual stackChunkOop allocate_chunk_slow(size_t stack_size, int argsize_md) = 0; int cont_size() { return _cont_stack_bottom - _cont_stack_top; } @@ -437,20 +438,12 @@ class FreezeBase : public StackObj { protected: void freeze_fast_copy(stackChunkOop chunk, int chunk_start_sp CONT_JFR_ONLY(COMMA bool chunk_is_allocated)); bool freeze_fast_new_chunk(stackChunkOop chunk); - -#ifdef ASSERT - bool is_empty(stackChunkOop chunk) { - // during freeze, the chunk is in an intermediate state (after setting the chunk's argsize but before setting its - // ultimate sp) so we use this instead of stackChunkOopDesc::is_empty - return chunk->sp() >= chunk->stack_size() - chunk->argsize() - frame::metadata_words_at_top; - } -#endif }; template class Freeze : public FreezeBase { private: - stackChunkOop allocate_chunk(size_t stack_size); + stackChunkOop allocate_chunk(size_t stack_size, int argsize_md); public: inline Freeze(JavaThread* thread, ContinuationWrapper& cont, intptr_t* frame_sp) @@ -459,7 +452,7 @@ class Freeze : public FreezeBase { freeze_result try_freeze_fast(); protected: - virtual stackChunkOop allocate_chunk_slow(size_t stack_size) override { return allocate_chunk(stack_size); } + virtual stackChunkOop allocate_chunk_slow(size_t stack_size, int argsize_md) override { return allocate_chunk(stack_size, argsize_md); } }; FreezeBase::FreezeBase(JavaThread* thread, ContinuationWrapper& cont, intptr_t* frame_sp) : @@ -542,7 +535,7 @@ freeze_result Freeze::try_freeze_fast() { DEBUG_ONLY(_fast_freeze_size = size_if_fast_freeze_available();) assert(_fast_freeze_size == 0, ""); - stackChunkOop chunk = allocate_chunk(cont_size() + frame::metadata_words); + stackChunkOop chunk = allocate_chunk(cont_size() + frame::metadata_words, _cont.argsize() + frame::metadata_words_at_top); if (freeze_fast_new_chunk(chunk)) { return freeze_ok; } @@ -571,7 +564,7 @@ int FreezeBase::size_if_fast_freeze_available() { // so we subtract it only if we overlap with the caller, i.e. the current chunk isn't empty. // Consider leaving the chunk's argsize set when emptying it and removing the following branch, // although that would require changing stackChunkOopDesc::is_empty - if (chunk_sp < chunk->stack_size()) { + if (!chunk->is_empty()) { total_size_needed -= _cont.argsize() + frame::metadata_words_at_top; } @@ -584,15 +577,21 @@ int FreezeBase::size_if_fast_freeze_available() { void FreezeBase::freeze_fast_existing_chunk() { stackChunkOop chunk = _cont.tail(); - DEBUG_ONLY(_orig_chunk_sp = chunk->sp_address();) DEBUG_ONLY(_fast_freeze_size = size_if_fast_freeze_available();) assert(_fast_freeze_size > 0, ""); - if (chunk->sp() < chunk->stack_size()) { // we are copying into a non-empty chunk + if (!chunk->is_empty()) { // we are copying into a non-empty chunk DEBUG_ONLY(_empty = false;) - assert(chunk->sp() < (chunk->stack_size() - chunk->argsize()), ""); - assert(*(address*)(chunk->sp_address() - frame::sender_sp_ret_address_offset()) == chunk->pc(), ""); + DEBUG_ONLY(_orig_chunk_sp = chunk->sp_address();) +#ifdef ASSERT + { + intptr_t* retaddr_slot = (chunk->sp_address() + - frame::sender_sp_ret_address_offset()); + assert(ContinuationHelper::return_address_at(retaddr_slot) == chunk->pc(), + "unexpected saved return address"); + } +#endif // the chunk's sp before the freeze, adjusted to point beyond the stack-passed arguments in the topmost frame // we overlap; we'll overwrite the chunk's top frame's callee arguments @@ -606,8 +605,15 @@ void FreezeBase::freeze_fast_existing_chunk() { assert(bottom_sp == _bottom_address, ""); // Because the chunk isn't empty, we know there's a caller in the chunk, therefore the bottom-most frame // should have a return barrier (installed back when we thawed it). - assert(*(address*)(bottom_sp-frame::sender_sp_ret_address_offset()) == StubRoutines::cont_returnBarrier(), - "should be the continuation return barrier"); +#ifdef ASSERT + { + intptr_t* retaddr_slot = (bottom_sp + - frame::sender_sp_ret_address_offset()); + assert(ContinuationHelper::return_address_at(retaddr_slot) + == StubRoutines::cont_returnBarrier(), + "should be the continuation return barrier"); + } +#endif // We copy the fp from the chunk back to the stack because it contains some caller data, // including, possibly, an oop that might have gone stale since we thawed. patch_stack_pd(bottom_sp, chunk->sp_address()); @@ -615,13 +621,14 @@ void FreezeBase::freeze_fast_existing_chunk() { freeze_fast_copy(chunk, chunk_start_sp CONT_JFR_ONLY(COMMA false)); } else { // the chunk is empty - DEBUG_ONLY(_empty = true;) - const int chunk_start_sp = chunk->sp(); + const int chunk_start_sp = chunk->stack_size(); - assert(chunk_start_sp == chunk->stack_size(), ""); + DEBUG_ONLY(_empty = true;) + DEBUG_ONLY(_orig_chunk_sp = chunk->start_address() + chunk_start_sp;) chunk->set_max_thawing_size(cont_size()); - chunk->set_argsize(_cont.argsize()); + chunk->set_bottom(chunk_start_sp - _cont.argsize() - frame::metadata_words_at_top); + chunk->set_sp(chunk->bottom()); freeze_fast_copy(chunk, chunk_start_sp CONT_JFR_ONLY(COMMA false)); } @@ -639,7 +646,6 @@ bool FreezeBase::freeze_fast_new_chunk(stackChunkOop chunk) { } chunk->set_max_thawing_size(cont_size()); - chunk->set_argsize(_cont.argsize()); // in a fresh chunk, we freeze *with* the bottom-most frame's stack arguments. // They'll then be stored twice: in the chunk and in the parent chunk's top frame @@ -675,7 +681,14 @@ void FreezeBase::freeze_fast_copy(stackChunkOop chunk, int chunk_start_sp CONT_J assert(!(_fast_freeze_size > 0) || _orig_chunk_sp - (chunk->start_address() + chunk_new_sp) == _fast_freeze_size, ""); intptr_t* chunk_top = chunk->start_address() + chunk_new_sp; - assert(_empty || *(address*)(_orig_chunk_sp - frame::sender_sp_ret_address_offset()) == chunk->pc(), ""); +#ifdef ASSERT + if (!_empty) { + intptr_t* retaddr_slot = (_orig_chunk_sp + - frame::sender_sp_ret_address_offset()); + assert(ContinuationHelper::return_address_at(retaddr_slot) == chunk->pc(), + "unexpected saved return address"); + } +#endif log_develop_trace(continuations)("freeze_fast start: " INTPTR_FORMAT " sp: %d chunk_top: " INTPTR_FORMAT, p2i(chunk->start_address()), chunk_new_sp, p2i(chunk_top)); @@ -684,15 +697,27 @@ void FreezeBase::freeze_fast_copy(stackChunkOop chunk, int chunk_start_sp CONT_J copy_to_chunk(from, to, cont_size() + frame::metadata_words_at_bottom); // Because we're not patched yet, the chunk is now in a bad state - // patch return pc of the bottom-most frozen frame (now in the chunk) with the actual caller's return address - intptr_t* chunk_bottom_sp = chunk_top + cont_size() - _cont.argsize() - frame::metadata_words_at_top; - assert(_empty || *(address*)(chunk_bottom_sp-frame::sender_sp_ret_address_offset()) == StubRoutines::cont_returnBarrier(), ""); - *(address*)(chunk_bottom_sp - frame::sender_sp_ret_address_offset()) = chunk->pc(); + // patch return pc of the bottom-most frozen frame (now in the chunk) + // with the actual caller's return address + intptr_t* chunk_bottom_retaddr_slot = (chunk_top + cont_size() + - _cont.argsize() + - frame::metadata_words_at_top + - frame::sender_sp_ret_address_offset()); +#ifdef ASSERT + if (!_empty) { + assert(ContinuationHelper::return_address_at(chunk_bottom_retaddr_slot) + == StubRoutines::cont_returnBarrier(), + "should be the continuation return barrier"); + } +#endif + ContinuationHelper::patch_return_address_at(chunk_bottom_retaddr_slot, + chunk->pc()); // We're always writing to a young chunk, so the GC can't see it until the next safepoint. chunk->set_sp(chunk_new_sp); // set chunk->pc to the return address of the topmost frame in the chunk - chunk->set_pc(*(address*)(_cont_stack_top - frame::sender_sp_ret_address_offset())); + chunk->set_pc(ContinuationHelper::return_address_at( + _cont_stack_top - frame::sender_sp_ret_address_offset())); _cont.write(); @@ -897,7 +922,6 @@ freeze_result FreezeBase::finalize_freeze(const frame& callee, frame& caller, in int overlap = 0; // the args overlap the caller -- if there is one in this chunk and is of the same kind int unextended_sp = -1; if (chunk != nullptr) { - unextended_sp = chunk->sp(); if (!chunk->is_empty()) { StackChunkFrameStream last(chunk); unextended_sp = chunk->to_offset(StackChunkFrameStream(chunk).unextended_sp()); @@ -905,6 +929,8 @@ freeze_result FreezeBase::finalize_freeze(const frame& callee, frame& caller, in if (callee.is_interpreted_frame() == top_interpreted) { overlap = argsize_md; } + } else { + unextended_sp = chunk->stack_size() - frame::metadata_words_at_top; } } @@ -942,25 +968,21 @@ freeze_result FreezeBase::finalize_freeze(const frame& callee, frame& caller, in _freeze_size += overlap; // we're allocating a new chunk, so no overlap // overlap = 0; - chunk = allocate_chunk_slow(_freeze_size); + chunk = allocate_chunk_slow(_freeze_size, argsize_md); if (chunk == nullptr) { return freeze_exception; } // Install new chunk _cont.set_tail(chunk); - - int sp = chunk->stack_size() - argsize_md; - chunk->set_sp(sp); - chunk->set_argsize(argsize); - assert(is_empty(chunk), ""); + assert(chunk->is_empty(), ""); } else { // REUSE EXISTING CHUNK log_develop_trace(continuations)("Reusing chunk mixed: %d empty: %d", chunk->has_mixed_frames(), chunk->is_empty()); if (chunk->is_empty()) { int sp = chunk->stack_size() - argsize_md; chunk->set_sp(sp); - chunk->set_argsize(argsize); + chunk->set_bottom(sp); _freeze_size += overlap; assert(chunk->max_thawing_size() == 0, ""); } DEBUG_ONLY(else empty_chunk = false;) @@ -970,10 +992,10 @@ freeze_result FreezeBase::finalize_freeze(const frame& callee, frame& caller, in chunk->set_has_mixed_frames(true); assert(chunk->requires_barriers() == _barriers, ""); - assert(!_barriers || is_empty(chunk), ""); + assert(!_barriers || chunk->is_empty(), ""); - assert(!is_empty(chunk) || StackChunkFrameStream(chunk).is_done(), ""); - assert(!is_empty(chunk) || StackChunkFrameStream(chunk).to_frame().is_empty(), ""); + assert(!chunk->is_empty() || StackChunkFrameStream(chunk).is_done(), ""); + assert(!chunk->is_empty() || StackChunkFrameStream(chunk).to_frame().is_empty(), ""); // We unwind frames after the last safepoint so that the GC will have found the oops in the frames, but before // writing into the chunk. This is so that an asynchronous stack walk (not at a safepoint) that suspends us here @@ -1019,7 +1041,7 @@ void FreezeBase::patch(const frame& f, frame& hf, const frame& caller, bool is_b // If we're the bottom frame, we need to replace the return barrier with the real // caller's pc. address last_pc = caller.pc(); - assert((last_pc == nullptr) == is_empty(_cont.tail()), ""); + assert((last_pc == nullptr) == _cont.tail()->is_empty(), ""); ContinuationHelper::Frame::patch_pc(caller, last_pc); } else { assert(!caller.is_empty(), ""); @@ -1208,7 +1230,6 @@ NOINLINE freeze_result FreezeBase::recurse_freeze_stub_frame(frame& f, frame& ca NOINLINE void FreezeBase::finish_freeze(const frame& f, const frame& top) { stackChunkOop chunk = _cont.tail(); - assert(chunk->to_offset(top.sp()) <= chunk->sp(), ""); LogTarget(Trace, continuations) lt; if (lt.develop_is_enabled()) { @@ -1273,6 +1294,7 @@ inline bool FreezeBase::stack_overflow() { // detect stack overflow in recursive class StackChunkAllocator : public MemAllocator { const size_t _stack_size; + int _argsize_md; ContinuationWrapper& _continuation_wrapper; JvmtiSampledObjectAllocEventCollector* const _jvmti_event_collector; mutable bool _took_slow_path; @@ -1288,8 +1310,11 @@ class StackChunkAllocator : public MemAllocator { const size_t hs = oopDesc::header_size(); Copy::fill_to_aligned_words(mem + hs, vmClasses::StackChunk_klass()->size_helper() - hs); + int bottom = (int)_stack_size - _argsize_md; + jdk_internal_vm_StackChunk::set_size(mem, (int)_stack_size); - jdk_internal_vm_StackChunk::set_sp(mem, (int)_stack_size); + jdk_internal_vm_StackChunk::set_bottom(mem, bottom); + jdk_internal_vm_StackChunk::set_sp(mem, bottom); return finish(mem); } @@ -1313,10 +1338,12 @@ class StackChunkAllocator : public MemAllocator { size_t word_size, Thread* thread, size_t stack_size, + int argsize_md, ContinuationWrapper& continuation_wrapper, JvmtiSampledObjectAllocEventCollector* jvmti_event_collector) : MemAllocator(klass, word_size, thread), _stack_size(stack_size), + _argsize_md(argsize_md), _continuation_wrapper(continuation_wrapper), _jvmti_event_collector(jvmti_event_collector), _took_slow_path(false) {} @@ -1350,7 +1377,7 @@ class StackChunkAllocator : public MemAllocator { }; template -stackChunkOop Freeze::allocate_chunk(size_t stack_size) { +stackChunkOop Freeze::allocate_chunk(size_t stack_size, int argsize_md) { log_develop_trace(continuations)("allocate_chunk allocating new chunk"); InstanceStackChunkKlass* klass = InstanceStackChunkKlass::cast(vmClasses::StackChunk_klass()); @@ -1372,7 +1399,7 @@ stackChunkOop Freeze::allocate_chunk(size_t stack_size) { // instrumentation have been deferred. This property is important for // some GCs, as this ensures that the allocated object is in the young // generation / newly allocated memory. - StackChunkAllocator allocator(klass, size_in_words, current, stack_size, _cont, _jvmti_event_collector); + StackChunkAllocator allocator(klass, size_in_words, current, stack_size, argsize_md, _cont, _jvmti_event_collector); stackChunkOop chunk = allocator.allocate(); if (chunk == nullptr) { @@ -1382,11 +1409,11 @@ stackChunkOop Freeze::allocate_chunk(size_t stack_size) { // assert that chunk is properly initialized assert(chunk->stack_size() == (int)stack_size, ""); assert(chunk->size() >= stack_size, "chunk->size(): %zu size: %zu", chunk->size(), stack_size); - assert(chunk->sp() == chunk->stack_size(), ""); + assert(chunk->sp() == chunk->bottom(), ""); assert((intptr_t)chunk->start_address() % 8 == 0, ""); assert(chunk->max_thawing_size() == 0, ""); assert(chunk->pc() == nullptr, ""); - assert(chunk->argsize() == 0, ""); + assert(chunk->is_empty(), ""); assert(chunk->flags() == 0, ""); assert(chunk->is_gc_mode() == false, ""); @@ -1819,12 +1846,11 @@ class ReconstructedStack : public StackObj { }; inline void ThawBase::clear_chunk(stackChunkOop chunk) { - chunk->set_sp(chunk->stack_size()); - chunk->set_argsize(0); + chunk->set_sp(chunk->bottom()); chunk->set_max_thawing_size(0); } - int ThawBase::remove_top_compiled_frame_from_chunk(stackChunkOop chunk, int &argsize) { +int ThawBase::remove_top_compiled_frame_from_chunk(stackChunkOop chunk, int &argsize) { bool empty = false; StackChunkFrameStream f(chunk); DEBUG_ONLY(intptr_t* const chunk_sp = chunk->start_address() + chunk->sp();) @@ -1834,7 +1860,7 @@ inline void ThawBase::clear_chunk(stackChunkOop chunk) { const int frame_size = f.cb()->frame_size(); argsize = f.stack_argsize(); - f.next(SmallRegisterMap::instance, true /* stop */); + f.next(SmallRegisterMap::instance(), true /* stop */); empty = f.is_done(); assert(!empty || argsize == chunk->argsize(), ""); @@ -1845,7 +1871,15 @@ inline void ThawBase::clear_chunk(stackChunkOop chunk) { chunk->set_max_thawing_size(chunk->max_thawing_size() - frame_size); // We set chunk->pc to the return pc into the next frame chunk->set_pc(f.pc()); - assert(f.pc() == *(address*)(chunk_sp + frame_size - frame::sender_sp_ret_address_offset()), "unexpected pc"); +#ifdef ASSERT + { + intptr_t* retaddr_slot = (chunk_sp + + frame_size + - frame::sender_sp_ret_address_offset()); + assert(f.pc() == ContinuationHelper::return_address_at(retaddr_slot), + "unexpected pc"); + } +#endif } assert(empty == chunk->is_empty(), ""); // returns the size required to store the frame on stack, and because it is a @@ -1865,7 +1899,9 @@ void ThawBase::patch_return(intptr_t* sp, bool is_last) { log_develop_trace(continuations)("thaw_fast patching -- sp: " INTPTR_FORMAT, p2i(sp)); address pc = !is_last ? StubRoutines::cont_returnBarrier() : _cont.entryPC(); - *(address*)(sp - frame::sender_sp_ret_address_offset()) = pc; + ContinuationHelper::patch_return_address_at( + sp - frame::sender_sp_ret_address_offset(), + pc); } template @@ -2034,7 +2070,7 @@ bool ThawBase::recurse_thaw_java_frame(frame& caller, int num_frames) { int argsize = _stream.stack_argsize(); - _stream.next(SmallRegisterMap::instance); + _stream.next(SmallRegisterMap::instance()); assert(_stream.to_frame().is_empty() == _stream.is_done(), ""); // we never leave a compiled caller of an interpreted frame as the top frame in the chunk @@ -2061,8 +2097,7 @@ void ThawBase::finalize_thaw(frame& entry, int argsize) { chunk->set_sp(chunk->to_offset(_stream.sp())); chunk->set_pc(_stream.pc()); } else { - chunk->set_argsize(0); - chunk->set_sp(chunk->stack_size()); + chunk->set_sp(chunk->bottom()); chunk->set_pc(nullptr); } assert(_stream.is_done() == chunk->is_empty(), ""); @@ -2143,7 +2178,7 @@ NOINLINE void ThawBase::recurse_thaw_interpreted_frame(const frame& hf, frame& c assert(hf.is_interpreted_frame(), ""); if (UNLIKELY(seen_by_gc())) { - _cont.tail()->do_barriers(_stream, SmallRegisterMap::instance); + _cont.tail()->do_barriers(_stream, SmallRegisterMap::instance()); } const bool is_bottom_frame = recurse_thaw_java_frame(caller, num_frames); @@ -2186,7 +2221,7 @@ NOINLINE void ThawBase::recurse_thaw_interpreted_frame(const frame& hf, frame& c if (!is_bottom_frame) { // can only fix caller once this frame is thawed (due to callee saved regs) - _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance); + _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance()); } else if (_cont.tail()->has_bitmap() && locals > 0) { assert(hf.is_heap_frame(), "should be"); address start = (address)(heap_frame_bottom - locals); @@ -2203,7 +2238,7 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n assert(_cont.is_preempted() || !stub_caller, "stub caller not at preemption"); if (!stub_caller && UNLIKELY(seen_by_gc())) { // recurse_thaw_stub_frame already invoked our barriers with a full regmap - _cont.tail()->do_barriers(_stream, SmallRegisterMap::instance); + _cont.tail()->do_barriers(_stream, SmallRegisterMap::instance()); } const bool is_bottom_frame = recurse_thaw_java_frame(caller, num_frames); @@ -2262,10 +2297,10 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n if (!is_bottom_frame) { // can only fix caller once this frame is thawed (due to callee saved regs); this happens on the stack - _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance); + _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance()); } else if (_cont.tail()->has_bitmap() && added_argsize > 0) { address start = (address)(heap_frame_top + ContinuationHelper::CompiledFrame::size(hf) + frame::metadata_words_at_top); - int stack_args_slots = f.cb()->as_compiled_method()->method()->num_stack_arg_slots(false /* rounded */); + int stack_args_slots = f.cb()->as_nmethod()->num_stack_arg_slots(false /* rounded */); int argsize_in_bytes = stack_args_slots * VMRegImpl::stack_slot_size; clear_bitmap_bits(start, start + argsize_in_bytes); } @@ -2334,7 +2369,6 @@ void ThawBase::finish_thaw(frame& f) { chunk->set_has_mixed_frames(false); } chunk->set_max_thawing_size(0); - assert(chunk->argsize() == 0, ""); } else { chunk->set_max_thawing_size(chunk->max_thawing_size() - _align_size); } @@ -2345,7 +2379,7 @@ void ThawBase::finish_thaw(frame& f) { f.set_sp(align_down(f.sp(), frame::frame_alignment)); } push_return_frame(f); - chunk->fix_thawed_frame(f, SmallRegisterMap::instance); // can only fix caller after push_return_frame (due to callee saved regs) + chunk->fix_thawed_frame(f, SmallRegisterMap::instance()); // can only fix caller after push_return_frame (due to callee saved regs) assert(_cont.is_empty() == _cont.last_frame().is_empty(), ""); @@ -2416,7 +2450,6 @@ static inline intptr_t* thaw_internal(JavaThread* thread, const Continuation::th #ifdef ASSERT intptr_t* sp0 = sp; - address pc0 = *(address*)(sp - frame::sender_sp_ret_address_offset()); set_anchor(thread, sp0); log_frames(thread); if (LoomVerifyAfterThaw) { diff --git a/src/hotspot/share/runtime/continuationHelper.hpp b/src/hotspot/share/runtime/continuationHelper.hpp index e3958632975..6d8474e1844 100644 --- a/src/hotspot/share/runtime/continuationHelper.hpp +++ b/src/hotspot/share/runtime/continuationHelper.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ class ContinuationHelper { static inline void push_pd(const frame& f); + static inline address return_address_at(intptr_t* sp); + static inline void patch_return_address_at(intptr_t* sp, address pc); + static inline int frame_align_words(int size); static inline intptr_t* frame_align_pointer(intptr_t* sp); @@ -68,7 +71,7 @@ class ContinuationHelper::Frame : public AllStatic { static inline address real_pc(const frame& f); static inline void patch_pc(const frame& f, address pc); static address* return_pc_address(const frame& f); - static address return_pc(const frame& f) { return *return_pc_address(f); } + static address return_pc(const frame& f); static bool is_stub(CodeBlob* cb); #ifdef ASSERT diff --git a/src/hotspot/share/runtime/continuationHelper.inline.hpp b/src/hotspot/share/runtime/continuationHelper.inline.hpp index 4e74a7871b9..402703f1b19 100644 --- a/src/hotspot/share/runtime/continuationHelper.inline.hpp +++ b/src/hotspot/share/runtime/continuationHelper.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,17 @@ #include CPU_HEADER_INLINE(continuationHelper) +#ifndef CPU_OVERRIDES_RETURN_ADDRESS_ACCESSORS +inline address ContinuationHelper::return_address_at(intptr_t* sp) { + return *(address*)sp; +} + +inline void ContinuationHelper::patch_return_address_at(intptr_t* sp, + address pc) { + *(address*)sp = pc; +} +#endif // !CPU_OVERRIDES_RETURN_ADDRESS_ACCESSORS + inline bool ContinuationHelper::NonInterpretedUnknownFrame::is_instance(const frame& f) { return !f.is_interpreted_frame(); } @@ -49,6 +60,10 @@ inline Method* ContinuationHelper::Frame::frame_method(const frame& f) { return f.is_interpreted_frame() ? f.interpreter_frame_method() : f.cb()->as_compiled_method()->method(); } +inline address ContinuationHelper::Frame::return_pc(const frame& f) { + return return_address_at((intptr_t *)return_pc_address(f)); +} + #ifdef ASSERT inline intptr_t* ContinuationHelper::Frame::frame_top(const frame &f) { if (f.is_interpreted_frame()) { @@ -75,11 +90,11 @@ inline bool ContinuationHelper::InterpretedFrame::is_instance(const frame& f) { } inline address ContinuationHelper::InterpretedFrame::return_pc(const frame& f) { - return *return_pc_address(f); + return return_address_at((intptr_t *)return_pc_address(f)); } inline int ContinuationHelper::InterpretedFrame::size(const frame&f) { - return InterpretedFrame::frame_bottom(f) - InterpretedFrame::frame_top(f); + return pointer_delta_as_int(InterpretedFrame::frame_bottom(f), InterpretedFrame::frame_top(f)); } inline int ContinuationHelper::InterpretedFrame::stack_argsize(const frame& f) { diff --git a/src/hotspot/share/runtime/continuationJavaClasses.cpp b/src/hotspot/share/runtime/continuationJavaClasses.cpp index 1185af8d6a0..d9f2d05b7e9 100644 --- a/src/hotspot/share/runtime/continuationJavaClasses.cpp +++ b/src/hotspot/share/runtime/continuationJavaClasses.cpp @@ -84,7 +84,7 @@ int jdk_internal_vm_StackChunk::_parent_offset; int jdk_internal_vm_StackChunk::_size_offset; int jdk_internal_vm_StackChunk::_sp_offset; int jdk_internal_vm_StackChunk::_pc_offset; -int jdk_internal_vm_StackChunk::_argsize_offset; +int jdk_internal_vm_StackChunk::_bottom_offset; int jdk_internal_vm_StackChunk::_flags_offset; int jdk_internal_vm_StackChunk::_maxThawingSize_offset; int jdk_internal_vm_StackChunk::_cont_offset; @@ -93,7 +93,7 @@ int jdk_internal_vm_StackChunk::_cont_offset; macro(_parent_offset, k, vmSymbols::parent_name(), stackchunk_signature, false); \ macro(_size_offset, k, vmSymbols::size_name(), int_signature, false); \ macro(_sp_offset, k, vmSymbols::sp_name(), int_signature, false); \ - macro(_argsize_offset, k, vmSymbols::argsize_name(), int_signature, false); + macro(_bottom_offset, k, vmSymbols::bottom_name(), int_signature, false); void jdk_internal_vm_StackChunk::compute_offsets() { InstanceKlass* k = vmClasses::StackChunk_klass(); diff --git a/src/hotspot/share/runtime/continuationJavaClasses.hpp b/src/hotspot/share/runtime/continuationJavaClasses.hpp index 54d10d04154..05cba90a0f5 100644 --- a/src/hotspot/share/runtime/continuationJavaClasses.hpp +++ b/src/hotspot/share/runtime/continuationJavaClasses.hpp @@ -83,7 +83,7 @@ class jdk_internal_vm_StackChunk: AllStatic { static int _size_offset; static int _sp_offset; static int _pc_offset; - static int _argsize_offset; + static int _bottom_offset; static int _flags_offset; static int _maxThawingSize_offset; static int _cont_offset; @@ -112,8 +112,9 @@ class jdk_internal_vm_StackChunk: AllStatic { static inline void set_sp(HeapWord* chunk, int value); // used while allocating static inline address pc(oop chunk); static inline void set_pc(oop chunk, address value); - static inline int argsize(oop chunk); - static inline void set_argsize(oop chunk, int value); + static inline int bottom(oop chunk); + static inline void set_bottom(oop chunk, int value); + static inline void set_bottom(HeapWord* chunk, int value); static inline uint8_t flags(oop chunk); static inline void set_flags(oop chunk, uint8_t value); static inline uint8_t flags_acquire(oop chunk); diff --git a/src/hotspot/share/runtime/continuationJavaClasses.inline.hpp b/src/hotspot/share/runtime/continuationJavaClasses.inline.hpp index 987f367303d..b2dea2d704a 100644 --- a/src/hotspot/share/runtime/continuationJavaClasses.inline.hpp +++ b/src/hotspot/share/runtime/continuationJavaClasses.inline.hpp @@ -115,12 +115,19 @@ inline void jdk_internal_vm_StackChunk::set_size(HeapWord* chunk, int value) { *(int*)(((char*)chunk) + _size_offset) = (int)value; } +inline void jdk_internal_vm_StackChunk::set_bottom(HeapWord* chunk, int value) { + // Used by StackChunkAllocator before the Object has been finished, + // so don't cast too oop and use int_field_put in this function. + assert(_bottom_offset != 0, "must be set"); + *(int*)(((char*)chunk) + _bottom_offset) = (int)value; +} + inline int jdk_internal_vm_StackChunk::sp(oop chunk) { - return chunk->int_field(_sp_offset); + return chunk->int_field_relaxed(_sp_offset); } inline void jdk_internal_vm_StackChunk::set_sp(oop chunk, int value) { - chunk->int_field_put(_sp_offset, value); + chunk->int_field_put_relaxed(_sp_offset, value); } inline void jdk_internal_vm_StackChunk::set_sp(HeapWord* chunk, int value) { @@ -138,12 +145,12 @@ inline void jdk_internal_vm_StackChunk::set_pc(oop chunk, address value) { chunk->address_field_put(_pc_offset, value); } -inline int jdk_internal_vm_StackChunk::argsize(oop chunk) { - return chunk->int_field(_argsize_offset); +inline int jdk_internal_vm_StackChunk::bottom(oop chunk) { + return chunk->int_field(_bottom_offset); } -inline void jdk_internal_vm_StackChunk::set_argsize(oop chunk, int value) { - chunk->int_field_put(_argsize_offset, value); +inline void jdk_internal_vm_StackChunk::set_bottom(oop chunk, int value) { + chunk->int_field_put(_bottom_offset, value); } inline uint8_t jdk_internal_vm_StackChunk::flags(oop chunk) { diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 44baccc3bc7..199610788fc 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -390,7 +390,8 @@ static void restore_eliminated_locks(JavaThread* thread, GrowableArraylength(); i++) { + // Start locking from outermost/oldest frame + for (int i = (chunk->length() - 1); i >= 0; i--) { compiledVFrame* cvf = chunk->at(i); assert (cvf->scope() != nullptr,"expect only compiled java frames"); GrowableArray* monitors = cvf->monitors(); @@ -533,7 +534,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread #if COMPILER2_OR_JVMCI if ((jvmci_enabled COMPILER2_PRESENT( || ((DoEscapeAnalysis || EliminateNestedLocks) && EliminateLocks) )) && !EscapeBarrier::objs_are_deoptimized(current, deoptee.id())) { - bool unused; + bool unused = false; restore_eliminated_locks(current, chunk, realloc_failures, deoptee, exec_mode, unused); } #endif // COMPILER2_OR_JVMCI @@ -1736,13 +1737,14 @@ void Deoptimization::pop_frames_failed_reallocs(JavaThread* thread, vframeArray* for (int i = 0; i < array->frames(); i++) { MonitorChunk* monitors = array->element(i)->monitors(); if (monitors != nullptr) { - for (int j = 0; j < monitors->number_of_monitors(); j++) { + // Unlock in reverse order starting from most nested monitor. + for (int j = (monitors->number_of_monitors() - 1); j >= 0; j--) { BasicObjectLock* src = monitors->at(j); if (src->obj() != nullptr) { ObjectSynchronizer::exit(src->obj(), src->lock(), thread); } } - array->element(i)->free_monitors(thread); + array->element(i)->free_monitors(); #ifdef ASSERT array->element(i)->set_removed_monitors(); #endif diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 51d66b8d9f8..8021d590e27 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -954,7 +954,7 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer // process locals & expression stack InterpreterOopMap mask; if (query_oop_map_cache) { - m->mask_for(bci, &mask); + m->mask_for(m, bci, &mask); } else { OopMapCache::compute_one_oop_map(m, bci, &mask); } @@ -1021,7 +1021,7 @@ class CompiledArgumentOopFinder: public SignatureIterator { } tty->print_cr("Error walking frame oops:"); _fr.print_on(tty); - assert(loc != nullptr, "missing register map entry reg: " INTPTR_FORMAT " %s loc: " INTPTR_FORMAT, reg->value(), reg->name(), p2i(loc)); + assert(loc != nullptr, "missing register map entry reg: %d %s loc: " INTPTR_FORMAT, reg->value(), reg->name(), p2i(loc)); } #endif _f->do_oop(loc); @@ -1439,7 +1439,7 @@ void frame::describe(FrameValues& values, int frame_no, const RegisterMap* reg_m assert(sig_index == sizeargs, ""); } int stack_arg_slots = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs); - assert(stack_arg_slots == m->num_stack_arg_slots(false /* rounded */), ""); + assert(stack_arg_slots == cm->as_nmethod()->num_stack_arg_slots(false /* rounded */) || cm->is_osr_method(), ""); int out_preserve = SharedRuntime::out_preserve_stack_slots(); int sig_index = 0; int arg_index = (m->is_static() ? 0 : -1); @@ -1450,7 +1450,7 @@ void frame::describe(FrameValues& values, int frame_no, const RegisterMap* reg_m assert(t == sig_bt[sig_index], "sigs in sync"); VMReg fst = regs[sig_index].first(); if (fst->is_stack()) { - assert(((int)fst->reg2stack()) >= 0, "reg2stack: " INTPTR_FORMAT, fst->reg2stack()); + assert(((int)fst->reg2stack()) >= 0, "reg2stack: %d", fst->reg2stack()); int offset = (fst->reg2stack() + out_preserve) * VMRegImpl::stack_slot_size + stack_slot_offset; intptr_t* stack_address = (intptr_t*)((address)unextended_sp() + offset); if (at_this) { diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp index a66b9dee291..70067b8fb93 100644 --- a/src/hotspot/share/runtime/frame.hpp +++ b/src/hotspot/share/runtime/frame.hpp @@ -517,7 +517,7 @@ class FrameValues { if (a->location == b->location) { return a->priority - b->priority; } - return a->location - b->location; + return checked_cast(a->location - b->location); } void print_on(outputStream* out, int min_index, int max_index, intptr_t* v0, intptr_t* v1, diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 26259345311..1c999059d21 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -488,6 +488,9 @@ const int ObjectAlignmentInBytes = 8; develop(bool, ZapFillerObjects, trueInDebug, \ "Zap filler objects") \ \ + develop(bool, ZapTLAB, trueInDebug, \ + "Zap allocated TLABs") \ + \ product(bool, ExecutingUnitTests, false, \ "Whether the JVM is running unit tests or not") \ \ diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index ff8c842daaa..515a8d9d92f 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -420,8 +420,6 @@ JavaThread::JavaThread() : _free_handle_block(nullptr), _Stalled(0), - _monitor_chunks(nullptr), - _suspend_flags(0), _thread_state(_thread_new), @@ -743,6 +741,7 @@ static void ensure_join(JavaThread* thread) { // Clear the native thread instance - this makes isAlive return false and allows the join() // to complete once we've done the notify_all below. Needs a release() to obey Java Memory Model // requirements. + assert(java_lang_Thread::thread(threadObj()) == thread, "must be alive"); java_lang_Thread::release_set_thread(threadObj(), nullptr); lock.notify_all(thread); // Ignore pending exception, since we are exiting anyway @@ -996,13 +995,7 @@ JavaThread* JavaThread::active() { bool JavaThread::is_lock_owned(address adr) const { assert(LockingMode != LM_LIGHTWEIGHT, "should not be called with new lightweight locking"); - if (Thread::is_lock_owned(adr)) return true; - - for (MonitorChunk* chunk = monitor_chunks(); chunk != nullptr; chunk = chunk->next()) { - if (chunk->contains(adr)) return true; - } - - return false; + return is_in_full_stack(adr); } oop JavaThread::exception_oop() const { @@ -1013,22 +1006,6 @@ void JavaThread::set_exception_oop(oop o) { Atomic::store(&_exception_oop, o); } -void JavaThread::add_monitor_chunk(MonitorChunk* chunk) { - chunk->set_next(monitor_chunks()); - set_monitor_chunks(chunk); -} - -void JavaThread::remove_monitor_chunk(MonitorChunk* chunk) { - guarantee(monitor_chunks() != nullptr, "must be non empty"); - if (monitor_chunks() == chunk) { - set_monitor_chunks(chunk->next()); - } else { - MonitorChunk* prev = monitor_chunks(); - while (prev->next() != chunk) prev = prev->next(); - prev->set_next(chunk->next()); - } -} - void JavaThread::handle_special_runtime_exit_condition() { if (is_obj_deopt_suspend()) { frame_anchor()->make_walkable(); @@ -1353,13 +1330,6 @@ void JavaThread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) { DEBUG_ONLY(verify_frame_info();) - if (has_last_Java_frame()) { - // Traverse the monitor chunks - for (MonitorChunk* chunk = monitor_chunks(); chunk != nullptr; chunk = chunk->next()) { - chunk->oops_do(f); - } - } - assert(vframe_array_head() == nullptr, "deopt in progress at a safepoint!"); // If we have deferred set_locals there might be oops waiting to be // written @@ -2147,6 +2117,8 @@ void JavaThread::start_internal_daemon(JavaThread* current, JavaThread* target, // on a ThreadsList. We don't want to wait for the release when the // Theads_lock is dropped when the 'mu' destructor is run since the // JavaThread* is already visible to JVM/TI via the ThreadsList. + + assert(java_lang_Thread::thread(thread_oop()) == nullptr, "must not be alive"); java_lang_Thread::release_set_thread(thread_oop(), target); // isAlive == true now Thread::start(target); } diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index e8e6ccbfe6a..a2e407e69a8 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -194,10 +194,6 @@ class JavaThread: public Thread { void pop_jni_handle_block(); private: - MonitorChunk* _monitor_chunks; // Contains the off stack monitors - // allocated during deoptimization - // and by JNI_MonitorEnter/Exit - enum SuspendFlags { // NOTE: avoid using the sign-bit as cc generates different test code // when the sign-bit is used, and sometimes incorrectly - see CR 6398077 @@ -663,7 +659,7 @@ class JavaThread: public Thread { return (_suspend_flags & (_obj_deopt JFR_ONLY(| _trace_flag))) != 0; } - // Fast-locking support + // Stack-locking support (not for LM_LIGHTWEIGHT) bool is_lock_owned(address adr) const; // Accessors for vframe array top @@ -862,13 +858,7 @@ class JavaThread: public Thread { int depth_first_number() { return _depth_first_number; } void set_depth_first_number(int dfn) { _depth_first_number = dfn; } - private: - void set_monitor_chunks(MonitorChunk* monitor_chunks) { _monitor_chunks = monitor_chunks; } - public: - MonitorChunk* monitor_chunks() const { return _monitor_chunks; } - void add_monitor_chunk(MonitorChunk* chunk); - void remove_monitor_chunk(MonitorChunk* chunk); bool in_deopt_handler() const { return _in_deopt_handler > 0; } void inc_in_deopt_handler() { _in_deopt_handler++; } void dec_in_deopt_handler() { diff --git a/src/hotspot/share/runtime/jniHandles.cpp b/src/hotspot/share/runtime/jniHandles.cpp index 25c8aa8b10b..a74b56063dc 100644 --- a/src/hotspot/share/runtime/jniHandles.cpp +++ b/src/hotspot/share/runtime/jniHandles.cpp @@ -83,7 +83,7 @@ static void report_handle_allocation_failure(AllocFailType alloc_failmode, } jobject JNIHandles::make_global(Handle obj, AllocFailType alloc_failmode) { - assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC"); + assert(!Universe::heap()->is_stw_gc_active(), "can't extend the root set during GC pause"); assert(!current_thread_in_native(), "must not be in native"); jobject res = nullptr; if (!obj.is_null()) { @@ -105,7 +105,7 @@ jobject JNIHandles::make_global(Handle obj, AllocFailType alloc_failmode) { } jweak JNIHandles::make_weak_global(Handle obj, AllocFailType alloc_failmode) { - assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC"); + assert(!Universe::heap()->is_stw_gc_active(), "can't extend the root set during GC pause"); assert(!current_thread_in_native(), "must not be in native"); jweak res = nullptr; if (!obj.is_null()) { diff --git a/src/hotspot/share/runtime/monitorChunk.cpp b/src/hotspot/share/runtime/monitorChunk.cpp index c54ad685cdb..d18fc21d78d 100644 --- a/src/hotspot/share/runtime/monitorChunk.cpp +++ b/src/hotspot/share/runtime/monitorChunk.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ MonitorChunk::MonitorChunk(int number_on_monitors) { _number_of_monitors = number_on_monitors; _monitors = NEW_C_HEAP_ARRAY(BasicObjectLock, number_on_monitors, mtSynchronizer); - _next = nullptr; } diff --git a/src/hotspot/share/runtime/monitorChunk.hpp b/src/hotspot/share/runtime/monitorChunk.hpp index f16aa46fa64..5c804b5c595 100644 --- a/src/hotspot/share/runtime/monitorChunk.hpp +++ b/src/hotspot/share/runtime/monitorChunk.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * 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,23 +38,17 @@ class MonitorChunk: public CHeapObj { int _number_of_monitors; BasicObjectLock* _monitors; BasicObjectLock* monitors() const { return _monitors; } - MonitorChunk* _next; public: // Constructor MonitorChunk(int number_on_monitors); ~MonitorChunk(); - // link operations - MonitorChunk* next() const { return _next; } - void set_next(MonitorChunk* next) { _next = next; } - // Returns the number of monitors int number_of_monitors() const { return _number_of_monitors; } // Returns the index'th monitor BasicObjectLock* at(int index) { assert(index >= 0 && index < number_of_monitors(), "out of bounds check"); return &monitors()[index]; } - // Memory management void oops_do(OopClosure* f); diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index f7587bc6723..41bc71fc241 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -101,7 +101,6 @@ Mutex* tty_lock = nullptr; Mutex* RawMonitor_lock = nullptr; Mutex* PerfDataMemAlloc_lock = nullptr; Mutex* PerfDataManager_lock = nullptr; -Mutex* OopMapCacheAlloc_lock = nullptr; Mutex* FreeList_lock = nullptr; Mutex* OldSets_lock = nullptr; @@ -356,7 +355,6 @@ void mutex_init() { MUTEX_DEFL(PSOldGenExpand_lock , PaddedMutex , Heap_lock, true); } #endif - MUTEX_DEFL(OopMapCacheAlloc_lock , PaddedMutex , Threads_lock, true); MUTEX_DEFL(Module_lock , PaddedMutex , ClassLoaderDataGraph_lock); MUTEX_DEFL(SystemDictionary_lock , PaddedMonitor, Module_lock); MUTEX_DEFL(JNICritical_lock , PaddedMonitor, AdapterHandlerLibrary_lock); // used for JNI critical regions diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index f83ce1ac873..e039312ea31 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -97,7 +97,6 @@ extern Mutex* FullGCALot_lock; // a lock to make FullGCALot MT extern Mutex* RawMonitor_lock; extern Mutex* PerfDataMemAlloc_lock; // a lock on the allocator for PerfData memory for performance data extern Mutex* PerfDataManager_lock; // a long on access to PerfDataManager resources -extern Mutex* OopMapCacheAlloc_lock; // protects allocation of oop_map caches extern Mutex* FreeList_lock; // protects the free region list during safepoints extern Mutex* OldSets_lock; // protects the old region sets diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index d27d34d7a81..cd0709a7bca 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -929,13 +929,63 @@ bool os::print_function_and_library_name(outputStream* st, return have_function_name || have_library_name; } -ATTRIBUTE_NO_ASAN static void print_hex_readable_pointer(outputStream* st, address p, - int unitsize) { - switch (unitsize) { - case 1: st->print("%02x", *(u1*)p); break; - case 2: st->print("%04x", *(u2*)p); break; - case 4: st->print("%08x", *(u4*)p); break; - case 8: st->print("%016" FORMAT64_MODIFIER "x", *(u8*)p); break; +ATTRIBUTE_NO_ASAN static bool read_safely_from(intptr_t* p, intptr_t* result) { + const intptr_t errval = 0x1717; + intptr_t i = SafeFetchN(p, errval); + if (i == errval) { + i = SafeFetchN(p, ~errval); + if (i == ~errval) { + return false; + } + } + (*result) = i; + return true; +} + +static void print_hex_location(outputStream* st, address p, int unitsize) { + assert(is_aligned(p, unitsize), "Unaligned"); + address pa = align_down(p, sizeof(intptr_t)); +#ifndef _LP64 + // Special handling for printing qwords on 32-bit platforms + if (unitsize == 8) { + intptr_t i1, i2; + if (read_safely_from((intptr_t*)pa, &i1) && + read_safely_from((intptr_t*)pa + 1, &i2)) { + const uint64_t value = + LITTLE_ENDIAN_ONLY((((uint64_t)i2) << 32) | i1) + BIG_ENDIAN_ONLY((((uint64_t)i1) << 32) | i2); + st->print("%016" FORMAT64_MODIFIER "x", value); + } else { + st->print_raw("????????????????"); + } + return; + } +#endif // 32-bit, qwords + intptr_t i = 0; + if (read_safely_from((intptr_t*)pa, &i)) { + // bytes: CA FE BA BE DE AD C0 DE + // bytoff: 0 1 2 3 4 5 6 7 + // LE bits: 0 8 16 24 32 40 48 56 + // BE bits: 56 48 40 32 24 16 8 0 + const int offset = (int)(p - (address)pa); + const int bitoffset = + LITTLE_ENDIAN_ONLY(offset * BitsPerByte) + BIG_ENDIAN_ONLY((int)((sizeof(intptr_t) - unitsize - offset) * BitsPerByte)); + const int bitfieldsize = unitsize * BitsPerByte; + intptr_t value = bitfield(i, bitoffset, bitfieldsize); + switch (unitsize) { + case 1: st->print("%02x", (u1)value); break; + case 2: st->print("%04x", (u2)value); break; + case 4: st->print("%08x", (u4)value); break; + case 8: st->print("%016" FORMAT64_MODIFIER "x", (u8)value); break; + } + } else { + switch (unitsize) { + case 1: st->print_raw("??"); break; + case 2: st->print_raw("????"); break; + case 4: st->print_raw("????????"); break; + case 8: st->print_raw("????????????????"); break; + } } } @@ -956,11 +1006,7 @@ void os::print_hex_dump(outputStream* st, address start, address end, int unitsi // Print out the addresses as if we were starting from logical_start. st->print(PTR_FORMAT ": ", p2i(logical_p)); while (p < end) { - if (is_readable_pointer(p)) { - print_hex_readable_pointer(st, p, unitsize); - } else { - st->print("%*.*s", 2*unitsize, 2*unitsize, "????????????????"); - } + print_hex_location(st, p, unitsize); p += unitsize; logical_p += unitsize; cols++; @@ -1870,14 +1916,18 @@ void os::pretouch_memory(void* start, void* end, size_t page_size) { // We're doing concurrent-safe touch and memory state has page // granularity, so we can touch anywhere in a page. Touch at the // beginning of each page to simplify iteration. - char* cur = static_cast(align_down(start, page_size)); + void* first = align_down(start, page_size); void* last = align_down(static_cast(end) - 1, page_size); - assert(cur <= last, "invariant"); - // Iterate from first page through last (inclusive), being careful to - // avoid overflow if the last page abuts the end of the address range. - for ( ; true; cur += page_size) { - Atomic::add(reinterpret_cast(cur), 0, memory_order_relaxed); - if (cur >= last) break; + assert(first <= last, "invariant"); + const size_t pd_page_size = pd_pretouch_memory(first, last, page_size); + if (pd_page_size > 0) { + // Iterate from first page through last (inclusive), being careful to + // avoid overflow if the last page abuts the end of the address range. + last = align_down(static_cast(end) - 1, pd_page_size); + for (char* cur = static_cast(first); /* break */; cur += pd_page_size) { + Atomic::add(reinterpret_cast(cur), 0, memory_order_relaxed); + if (cur >= last) break; + } } } } diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index f445669ab23..a9bbf294747 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -219,6 +219,10 @@ class os: AllStatic { static void pd_free_memory(char *addr, size_t bytes, size_t alignment_hint); static void pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint); + // Returns 0 if pretouch is done via platform dependent method, or otherwise + // returns page_size that should be used for the common method. + static size_t pd_pretouch_memory(void* first, void* last, size_t page_size); + static char* pd_reserve_memory_special(size_t size, size_t alignment, size_t page_size, char* addr, bool executable); diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index 1d0997914c5..6cffd1d18af 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -39,6 +39,7 @@ #include "gc/shared/workerThread.hpp" #include "gc/shared/workerUtils.hpp" #include "interpreter/interpreter.hpp" +#include "interpreter/oopMapCache.hpp" #include "jfr/jfrEvents.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" @@ -610,6 +611,13 @@ class ParallelCleanupTask : public WorkerTask { OopStorage::trigger_cleanup_if_needed(); } + if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_REQUEST_OOPMAPCACHE_CLEANUP)) { + if (OopMapCache::has_cleanup_work()) { + Tracer t("triggering oopmap cache cleanup"); + OopMapCache::try_trigger_cleanup(); + } + } + _subtasks.all_tasks_claimed(); } }; diff --git a/src/hotspot/share/runtime/safepoint.hpp b/src/hotspot/share/runtime/safepoint.hpp index 1f78a1b8e5a..df99a63e3b5 100644 --- a/src/hotspot/share/runtime/safepoint.hpp +++ b/src/hotspot/share/runtime/safepoint.hpp @@ -75,6 +75,7 @@ class SafepointSynchronize : AllStatic { SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH, SAFEPOINT_CLEANUP_STRING_TABLE_REHASH, SAFEPOINT_CLEANUP_REQUEST_OOPSTORAGE_CLEANUP, + SAFEPOINT_CLEANUP_REQUEST_OOPMAPCACHE_CLEANUP, // Leave this one last. SAFEPOINT_CLEANUP_NUM_TASKS }; diff --git a/src/hotspot/share/runtime/serviceThread.cpp b/src/hotspot/share/runtime/serviceThread.cpp index ddc755a81f9..46f953ca52e 100644 --- a/src/hotspot/share/runtime/serviceThread.cpp +++ b/src/hotspot/share/runtime/serviceThread.cpp @@ -33,6 +33,7 @@ #include "gc/shared/oopStorage.hpp" #include "gc/shared/oopStorageSet.hpp" #include "memory/universe.hpp" +#include "interpreter/oopMapCache.hpp" #include "oops/oopHandle.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -95,6 +96,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { bool oop_handles_to_release = false; bool cldg_cleanup_work = false; bool jvmti_tagmap_work = false; + bool oopmap_cache_work = false; { // Need state transition ThreadBlockInVM so that this thread // will be handled by safepoint correctly when this thread is @@ -124,7 +126,8 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { (oopstorage_work = OopStorage::has_cleanup_work_and_reset()) | (oop_handles_to_release = JavaThread::has_oop_handles_to_release()) | (cldg_cleanup_work = ClassLoaderDataGraph::should_clean_metaspaces_and_reset()) | - (jvmti_tagmap_work = JvmtiTagMap::has_object_free_events_and_reset()) + (jvmti_tagmap_work = JvmtiTagMap::has_object_free_events_and_reset()) | + (oopmap_cache_work = OopMapCache::has_cleanup_work()) ) == 0) { // Wait until notified that there is some work to do. ml.wait(); @@ -195,6 +198,10 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { if (jvmti_tagmap_work) { JvmtiTagMap::flush_all_object_free_events(); } + + if (oopmap_cache_work) { + OopMapCache::cleanup(); + } } } diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 6439a958ccb..f8713f5bb8f 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -1437,7 +1437,7 @@ methodHandle SharedRuntime::resolve_sub_helper(bool is_virtual, bool is_optimize if (invoke_code == Bytecodes::_invokestatic) { assert(callee_method->method_holder()->is_initialized() || - callee_method->method_holder()->is_init_thread(current), + callee_method->method_holder()->is_reentrant_initialization(current), "invalid class initialization state for invoke_static"); if (!VM_Version::supports_fast_class_init_checks() && callee_method->needs_clinit_barrier()) { // In order to keep class initialization check, do not patch call @@ -1996,7 +1996,7 @@ void SharedRuntime::check_member_name_argument_is_last_argument(const methodHand for (int i = 0; i < member_arg_pos; i++) { VMReg a = regs_with_member_name[i].first(); VMReg b = regs_without_member_name[i].first(); - assert(a->value() == b->value(), "register allocation mismatch: a=" INTX_FORMAT ", b=" INTX_FORMAT, a->value(), b->value()); + assert(a->value() == b->value(), "register allocation mismatch: a= %d, b= %d", a->value(), b->value()); } assert(regs_with_member_name[member_arg_pos].first()->is_valid(), "bad member arg"); } diff --git a/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp b/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp index 0a279c57385..36fb3b0591d 100644 --- a/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp +++ b/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp @@ -188,9 +188,9 @@ inline int StackChunkFrameStream::stack_argsize() const { return 0; } assert(cb() != nullptr, ""); - assert(cb()->is_compiled(), ""); - assert(cb()->as_compiled_method()->method() != nullptr, ""); - return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; + assert(cb()->is_nmethod(), ""); + assert(cb()->as_nmethod()->method() != nullptr, ""); + return (cb()->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; } template diff --git a/src/hotspot/share/runtime/stubCodeGenerator.hpp b/src/hotspot/share/runtime/stubCodeGenerator.hpp index d13f1b6aed7..c085e9fc38c 100644 --- a/src/hotspot/share/runtime/stubCodeGenerator.hpp +++ b/src/hotspot/share/runtime/stubCodeGenerator.hpp @@ -90,7 +90,7 @@ class StubCodeDesc: public CHeapObj { address begin() const { return _begin; } address end() const { return _end; } uint disp() const { return _disp; } - int size_in_bytes() const { return _end - _begin; } + int size_in_bytes() const { return pointer_delta_as_int(_end, _begin); } bool contains(address pc) const { return _begin <= pc && pc < _end; } void print_on(outputStream* st) const; void print() const; diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index cdb8e2eedd7..8024c209ce3 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -512,16 +512,18 @@ void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) LockStack& lock_stack = current->lock_stack(); if (lock_stack.can_push()) { markWord mark = obj()->mark_acquire(); - if (mark.is_neutral()) { - assert(!lock_stack.contains(obj()), "thread must not already hold the lock"); + while (mark.is_neutral()) { + // Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications. // Try to swing into 'fast-locked' state. - markWord locked_mark = mark.set_fast_locked(); - markWord old_mark = obj()->cas_set_mark(locked_mark, mark); + assert(!lock_stack.contains(obj()), "thread must not already hold the lock"); + const markWord locked_mark = mark.set_fast_locked(); + const markWord old_mark = obj()->cas_set_mark(locked_mark, mark); if (old_mark == mark) { // Successfully fast-locked, push object to lock-stack and return. lock_stack.push(obj()); return; } + mark = old_mark; } } // All other paths fall-through to inflate-enter. @@ -571,23 +573,15 @@ void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) markWord mark = object->mark(); if (LockingMode == LM_LIGHTWEIGHT) { // Fast-locking does not use the 'lock' argument. - if (mark.is_fast_locked()) { - markWord unlocked_mark = mark.set_unlocked(); - markWord old_mark = object->cas_set_mark(unlocked_mark, mark); - if (old_mark != mark) { - // Another thread won the CAS, it must have inflated the monitor. - // It can only have installed an anonymously locked monitor at this point. - // Fetch that monitor, set owner correctly to this thread, and - // exit it (allowing waiting threads to enter). - assert(old_mark.has_monitor(), "must have monitor"); - ObjectMonitor* monitor = old_mark.monitor(); - assert(monitor->is_owner_anonymous(), "must be anonymous owner"); - monitor->set_owner_from_anonymous(current); - monitor->exit(current); + while (mark.is_fast_locked()) { + // Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications. + const markWord unlocked_mark = mark.set_unlocked(); + const markWord old_mark = object->cas_set_mark(unlocked_mark, mark); + if (old_mark == mark) { + current->lock_stack().remove(object); + return; } - LockStack& lock_stack = current->lock_stack(); - lock_stack.remove(object); - return; + mark = old_mark; } } else if (LockingMode == LM_LEGACY) { markWord dhw = lock->displaced_header(); @@ -730,6 +724,16 @@ int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) { return ret_code; } +void ObjectSynchronizer::waitUninterruptibly(Handle obj, jlong millis, TRAPS) { + if (millis < 0) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative"); + } + ObjectSynchronizer::inflate(THREAD, + obj(), + inflate_cause_wait)->wait(millis, false, THREAD); +} + + void ObjectSynchronizer::notify(Handle obj, TRAPS) { JavaThread* current = THREAD; @@ -907,13 +911,6 @@ static inline intptr_t get_next_hash(Thread* current, oop obj) { return value; } -// Can be called from non JavaThreads (e.g., VMThread) for FastHashCode -// calculations as part of JVM/TI tagging. -static bool is_lock_owned(Thread* thread, oop obj) { - assert(LockingMode == LM_LIGHTWEIGHT, "only call this with new lightweight locking enabled"); - return thread->is_Java_thread() ? JavaThread::cast(thread)->lock_stack().contains(obj) : false; -} - intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { while (true) { @@ -925,7 +922,7 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { assert(LockingMode == LM_MONITOR, "+VerifyHeavyMonitors requires LockingMode == 0 (LM_MONITOR)"); guarantee((obj->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked"); } - if (mark.is_neutral()) { // if this is a normal header + if (mark.is_neutral() || (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked())) { hash = mark.hash(); if (hash != 0) { // if it has a hash, just return it return hash; @@ -937,6 +934,10 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { if (test == mark) { // if the hash was installed, return it return hash; } + if (LockingMode == LM_LIGHTWEIGHT) { + // CAS failed, retry + continue; + } // Failed to install the hash. It could be that another thread // installed the hash just before our attempt or inflation has // occurred or... so we fall thru to inflate the monitor for @@ -968,14 +969,9 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { } // Fall thru so we only have one place that installs the hash in // the ObjectMonitor. - } else if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked() && is_lock_owned(current, obj)) { - // This is a fast-lock owned by the calling thread so use the - // markWord from the object. - hash = mark.hash(); - if (hash != 0) { // if it has a hash, just return it - return hash; - } - } else if (LockingMode == LM_LEGACY && mark.has_locker() && current->is_lock_owned((address)mark.locker())) { + } else if (LockingMode == LM_LEGACY && mark.has_locker() + && current->is_Java_thread() + && JavaThread::cast(current)->is_lock_owned((address)mark.locker())) { // This is a stack-lock owned by the calling thread so fetch the // displaced markWord from the BasicLock on the stack. temp = mark.displaced_mark_helper(); @@ -1304,6 +1300,13 @@ void ObjectSynchronizer::inflate_helper(oop obj) { (void)inflate(Thread::current(), obj, inflate_cause_vm_internal); } +// Can be called from non JavaThreads (e.g., VMThread) for FastHashCode +// calculations as part of JVM/TI tagging. +static bool is_lock_owned(Thread* thread, oop obj) { + assert(LockingMode == LM_LIGHTWEIGHT, "only call this with new lightweight locking enabled"); + return thread->is_Java_thread() ? JavaThread::cast(thread)->lock_stack().contains(obj) : false; +} + ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop object, const InflateCause cause) { EventJavaMonitorInflate event; diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index 4dea13432e7..e983aeb9deb 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -106,6 +106,11 @@ class ObjectSynchronizer : AllStatic { static bool quick_notify(oopDesc* obj, JavaThread* current, bool All); static bool quick_enter(oop obj, JavaThread* current, BasicLock* Lock); + // Special internal-use-only method for use by JVM infrastructure + // that needs to wait() on a java-level object but that can't risk + // throwing unexpected InterruptedExecutionExceptions. + static void waitUninterruptibly(Handle obj, jlong Millis, TRAPS); + // Inflate light weight monitor to heavy weight monitor static ObjectMonitor* inflate(Thread* current, oop obj, const InflateCause cause); // This version is only for internal use @@ -207,6 +212,7 @@ class ObjectLocker : public StackObj { // Monitor behavior void wait(TRAPS) { ObjectSynchronizer::wait(_obj, 0, CHECK); } // wait forever + void wait_uninterruptibly(TRAPS) { ObjectSynchronizer::waitUninterruptibly(_obj, 0, CHECK); } // wait forever void notify_all(TRAPS) { ObjectSynchronizer::notifyall(_obj, CHECK); } }; diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 51a9e847150..a576c488697 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -103,7 +103,10 @@ Thread::Thread() { _vm_error_callbacks = nullptr; // thread-specific hashCode stream generator state - Marsaglia shift-xor form - _hashStateX = os::random(); + // If we are dumping, keep ihashes constant. Note that during dumping we only + // ever run one java thread, and no other thread should generate ihashes either, + // so using a constant seed should work fine. + _hashStateX = DumpSharedSpaces ? 0x12345678 : os::random(); _hashStateY = 842502087; _hashStateZ = 0x8767; // (int)(3579807591LL & 0xffff) ; _hashStateW = 273326509; @@ -522,16 +525,6 @@ void Thread::print_owned_locks_on(outputStream* st) const { } #endif // ASSERT -// We had to move these methods here, because vm threads get into ObjectSynchronizer::enter -// However, there is a note in JavaThread::is_lock_owned() about the VM threads not being -// used for compilation in the future. If that change is made, the need for these methods -// should be revisited, and they should be removed if possible. - -bool Thread::is_lock_owned(address adr) const { - assert(LockingMode != LM_LIGHTWEIGHT, "should not be called with new lightweight locking"); - return is_in_full_stack(adr); -} - bool Thread::set_as_starting_thread() { assert(_starting_thread == nullptr, "already initialized: " "_starting_thread=" INTPTR_FORMAT, p2i(_starting_thread)); diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 9bd839dc4db..fabeb218ea8 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -475,9 +475,6 @@ class Thread: public ThreadShadow { } public: - // Used by fast lock support - virtual bool is_lock_owned(address adr) const; - // Check if address is within the given range of this thread's // stack: stack_base() > adr >= limit bool is_in_stack_range_incl(address adr, address limit) const { @@ -649,15 +646,17 @@ class Thread: public ThreadShadow { class ThreadInAsgct { private: Thread* _thread; + bool _saved_in_asgct; public: ThreadInAsgct(Thread* thread) : _thread(thread) { assert(thread != nullptr, "invariant"); - assert(!thread->in_asgct(), "invariant"); + // Allow AsyncGetCallTrace to be reentrant - save the previous state. + _saved_in_asgct = thread->in_asgct(); thread->set_in_asgct(true); } ~ThreadInAsgct() { assert(_thread->in_asgct(), "invariant"); - _thread->set_in_asgct(false); + _thread->set_in_asgct(_saved_in_asgct); } }; diff --git a/src/hotspot/share/runtime/vframe.cpp b/src/hotspot/share/runtime/vframe.cpp index 2dc2d5a9281..57a4b447de5 100644 --- a/src/hotspot/share/runtime/vframe.cpp +++ b/src/hotspot/share/runtime/vframe.cpp @@ -205,8 +205,9 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) { Klass* k = obj->klass(); st->print_cr("\t- %s <" INTPTR_FORMAT "> (a %s)", "parking to wait for ", p2i(obj), k->external_name()); } - else if (thread()->osthread()->get_state() == CONDVAR_WAIT) { - // We are waiting on the native class initialization monitor. + else if (thread()->osthread()->get_state() == OBJECT_WAIT) { + // We are waiting on an Object monitor but Object.wait() isn't the + // top-frame, so we should be waiting on a Class initialization monitor. InstanceKlass* k = thread()->class_to_be_initialized(); if (k != nullptr) { st->print_cr("\t- waiting on the Class initialization monitor for %s", k->external_name()); diff --git a/src/hotspot/share/runtime/vframeArray.cpp b/src/hotspot/share/runtime/vframeArray.cpp index 27391919b3c..a95deaf6fc1 100644 --- a/src/hotspot/share/runtime/vframeArray.cpp +++ b/src/hotspot/share/runtime/vframeArray.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/monitorChunk.hpp" #include "runtime/sharedRuntime.hpp" +#include "runtime/synchronizer.hpp" #include "runtime/vframe.hpp" #include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" @@ -48,11 +49,10 @@ int vframeArrayElement:: bci(void) const { return (_bci == SynchronizationEntryBCI ? 0 : _bci); } -void vframeArrayElement::free_monitors(JavaThread* jt) { +void vframeArrayElement::free_monitors() { if (_monitors != nullptr) { MonitorChunk* chunk = _monitors; _monitors = nullptr; - jt->remove_monitor_chunk(chunk); delete chunk; } } @@ -72,7 +72,7 @@ void vframeArrayElement::fill_in(compiledVFrame* vf, bool realloc_failures) { int index; { - Thread* current_thread = Thread::current(); + JavaThread* current_thread = JavaThread::current(); ResourceMark rm(current_thread); HandleMark hm(current_thread); @@ -85,7 +85,6 @@ void vframeArrayElement::fill_in(compiledVFrame* vf, bool realloc_failures) { // Allocate monitor chunk _monitors = new MonitorChunk(list->length()); - vf->thread()->add_monitor_chunk(_monitors); // Migrate the BasicLocks from the stack to the monitor chunk for (index = 0; index < list->length(); index++) { @@ -95,9 +94,16 @@ void vframeArrayElement::fill_in(compiledVFrame* vf, bool realloc_failures) { if (monitor->owner_is_scalar_replaced()) { dest->set_obj(nullptr); } else { - assert(monitor->owner() == nullptr || !monitor->owner()->is_unlocked(), "object must be null or locked"); + assert(monitor->owner() != nullptr, "monitor owner must not be null"); + assert(!monitor->owner()->is_unlocked(), "monitor must be locked"); dest->set_obj(monitor->owner()); + assert(ObjectSynchronizer::current_thread_holds_lock(current_thread, Handle(current_thread, dest->obj())), + "should be held, before move_to"); + monitor->lock()->move_to(monitor->owner(), dest->lock()); + + assert(ObjectSynchronizer::current_thread_holds_lock(current_thread, Handle(current_thread, dest->obj())), + "should be held, after move_to"); } } } @@ -308,7 +314,11 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, top = iframe()->previous_monitor_in_interpreter_frame(top); BasicObjectLock* src = _monitors->at(index); top->set_obj(src->obj()); + assert(src->obj() != nullptr || ObjectSynchronizer::current_thread_holds_lock(thread, Handle(thread, src->obj())), + "should be held, before move_to"); src->lock()->move_to(src->obj(), top->lock()); + assert(src->obj() != nullptr || ObjectSynchronizer::current_thread_holds_lock(thread, Handle(thread, src->obj())), + "should be held, after move_to"); } if (ProfileInterpreter) { iframe()->interpreter_frame_set_mdp(0); // clear out the mdp. @@ -649,9 +659,8 @@ void vframeArray::unpack_to_stack(frame &unpack_frame, int exec_mode, int caller } void vframeArray::deallocate_monitor_chunks() { - JavaThread* jt = JavaThread::current(); for (int index = 0; index < frames(); index++ ) { - element(index)->free_monitors(jt); + element(index)->free_monitors(); } } diff --git a/src/hotspot/share/runtime/vframeArray.hpp b/src/hotspot/share/runtime/vframeArray.hpp index 734703a94ae..b270046252d 100644 --- a/src/hotspot/share/runtime/vframeArray.hpp +++ b/src/hotspot/share/runtime/vframeArray.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,7 +77,7 @@ class vframeArrayElement { MonitorChunk* monitors(void) const { return _monitors; } - void free_monitors(JavaThread* jt); + void free_monitors(); StackValueCollection* locals(void) const { return _locals; } diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index fd6968634da..8e22b93dd16 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -239,6 +239,7 @@ nonstatic_field(InstanceKlass, _nonstatic_oop_map_size, int) \ volatile_nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \ volatile_nonstatic_field(InstanceKlass, _init_thread, JavaThread*) \ + nonstatic_field(InstanceKlass, _is_marked_dependent, bool) \ nonstatic_field(InstanceKlass, _itable_len, int) \ nonstatic_field(InstanceKlass, _reference_type, u1) \ volatile_nonstatic_field(InstanceKlass, _oop_map_cache, OopMapCache*) \ @@ -2233,7 +2234,6 @@ \ declare_constant(InstanceKlass::allocated) \ declare_constant(InstanceKlass::loaded) \ - declare_constant(InstanceKlass::being_linked) \ declare_constant(InstanceKlass::linked) \ declare_constant(InstanceKlass::being_initialized) \ declare_constant(InstanceKlass::fully_initialized) \ diff --git a/src/hotspot/share/sanitizers/ub.hpp b/src/hotspot/share/sanitizers/ub.hpp new file mode 100644 index 00000000000..7b0997fdea8 --- /dev/null +++ b/src/hotspot/share/sanitizers/ub.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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_SANITIZERS_UB_HPP +#define SHARE_SANITIZERS_UB_HPP + +// ATTRIBUTE_NO_UBSAN +// +// Function attribute which informs the compiler to disable UBSan checks in the +// following function or method. +// Useful if the function or method is known to do something special or even 'dangerous', for +// example causing desired signals/crashes. +#ifdef UNDEFINED_BEHAVIOR_SANITIZER +#if defined(__clang__) || defined(__GNUC__) +#define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined"))) +#endif +#endif + +#ifndef ATTRIBUTE_NO_UBSAN +#define ATTRIBUTE_NO_UBSAN +#endif + +#endif // SHARE_SANITIZERS_UB_HPP \ No newline at end of file diff --git a/src/hotspot/share/services/classLoadingService.cpp b/src/hotspot/share/services/classLoadingService.cpp index 2df8d12278d..a6c60854078 100644 --- a/src/hotspot/share/services/classLoadingService.cpp +++ b/src/hotspot/share/services/classLoadingService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ #include "utilities/defaultStream.hpp" #include "logging/log.hpp" #include "logging/logConfiguration.hpp" +#include "logging/logFileStreamOutput.hpp" #ifdef DTRACE_ENABLED @@ -128,6 +129,22 @@ bool ClassLoadingService::set_verbose(bool verbose) { return verbose; } +bool ClassLoadingService::get_verbose() { + for (LogTagSet* ts = LogTagSet::first(); ts != nullptr; ts = ts->next()) { + // set_verbose looks for a non-exact match for class+load, + // so look for all tag sets that match class+load* + if (ts->contains(LogTag::_class) && + ts->contains(LogTag::_load)) { + LogLevelType l = ts->level_for(StdoutLog); + if (l != LogLevel::Info && l != LogLevel::Debug && l != LogLevel::Trace) { + return false; + } + } + } + + return true; +} + // Caller to this function must own Management_lock void ClassLoadingService::reset_trace_class_unloading() { assert(Management_lock->owned_by_self(), "Must own the Management_lock"); diff --git a/src/hotspot/share/services/classLoadingService.hpp b/src/hotspot/share/services/classLoadingService.hpp index f9db3da5091..3aeb3f556a5 100644 --- a/src/hotspot/share/services/classLoadingService.hpp +++ b/src/hotspot/share/services/classLoadingService.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,7 @@ class ClassLoadingService : public AllStatic { public: static void init() NOT_MANAGEMENT_RETURN; static bool set_verbose(bool verbose) NOT_MANAGEMENT_RETURN_(false); + static bool get_verbose() NOT_MANAGEMENT_RETURN_(false); static void reset_trace_class_unloading() NOT_MANAGEMENT_RETURN; static jlong loaded_class_count() NOT_MANAGEMENT_RETURN_(0L); static jlong unloaded_class_count() NOT_MANAGEMENT_RETURN_(0L); @@ -63,7 +64,6 @@ class ClassLoadingService : public AllStatic { static jlong loaded_shared_class_bytes() NOT_MANAGEMENT_RETURN_(0L); static jlong unloaded_shared_class_bytes() NOT_MANAGEMENT_RETURN_(0L); static jlong class_method_data_size() NOT_MANAGEMENT_RETURN_(0L); - static bool get_verbose() { return log_is_enabled(Info, class, load); } static void notify_class_loaded(InstanceKlass* k, bool shared_class) NOT_MANAGEMENT_RETURN; diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 0f7c780035e..b426f5d4c29 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -1246,6 +1246,14 @@ u4 DumperSupport::get_static_fields_size(InstanceKlass* ik, u2& field_count) { } } + // Also provide a pointer to the init_lock if present, so there aren't unreferenced int[0] + // arrays. + oop init_lock = ik->init_lock(); + if (init_lock != nullptr) { + field_count++; + size += sizeof(address); + } + // We write the value itself plus a name and a one byte type tag per field. return size + field_count * (sizeof(address) + 1); } @@ -1283,6 +1291,14 @@ void DumperSupport::dump_static_fields(AbstractDumpWriter* writer, Klass* k) { prev = prev->previous_versions(); } } + + // Add init lock to the end if the class is not yet initialized + oop init_lock = ik->init_lock(); + if (init_lock != nullptr) { + writer->write_symbolID(vmSymbols::init_lock_name()); // name + writer->write_u1(sig2tag(vmSymbols::int_array_signature())); // type + writer->write_objectID(init_lock); + } } // dump the raw values of the instance fields of the given object diff --git a/src/hotspot/share/services/mallocHeader.hpp b/src/hotspot/share/services/mallocHeader.hpp index c376c130e9d..9a2ba3ff053 100644 --- a/src/hotspot/share/services/mallocHeader.hpp +++ b/src/hotspot/share/services/mallocHeader.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2022 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -108,11 +108,11 @@ class MallocHeader { void print_block_on_error(outputStream* st, address bad_address) const; - static uint16_t build_footer(uint8_t b1, uint8_t b2) { return ((uint16_t)b1 << 8) | (uint16_t)b2; } + static uint16_t build_footer(uint8_t b1, uint8_t b2) { return (uint16_t)(((uint16_t)b1 << 8) | (uint16_t)b2); } uint8_t* footer_address() const { return ((address)this) + sizeof(MallocHeader) + _size; } uint16_t get_footer() const { return build_footer(footer_address()[0], footer_address()[1]); } - void set_footer(uint16_t v) { footer_address()[0] = v >> 8; footer_address()[1] = (uint8_t)v; } + void set_footer(uint16_t v) { footer_address()[0] = (uint8_t)(v >> 8); footer_address()[1] = (uint8_t)v; } template inline static OutTypeParam resolve_checked_impl(InTypeParam memblock); diff --git a/src/hotspot/share/services/mallocSiteTable.hpp b/src/hotspot/share/services/mallocSiteTable.hpp index 2523547a075..2b602527e98 100644 --- a/src/hotspot/share/services/mallocSiteTable.hpp +++ b/src/hotspot/share/services/mallocSiteTable.hpp @@ -119,7 +119,7 @@ class MallocSiteTable : AllStatic { assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE && pos_idx < MAX_BUCKET_LENGTH, "overflow"); return (uint32_t)bucket_idx << 16 | pos_idx; } - static uint16_t bucket_idx_from_marker(uint32_t marker) { return marker >> 16; } + static uint16_t bucket_idx_from_marker(uint32_t marker) { return (uint16_t)(marker >> 16); } static uint16_t pos_idx_from_marker(uint32_t marker) { return marker & 0xFFFF; } public: diff --git a/src/hotspot/share/services/memoryService.cpp b/src/hotspot/share/services/memoryService.cpp index 21b773e204e..2f5e5f8dc78 100644 --- a/src/hotspot/share/services/memoryService.cpp +++ b/src/hotspot/share/services/memoryService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #include "classfile/vmSymbols.hpp" #include "gc/shared/collectedHeap.hpp" #include "logging/logConfiguration.hpp" +#include "logging/logFileStreamOutput.hpp" #include "memory/heap.hpp" #include "memory/memRegion.hpp" #include "memory/resourceArea.hpp" @@ -202,6 +203,21 @@ bool MemoryService::set_verbose(bool verbose) { return verbose; } +bool MemoryService::get_verbose() { + for (LogTagSet* ts = LogTagSet::first(); ts != nullptr; ts = ts->next()) { + // set_verbose only sets gc and not gc*, so check for an exact match + const bool is_gc_exact_match = ts->contains(LogTag::_gc) && ts->ntags() == 1; + if (is_gc_exact_match) { + LogLevelType l = ts->level_for(StdoutLog); + if (l == LogLevel::Info || l == LogLevel::Debug || l == LogLevel::Trace) { + return true; + } + } + } + + return false; +} + Handle MemoryService::create_MemoryUsage_obj(MemoryUsage usage, TRAPS) { InstanceKlass* ik = Management::java_lang_management_MemoryUsage_klass(CHECK_NH); diff --git a/src/hotspot/share/services/memoryService.hpp b/src/hotspot/share/services/memoryService.hpp index a00e49dd0a7..78214548e91 100644 --- a/src/hotspot/share/services/memoryService.hpp +++ b/src/hotspot/share/services/memoryService.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -106,8 +106,8 @@ class MemoryService : public AllStatic { GCCause::Cause cause, bool allMemoryPoolsAffected, const char* notificationMessage = nullptr); - static bool get_verbose() { return log_is_enabled(Info, gc); } static bool set_verbose(bool verbose); + static bool get_verbose(); // Create an instance of java/lang/management/MemoryUsage static Handle create_MemoryUsage_obj(MemoryUsage usage, TRAPS); diff --git a/src/hotspot/share/utilities/align.hpp b/src/hotspot/share/utilities/align.hpp index 7c7a4f67bc5..1414d91a19d 100644 --- a/src/hotspot/share/utilities/align.hpp +++ b/src/hotspot/share/utilities/align.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,7 +63,7 @@ constexpr T align_down(T size, A alignment) { // Convert mask to T before logical_not. Otherwise, if alignment is unsigned // and smaller than T, the result of the logical_not will be zero-extended // by integral promotion, and upper bits of size will be discarded. - T result = size & ~T(alignment_mask(alignment)); + T result = T(size & ~T(alignment_mask(alignment))); assert(is_aligned(result, alignment), "must be aligned: " UINT64_FORMAT, (uint64_t)result); return result; @@ -71,7 +71,7 @@ constexpr T align_down(T size, A alignment) { template::value)> constexpr T align_up(T size, A alignment) { - T adjusted = size + alignment_mask(alignment); + T adjusted = checked_cast(size + alignment_mask(alignment)); return align_down(adjusted, alignment); } diff --git a/src/hotspot/share/utilities/copy.hpp b/src/hotspot/share/utilities/copy.hpp index c16a62729b1..58e659955b4 100644 --- a/src/hotspot/share/utilities/copy.hpp +++ b/src/hotspot/share/utilities/copy.hpp @@ -212,6 +212,7 @@ class Copy : AllStatic { // byte_count is in bytes to check its alignment assert_params_ok(from, to, HeapWordSize); assert_byte_count_ok(byte_count, HeapWordSize); + if (byte_count == 0) return; size_t count = align_up(byte_count, HeapWordSize) >> LogHeapWordSize; assert(from <= to || to + count <= from, "do not overwrite source data"); diff --git a/src/hotspot/share/utilities/elfFile.hpp b/src/hotspot/share/utilities/elfFile.hpp index bad92f82af5..579837ebf80 100644 --- a/src/hotspot/share/utilities/elfFile.hpp +++ b/src/hotspot/share/utilities/elfFile.hpp @@ -255,7 +255,7 @@ class ElfFile: public CHeapObj { } void update_null_terminator_index() { - _null_terminator_index = strlen(_path); + _null_terminator_index = checked_cast(strlen(_path)); } bool copy_to_path_index(uint16_t index_in_path, const char* src); diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 7e6ebf9fdde..f3ec5d80056 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -520,12 +520,20 @@ inline size_t pointer_delta(const MetaWord* left, const MetaWord* right) { // everything: it isn't intended to make sure that pointer types are // compatible, for example. template -T2 checked_cast(T1 thing) { +constexpr T2 checked_cast(T1 thing) { T2 result = static_cast(thing); assert(static_cast(result) == thing, "must be"); return result; } +// pointer_delta_as_int is called to do pointer subtraction for nearby pointers that +// returns a non-negative int, usually used as a size of a code buffer range. +// This scales to sizeof(T). +template +inline int pointer_delta_as_int(const volatile T* left, const volatile T* right) { + return checked_cast(pointer_delta(left, right, sizeof(T))); +} + // Need the correct linkage to call qsort without warnings extern "C" { typedef int (*_sort_Fn)(const void *, const void *); @@ -667,7 +675,7 @@ inline double fabsd(double value) { // is zero, return 0.0. template inline double percent_of(T numerator, T denominator) { - return denominator != 0 ? (double)numerator / denominator * 100.0 : 0.0; + return denominator != 0 ? (double)numerator / (double)denominator * 100.0 : 0.0; } //---------------------------------------------------------------------------------------------------- diff --git a/src/hotspot/share/utilities/growableArray.hpp b/src/hotspot/share/utilities/growableArray.hpp index 5b67bc88e1b..63dbf668eed 100644 --- a/src/hotspot/share/utilities/growableArray.hpp +++ b/src/hotspot/share/utilities/growableArray.hpp @@ -278,10 +278,12 @@ class GrowableArrayView : public GrowableArrayBase { } void sort(int f(E*, E*)) { + if (_data == nullptr) return; qsort(_data, length(), sizeof(E), (_sort_Fn)f); } // sort by fixed-stride sub arrays: void sort(int f(E*, E*), int stride) { + if (_data == nullptr) return; qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f); } diff --git a/src/hotspot/share/utilities/nativeCallStack.hpp b/src/hotspot/share/utilities/nativeCallStack.hpp index 07e30c163e0..841b2cb2045 100644 --- a/src/hotspot/share/utilities/nativeCallStack.hpp +++ b/src/hotspot/share/utilities/nativeCallStack.hpp @@ -120,7 +120,7 @@ class NativeCallStack : public StackObj { for (int i = 0; i < NMT_TrackingStackDepth; i++) { hash += (uintptr_t)_stack[i]; } - return hash; + return (unsigned int)hash; } void print_on(outputStream* out) const; diff --git a/src/hotspot/share/utilities/powerOfTwo.hpp b/src/hotspot/share/utilities/powerOfTwo.hpp index 29abc972eaa..786977a347f 100644 --- a/src/hotspot/share/utilities/powerOfTwo.hpp +++ b/src/hotspot/share/utilities/powerOfTwo.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,7 +117,7 @@ inline T round_up_power_of_2(T value) { template ::value)> inline T next_power_of_2(T value) { assert(value < std::numeric_limits::max(), "Overflow"); - return round_up_power_of_2(value + 1); + return T(round_up_power_of_2(value + 1)); } // Find log2 value greater than this input diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 868c67a7dbc..741ede5d41e 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -59,6 +59,7 @@ #include "runtime/vmOperations.hpp" #include "runtime/vm_version.hpp" #include "services/memTracker.hpp" +#include "sanitizers/ub.hpp" #include "utilities/debug.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" @@ -2058,8 +2059,11 @@ bool VMError::check_timeout() { #ifdef ASSERT typedef void (*voidfun_t)(); -// Crash with an authentic sigfpe +// Crash with an authentic sigfpe; behavior is subtly different from a real signal +// compared to one generated with raise (asynchronous vs synchronous). See JDK-8065895. volatile int sigfpe_int = 0; + +ATTRIBUTE_NO_UBSAN static void ALWAYSINLINE crash_with_sigfpe() { // generate a native synchronous SIGFPE where possible; diff --git a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java index 109acce3853..8f5ff41957e 100644 --- a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java +++ b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -159,8 +159,16 @@ public void writeBytes(byte[] b) { * @throws NullPointerException if {@code out} is {@code null}. * @throws IOException if an I/O error occurs. */ - public synchronized void writeTo(OutputStream out) throws IOException { - out.write(buf, 0, count); + public void writeTo(OutputStream out) throws IOException { + if (Thread.currentThread().isVirtual()) { + byte[] bytes; + synchronized (this) { + bytes = Arrays.copyOf(buf, count); + } + out.write(bytes); + } else synchronized (this) { + out.write(buf, 0, count); + } } /** diff --git a/src/java.base/share/classes/java/lang/Thread.java b/src/java.base/share/classes/java/lang/Thread.java index 4ff54446a23..6d56a37ea4a 100644 --- a/src/java.base/share/classes/java/lang/Thread.java +++ b/src/java.base/share/classes/java/lang/Thread.java @@ -1712,20 +1712,21 @@ public final void stop() { public void interrupt() { if (this != Thread.currentThread()) { checkAccess(); + } + + // Setting the interrupt status must be done before reading nioBlocker. + interrupted = true; + interrupt0(); // inform VM of interrupt - // thread may be blocked in an I/O operation + // thread may be blocked in an I/O operation + if (this != Thread.currentThread()) { synchronized (interruptLock) { Interruptible b = nioBlocker; if (b != null) { - interrupted = true; - interrupt0(); // inform VM of interrupt b.interrupt(this); - return; } } } - interrupted = true; - interrupt0(); // inform VM of interrupt } /** diff --git a/src/java.base/share/classes/java/nio/charset/Charset.java b/src/java.base/share/classes/java/nio/charset/Charset.java index b87dfc16436..2031b879f35 100644 --- a/src/java.base/share/classes/java/nio/charset/Charset.java +++ b/src/java.base/share/classes/java/nio/charset/Charset.java @@ -42,7 +42,6 @@ import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; -import java.util.Objects; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.Set; @@ -689,7 +688,12 @@ public static Charset defaultCharset() { * If the canonical name or any of the aliases are illegal */ protected Charset(String canonicalName, String[] aliases) { - String[] as = Objects.requireNonNullElse(aliases, zeroAliases); + String[] as = + aliases == null ? + zeroAliases : + VM.isSystemDomainLoader(getClass().getClassLoader()) ? + aliases : + Arrays.copyOf(aliases, aliases.length); // Skip checks for the standard, built-in Charsets we always load // during initialization. diff --git a/src/java.base/share/classes/java/nio/file/CopyMoveHelper.java b/src/java.base/share/classes/java/nio/file/CopyMoveHelper.java index 56179b8dd33..24a89456661 100644 --- a/src/java.base/share/classes/java/nio/file/CopyMoveHelper.java +++ b/src/java.base/share/classes/java/nio/file/CopyMoveHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. * 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 @@ package java.nio.file; -import java.nio.file.attribute.*; import java.io.InputStream; import java.io.IOException; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.BasicFileAttributeView; +import java.nio.file.attribute.PosixFileAttributes; +import java.nio.file.attribute.PosixFileAttributeView; +import java.nio.file.spi.FileSystemProvider; /** * Helper class to support copying or moving files when the source and target @@ -129,10 +133,14 @@ static void copyToForeignTarget(Path source, Path target, if (sourceAttrs.isSymbolicLink()) throw new IOException("Copying of symbolic links not supported"); + // ensure source can be copied + FileSystemProvider provider = source.getFileSystem().provider(); + provider.checkAccess(source, AccessMode.READ); + // delete target if it exists and REPLACE_EXISTING is specified - if (opts.replaceExisting) { + if (opts.replaceExisting) Files.deleteIfExists(target); - } else if (Files.exists(target)) + else if (Files.exists(target)) throw new FileAlreadyExistsException(target.toString()); // create directory or copy file diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 8fac36fb84f..02f556489e6 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -50,6 +50,7 @@ import java.util.spi.LocaleNameProvider; import java.util.stream.Stream; +import jdk.internal.util.StaticProperty; import jdk.internal.vm.annotation.Stable; import sun.security.action.GetPropertyAction; @@ -1053,11 +1054,10 @@ private static synchronized Locale getFormatLocale() { private static Locale initDefault() { String language, region, script, country, variant; - Properties props = GetPropertyAction.privilegedGetProperties(); - language = props.getProperty("user.language", "en"); + language = StaticProperty.USER_LANGUAGE; // for compatibility, check for old user.region property - region = props.getProperty("user.region"); - if (region != null) { + region = StaticProperty.USER_REGION; + if (!region.isEmpty()) { // region can be of form country, country_variant, or _variant int i = region.indexOf('_'); if (i >= 0) { @@ -1069,30 +1069,24 @@ private static Locale initDefault() { } script = ""; } else { - script = props.getProperty("user.script", ""); - country = props.getProperty("user.country", ""); - variant = props.getProperty("user.variant", ""); + script = StaticProperty.USER_SCRIPT; + country = StaticProperty.USER_COUNTRY; + variant = StaticProperty.USER_VARIANT; } return getInstance(language, script, country, variant, - getDefaultExtensions(props.getProperty("user.extensions", "")) + getDefaultExtensions(StaticProperty.USER_EXTENSIONS) .orElse(null)); } private static Locale initDefault(Locale.Category category) { - Properties props = GetPropertyAction.privilegedGetProperties(); - Locale locale = Locale.defaultLocale; return getInstance( - props.getProperty(category.languageKey, - locale.getLanguage()), - props.getProperty(category.scriptKey, - locale.getScript()), - props.getProperty(category.countryKey, - locale.getCountry()), - props.getProperty(category.variantKey, - locale.getVariant()), - getDefaultExtensions(props.getProperty(category.extensionsKey, "")) + category == Category.DISPLAY ? StaticProperty.USER_LANGUAGE_DISPLAY : StaticProperty.USER_LANGUAGE_FORMAT, + category == Category.DISPLAY ? StaticProperty.USER_SCRIPT_DISPLAY : StaticProperty.USER_SCRIPT_FORMAT, + category == Category.DISPLAY ? StaticProperty.USER_COUNTRY_DISPLAY : StaticProperty.USER_COUNTRY_FORMAT, + category == Category.DISPLAY ? StaticProperty.USER_VARIANT_DISPLAY : StaticProperty.USER_VARIANT_FORMAT, + getDefaultExtensions(category == Category.DISPLAY ? StaticProperty.USER_EXTENSIONS_DISPLAY : StaticProperty.USER_EXTENSIONS_FORMAT) .orElse(locale.getLocaleExtensions())); } diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index 5e698b1540f..8aafda5312e 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -981,9 +981,7 @@ public final ForkJoinWorkerThread newThread(ForkJoinPool pool) { boolean isCommon = (pool.workerNamePrefix == null); @SuppressWarnings("removal") SecurityManager sm = System.getSecurityManager(); - if (sm == null) - return new ForkJoinWorkerThread(null, pool, true, false); - else if (isCommon) + if (sm != null && isCommon) return newCommonWithACC(pool); else return newRegularWithACC(pool); diff --git a/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java b/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java index 32f7840ef04..6d6d9efad03 100644 --- a/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java @@ -194,6 +194,8 @@ else if (p.cmpExItem(m, e) != m) if ((m = s.await(e, ns, this, // spin if (nearly) empty p == null || p.waiter == null)) == e) unspliceLifo(s); // cancelled + else if (m != null) + s.selfLinkItem(); break; } } diff --git a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java index c7631dc76cc..f4d7d0c08c0 100644 --- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java +++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java @@ -1127,13 +1127,18 @@ public ConditionObject() { } private void doSignal(ConditionNode first, boolean all) { while (first != null) { ConditionNode next = first.nextWaiter; + if ((firstWaiter = next) == null) lastWaiter = null; + else + first.nextWaiter = null; // GC assistance + if ((first.getAndUnsetStatus(COND) & COND) != 0) { enqueue(first); if (!all) break; } + first = next; } } diff --git a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java index 36d21d3fcfc..1f51419f94c 100644 --- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java +++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java @@ -1506,13 +1506,18 @@ public ConditionObject() { } private void doSignal(ConditionNode first, boolean all) { while (first != null) { ConditionNode next = first.nextWaiter; + if ((firstWaiter = next) == null) lastWaiter = null; + else + first.nextWaiter = null; // GC assistance + if ((first.getAndUnsetStatus(COND) & COND) != 0) { enqueue(first); if (!all) break; } + first = next; } } diff --git a/src/java.base/share/classes/javax/crypto/KEM.java b/src/java.base/share/classes/javax/crypto/KEM.java index e05027a7abc..7df7fa236c8 100644 --- a/src/java.base/share/classes/javax/crypto/KEM.java +++ b/src/java.base/share/classes/javax/crypto/KEM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.security.*; import java.security.InvalidAlgorithmParameterException; import java.security.spec.AlgorithmParameterSpec; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -539,10 +540,19 @@ public static KEM getInstance(String algorithm) List list = GetInstance.getServices( "KEM", Objects.requireNonNull(algorithm, "null algorithm name")); - if (list.isEmpty()) { - throw new NoSuchAlgorithmException(algorithm + " KEM not available"); + List allowed = new ArrayList<>(); + for (Provider.Service s : list) { + if (!JceSecurity.canUseProvider(s.getProvider())) { + continue; + } + allowed.add(s); + } + if (allowed.isEmpty()) { + throw new NoSuchAlgorithmException + (algorithm + " KEM not available"); } - return new KEM(algorithm, new DelayedKEM(list.toArray(new Provider.Service[0]))); + + return new KEM(algorithm, new DelayedKEM(allowed.toArray(new Provider.Service[0]))); } /** @@ -568,7 +578,7 @@ public static KEM getInstance(String algorithm, Provider provider) if (provider == null) { return getInstance(algorithm); } - GetInstance.Instance instance = GetInstance.getInstance( + GetInstance.Instance instance = JceSecurity.getInstance( "KEM", KEMSpi.class, Objects.requireNonNull(algorithm, "null algorithm name"), @@ -601,7 +611,7 @@ public static KEM getInstance(String algorithm, String provider) if (provider == null) { return getInstance(algorithm); } - GetInstance.Instance instance = GetInstance.getInstance( + GetInstance.Instance instance = JceSecurity.getInstance( "KEM", KEMSpi.class, Objects.requireNonNull(algorithm, "null algorithm name"), diff --git a/src/java.base/share/classes/jdk/internal/classfile/Attributes.java b/src/java.base/share/classes/jdk/internal/classfile/Attributes.java index 4b6acfd2f11..b972e0b486c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/Attributes.java +++ b/src/java.base/share/classes/jdk/internal/classfile/Attributes.java @@ -461,7 +461,7 @@ protected void writeBody(BufWriter buf, ModulePackagesAttribute attr) { /** Attribute mapper for the {@code ModuleResolution} attribute */ public static final AttributeMapper - MODULE_RESOLUTION = new AbstractAttributeMapper<>(NAME_MODULE_RESOLUTION, true, Classfile.JAVA_9_VERSION) { + MODULE_RESOLUTION = new AbstractAttributeMapper<>(NAME_MODULE_RESOLUTION, Classfile.JAVA_9_VERSION) { @Override public ModuleResolutionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { return new BoundAttribute.BoundModuleResolutionAttribute(cf, this, p); @@ -475,7 +475,7 @@ protected void writeBody(BufWriter buf, ModuleResolutionAttribute attr) { /** Attribute mapper for the {@code ModuleTarget} attribute */ public static final AttributeMapper - MODULE_TARGET = new AbstractAttributeMapper<>(NAME_MODULE_TARGET, true, Classfile.JAVA_9_VERSION) { + MODULE_TARGET = new AbstractAttributeMapper<>(NAME_MODULE_TARGET, Classfile.JAVA_9_VERSION) { @Override public ModuleTargetAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { return new BoundAttribute.BoundModuleTargetAttribute(cf, this, p); diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index ad533280388..3906d07e775 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -688,10 +688,6 @@ public static long mismatch(MemorySegment srcSegment, long srcFromOffset, long s long dstBytes = dstToOffset - dstFromOffset; srcImpl.checkAccess(srcFromOffset, srcBytes, true); dstImpl.checkAccess(dstFromOffset, dstBytes, true); - if (dstImpl == srcImpl) { - srcImpl.checkValidState(); - return -1; - } long bytes = Math.min(srcBytes, dstBytes); long i = 0; diff --git a/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java index be392c3ae2d..f18cb05a8da 100644 --- a/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java +++ b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -204,8 +204,14 @@ public boolean containsValue(Object value) { @Override public V get(Object key) { - Objects.requireNonNull(key, "key must not be null"); removeStaleReferences(); + return getNoCheckStale(key); + } + + // Internal get(key) without removing stale references that would modify the keyset. + // Use when iterating or streaming over the keys to avoid ConcurrentModificationException. + private V getNoCheckStale(Object key) { + Objects.requireNonNull(key, "key must not be null"); return map.get(lookupKey(key)); } @@ -276,7 +282,7 @@ public Collection values() { public Set> entrySet() { removeStaleReferences(); return filterKeySet() - .map(k -> new AbstractMap.SimpleEntry<>(k, get(k))) + .map(k -> new AbstractMap.SimpleEntry<>(k, getNoCheckStale(k))) .collect(Collectors.toSet()); } @@ -320,7 +326,7 @@ public V replace(K key, V value) { public String toString() { removeStaleReferences(); return filterKeySet() - .map(k -> k + "=" + get(k)) + .map(k -> k + "=" + getNoCheckStale(k)) .collect(Collectors.joining(", ", "{", "}")); } diff --git a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java index 3683aaeffcb..da06bf07a65 100644 --- a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java +++ b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java @@ -57,6 +57,22 @@ public final class StaticProperty { private static final String OS_NAME; private static final String OS_ARCH; private static final String OS_VERSION; + public static final String USER_LANGUAGE; + public static final String USER_LANGUAGE_DISPLAY; + public static final String USER_LANGUAGE_FORMAT; + public static final String USER_SCRIPT; + public static final String USER_SCRIPT_DISPLAY; + public static final String USER_SCRIPT_FORMAT; + public static final String USER_COUNTRY; + public static final String USER_COUNTRY_DISPLAY; + public static final String USER_COUNTRY_FORMAT; + public static final String USER_VARIANT; + public static final String USER_VARIANT_DISPLAY; + public static final String USER_VARIANT_FORMAT; + public static final String USER_EXTENSIONS; + public static final String USER_EXTENSIONS_DISPLAY; + public static final String USER_EXTENSIONS_FORMAT; + public static final String USER_REGION; private StaticProperty() {} @@ -79,6 +95,22 @@ private StaticProperty() {} OS_NAME = getProperty(props, "os.name"); OS_ARCH = getProperty(props, "os.arch"); OS_VERSION = getProperty(props, "os.version"); + USER_LANGUAGE = getProperty(props, "user.language", "en"); + USER_LANGUAGE_DISPLAY = getProperty(props, "user.language.display", USER_LANGUAGE); + USER_LANGUAGE_FORMAT = getProperty(props, "user.language.format", USER_LANGUAGE); + USER_SCRIPT = getProperty(props, "user.script", ""); + USER_SCRIPT_DISPLAY = getProperty(props, "user.script.display", USER_SCRIPT); + USER_SCRIPT_FORMAT = getProperty(props, "user.script.format", USER_SCRIPT); + USER_COUNTRY = getProperty(props, "user.country", ""); + USER_COUNTRY_DISPLAY = getProperty(props, "user.country.display", USER_COUNTRY); + USER_COUNTRY_FORMAT = getProperty(props, "user.country.format", USER_COUNTRY); + USER_VARIANT = getProperty(props, "user.variant", ""); + USER_VARIANT_DISPLAY = getProperty(props, "user.variant.display", USER_VARIANT); + USER_VARIANT_FORMAT = getProperty(props, "user.variant.format", USER_VARIANT); + USER_EXTENSIONS = getProperty(props, "user.extensions", ""); + USER_EXTENSIONS_DISPLAY = getProperty(props, "user.extensions.display", USER_EXTENSIONS); + USER_EXTENSIONS_FORMAT = getProperty(props, "user.extensions.format", USER_EXTENSIONS); + USER_REGION = getProperty(props, "user.region", ""); } private static String getProperty(Properties props, String key) { diff --git a/src/java.base/share/classes/jdk/internal/vm/StackChunk.java b/src/java.base/share/classes/jdk/internal/vm/StackChunk.java index 0c48ce67934..ab562706c24 100644 --- a/src/java.base/share/classes/jdk/internal/vm/StackChunk.java +++ b/src/java.base/share/classes/jdk/internal/vm/StackChunk.java @@ -31,10 +31,10 @@ public static void init() {} private StackChunk parent; private int size; // in words private int sp; // in words - private int argsize; // bottom stack-passed arguments, in words + private int bottom; // in words // The stack itself is appended here by the VM, as well as some injected fields public StackChunk parent() { return parent; } - public boolean isEmpty() { return sp >= (size - argsize); } + public boolean isEmpty() { return sp == bottom; } } diff --git a/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/src/java.base/share/classes/sun/launcher/LauncherHelper.java index 8985077df37..58a6be5fa1e 100644 --- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java +++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java @@ -170,7 +170,7 @@ static void showSettings(boolean printToStderr, String optionFlag, printProperties(); break; case "locale": - printLocale(); + printLocale(false); break; case "security": var opt = opts.length > 2 ? opts[2].trim() : "all"; @@ -184,7 +184,7 @@ static void showSettings(boolean printToStderr, String optionFlag, default: printVmSettings(initialHeapSize, maxHeapSize, stackSize); printProperties(); - printLocale(); + printLocale(true); SecuritySettings.printSecuritySummarySettings(ostream); if (OperatingSystem.isLinux()) { printSystemMetrics(); @@ -280,9 +280,15 @@ private static void printPropertyValue(String key, String value) { /* * prints the locale subopt/section */ - private static void printLocale() { + private static void printLocale(boolean summaryMode) { Locale locale = Locale.getDefault(); - ostream.println(LOCALE_SETTINGS); + if (!summaryMode) { + ostream.println(LOCALE_SETTINGS); + } else { + ostream.println("Locale settings summary:"); + ostream.println(INDENT + "Use \"-XshowSettings:locale\" " + + "option for verbose locale settings options"); + } ostream.println(INDENT + "default locale = " + locale.getDisplayName()); ostream.println(INDENT + "default display locale = " + @@ -291,7 +297,9 @@ private static void printLocale() { Locale.getDefault(Category.FORMAT).getDisplayName()); ostream.println(INDENT + "tzdata version = " + ZoneInfoFile.getVersion()); - printLocales(); + if (!summaryMode) { + printLocales(); + } ostream.println(); } diff --git a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java index abd1447e995..b9b34653f99 100644 --- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -759,20 +759,18 @@ public long transferTo(long position, long count, if (position > sz) return 0; - // Now position <= sz so remaining >= 0 and - // remaining == 0 if and only if sz == 0 - long remaining = sz - position; - - // Adjust count only if remaining > 0, i.e., - // sz > position which means sz > 0 - if (remaining > 0 && remaining < count) - count = remaining; - // System calls supporting fast transfers might not work on files // which advertise zero size such as those in Linux /proc if (sz > 0) { - // Attempt a direct transfer, if the kernel supports it, limiting - // the number of bytes according to which platform + // Now sz > 0 and position <= sz so remaining >= 0 and + // remaining == 0 if and only if sz == position + long remaining = sz - position; + + if (remaining >= 0 && remaining < count) + count = remaining; + + // Attempt a direct transfer, if the kernel supports it, + // limiting the number of bytes according to which platform int icount = (int)Math.min(count, nd.maxDirectTransferSize()); long n; if ((n = transferToDirectly(position, icount, target)) >= 0) diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java index 155cb439260..bdf2935eff3 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java @@ -382,7 +382,7 @@ private void onCertificate(ServerHandshakeContext shc, ClientAuthType.CLIENT_AUTH_REQUESTED) { // unexpected or require client authentication throw shc.conContext.fatal(Alert.BAD_CERTIFICATE, - "Empty server certificate chain"); + "Empty client certificate chain"); } else { return; } @@ -399,7 +399,7 @@ private void onCertificate(ServerHandshakeContext shc, } } catch (CertificateException ce) { throw shc.conContext.fatal(Alert.BAD_CERTIFICATE, - "Failed to parse server certificates", ce); + "Failed to parse client certificates", ce); } checkClientCerts(shc, x509Certs); @@ -1216,7 +1216,7 @@ private static X509Certificate[] checkClientCerts( } } catch (CertificateException ce) { throw shc.conContext.fatal(Alert.BAD_CERTIFICATE, - "Failed to parse server certificates", ce); + "Failed to parse client certificates", ce); } // find out the types of client authentication used diff --git a/src/java.base/share/classes/sun/security/ssl/ClientHello.java b/src/java.base/share/classes/sun/security/ssl/ClientHello.java index 091bfa8986e..babf2bb452d 100644 --- a/src/java.base/share/classes/sun/security/ssl/ClientHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ClientHello.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -903,8 +903,8 @@ private ProtocolVersion negotiateProtocol( throw context.conContext.fatal(Alert.PROTOCOL_VERSION, "The client supported protocol versions " + Arrays.toString( ProtocolVersion.toStringArray(clientSupportedVersions)) + - " are not accepted by server preferences " + - context.activeProtocols); + " are not accepted by server preferences " + Arrays.toString( + ProtocolVersion.toStringArray(context.activeProtocols))); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index b4129964662..d8494595911 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1781,21 +1781,24 @@ private void closeSocket(boolean selfInitiated) throws IOException { if (conContext.inputRecord instanceof SSLSocketInputRecord inputRecord && isConnected) { if (appInput.readLock.tryLock()) { - int soTimeout = getSoTimeout(); try { - // deplete could hang on the skip operation - // in case of infinite socket read timeout. - // Change read timeout to avoid deadlock. - // This workaround could be replaced later - // with the right synchronization - if (soTimeout == 0) - setSoTimeout(DEFAULT_SKIP_TIMEOUT); - inputRecord.deplete(false); - } catch (java.net.SocketTimeoutException stEx) { - // skip timeout exception during deplete + int soTimeout = getSoTimeout(); + try { + // deplete could hang on the skip operation + // in case of infinite socket read timeout. + // Change read timeout to avoid deadlock. + // This workaround could be replaced later + // with the right synchronization + if (soTimeout == 0) + setSoTimeout(DEFAULT_SKIP_TIMEOUT); + inputRecord.deplete(false); + } catch (java.net.SocketTimeoutException stEx) { + // skip timeout exception during deplete + } finally { + if (soTimeout == 0) + setSoTimeout(soTimeout); + } } finally { - if (soTimeout == 0) - setSoTimeout(soTimeout); appInput.readLock.unlock(); } } diff --git a/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java b/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java index eaf154af3bb..96c3fe2fa6a 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ import static sun.security.ssl.SSLExtension.CH_SERVER_NAME; import static sun.security.ssl.SSLExtension.EE_SERVER_NAME; import sun.security.ssl.SSLExtension.ExtensionConsumer; +import static sun.security.ssl.SSLExtension.SH_PRE_SHARED_KEY; import static sun.security.ssl.SSLExtension.SH_SERVER_NAME; import sun.security.ssl.SSLExtension.SSLExtensionSpec; import sun.security.ssl.SSLHandshake.HandshakeMessage; @@ -342,6 +343,10 @@ public void consume(ConnectionContext context, sni, shc.resumingSession.serverNameIndication)) { shc.isResumption = false; shc.resumingSession = null; + // this server is disallowing this session resumption, + // so don't include the pre-shared key in the + // ServerHello handshake message + shc.handshakeExtensions.remove(SH_PRE_SHARED_KEY); if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "abort session resumption, " + diff --git a/src/java.base/share/classes/sun/security/util/Debug.java b/src/java.base/share/classes/sun/security/util/Debug.java index e5a6b288ff8..0a8ef136b92 100644 --- a/src/java.base/share/classes/sun/security/util/Debug.java +++ b/src/java.base/share/classes/sun/security/util/Debug.java @@ -27,6 +27,9 @@ import java.io.PrintStream; import java.math.BigInteger; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.HexFormat; import java.util.regex.Pattern; import java.util.regex.Matcher; @@ -41,8 +44,14 @@ public class Debug { private String prefix; + private boolean printDateTime; + private boolean printThreadDetails; private static String args; + private static boolean threadInfoAll; + private static boolean timeStampInfoAll; + private static final String TIMESTAMP_OPTION = "+timestamp"; + private static final String THREAD_OPTION = "+thread"; static { args = GetPropertyAction.privilegedGetProperty("java.security.debug"); @@ -61,12 +70,21 @@ public class Debug { args = marshal(args); if (args.equals("help")) { Help(); + } else if (args.contains("all")) { + // "all" option has special handling for decorator options + // If the thread or timestamp decorator option is detected + // with the "all" option, then it impacts decorator options + // for other categories + int beginIndex = args.lastIndexOf("all") + "all".length(); + int commaIndex = args.indexOf(',', beginIndex); + if (commaIndex == -1) commaIndex = args.length(); + threadInfoAll = args.substring(beginIndex, commaIndex).contains(THREAD_OPTION); + timeStampInfoAll = args.substring(beginIndex, commaIndex).contains(TIMESTAMP_OPTION); } } } - public static void Help() - { + public static void Help() { System.err.println(); System.err.println("all turn on all debugging"); System.err.println("access print all checkPermission results"); @@ -95,6 +113,11 @@ public static void Help() System.err.println("ts timestamping"); System.err.println("x509 X.509 certificate debugging"); System.err.println(); + System.err.println("+timestamp can be appended to any of above options to print"); + System.err.println(" a timestamp for that debug option"); + System.err.println("+thread can be appended to any of above options to print"); + System.err.println(" thread and caller information for that debug option"); + System.err.println(); System.err.println("The following can be used with access:"); System.err.println(); System.err.println("stack include stack trace"); @@ -139,8 +162,7 @@ public static void Help() * option is set. Set the prefix to be the same as option. */ - public static Debug getInstance(String option) - { + public static Debug getInstance(String option) { return getInstance(option, option); } @@ -148,23 +170,57 @@ public static Debug getInstance(String option) * Get a Debug object corresponding to whether or not the given * option is set. Set the prefix to prefix. */ - public static Debug getInstance(String option, String prefix) - { + public static Debug getInstance(String option, String prefix) { if (isOn(option)) { Debug d = new Debug(); d.prefix = prefix; + d.configureExtras(option); return d; } else { return null; } } + private static String formatCaller() { + return StackWalker.getInstance().walk(s -> + s.dropWhile(f -> + f.getClassName().startsWith("sun.security.util.Debug")) + .map(f -> f.getFileName() + ":" + f.getLineNumber()) + .findFirst().orElse("unknown caller")); + } + + // parse an option string to determine if extra details, + // like thread and timestamp, should be printed + private void configureExtras(String option) { + // treat "all" as special case, only used for java.security.debug property + this.printDateTime = timeStampInfoAll; + this.printThreadDetails = threadInfoAll; + + if (printDateTime && printThreadDetails) { + // nothing left to configure + return; + } + + // args is converted to lower case for the most part via marshal method + int optionIndex = args.lastIndexOf(option); + if (optionIndex == -1) { + // option not in args list. Only here since "all" was present + // in debug property argument. "all" option already parsed + return; + } + int beginIndex = optionIndex + option.length(); + int commaIndex = args.indexOf(',', beginIndex); + if (commaIndex == -1) commaIndex = args.length(); + String subOpt = args.substring(beginIndex, commaIndex); + printDateTime = printDateTime || subOpt.contains(TIMESTAMP_OPTION); + printThreadDetails = printThreadDetails || subOpt.contains(THREAD_OPTION); + } + /** * True if the system property "security.debug" contains the * string "option". */ - public static boolean isOn(String option) - { + public static boolean isOn(String option) { if (args == null) return false; else { @@ -187,18 +243,16 @@ public static boolean isVerbose() { * created from the call to getInstance. */ - public void println(String message) - { - System.err.println(prefix + ": "+message); + public void println(String message) { + System.err.println(prefix + extraInfo() + ": " + message); } /** * print a message to stderr that is prefixed with the prefix * created from the call to getInstance and obj. */ - public void println(Object obj, String message) - { - System.err.println(prefix + " [" + obj.getClass().getSimpleName() + + public void println(Object obj, String message) { + System.err.println(prefix + extraInfo() + " [" + obj.getClass().getSimpleName() + "@" + System.identityHashCode(obj) + "]: "+message); } @@ -206,18 +260,36 @@ public void println(Object obj, String message) * print a blank line to stderr that is prefixed with the prefix. */ - public void println() - { - System.err.println(prefix + ":"); + public void println() { + System.err.println(prefix + extraInfo() + ":"); } /** * print a message to stderr that is prefixed with the prefix. */ - public static void println(String prefix, String message) - { - System.err.println(prefix + ": "+message); + public void println(String prefix, String message) { + System.err.println(prefix + extraInfo() + ": " + message); + } + + /** + * If thread debug option enabled, include information containing + * hex value of threadId and the current thread name + * If timestamp debug option enabled, include timestamp string + * @return extra info if debug option enabled. + */ + private String extraInfo() { + String retString = ""; + if (printThreadDetails) { + retString = "0x" + Long.toHexString( + Thread.currentThread().threadId()).toUpperCase(Locale.ROOT) + + "|" + Thread.currentThread().getName() + "|" + formatCaller(); + } + if (printDateTime) { + retString += (retString.isEmpty() ? "" : "|") + + FormatHolder.DATE_TIME_FORMATTER.format(Instant.now()); + } + return retString.isEmpty() ? "" : "[" + retString + "]"; } /** @@ -333,4 +405,11 @@ public static String toString(byte[] b) { return HexFormat.ofDelimiter(":").formatHex(b); } + // Holder class to break cyclic dependency seen during build + private static class FormatHolder { + private static final String PATTERN = "yyyy-MM-dd kk:mm:ss.SSS"; + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter + .ofPattern(PATTERN, Locale.ENGLISH) + .withZone(ZoneId.systemDefault()); + } } diff --git a/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java b/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java index 8e201e550ed..17b9e7248c0 100644 --- a/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java +++ b/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,22 @@ void checkDistrust(String variant, X509Certificate[] chain) } SymantecTLSPolicy.checkDistrust(chain); } + }, + + /** + * Distrust TLS Server certificates anchored by an Entrust root CA and + * issued after November 11, 2024. If enabled, this policy is currently + * enforced by the PKIX and SunX509 TrustManager implementations + * of the SunJSSE provider implementation. + */ + ENTRUST_TLS { + void checkDistrust(String variant, X509Certificate[] chain) + throws ValidatorException { + if (!variant.equals(Validator.VAR_TLS_SERVER)) { + return; + } + EntrustTLSPolicy.checkDistrust(chain); + } }; /** diff --git a/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java b/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java new file mode 100644 index 00000000000..4c4906d8eb3 --- /dev/null +++ b/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.security.validator; + +import java.security.cert.X509Certificate; +import java.time.LocalDate; +import java.time.Month; +import java.time.ZoneOffset; +import java.util.Date; +import java.util.Map; +import java.util.Set; + +import sun.security.util.Debug; +import sun.security.x509.X509CertImpl; + +/** + * This class checks if Entrust issued TLS Server certificates should be + * restricted. + */ +final class EntrustTLSPolicy { + + private static final Debug debug = Debug.getInstance("certpath"); + + // SHA-256 certificate fingerprints of distrusted roots + private static final Set FINGERPRINTS = Set.of( + // cacerts alias: entrustevca + // DN: CN=Entrust Root Certification Authority, + // OU=(c) 2006 Entrust, Inc., + // OU=www.entrust.net/CPS is incorporated by reference, + // O=Entrust, Inc., C=US + "73C176434F1BC6D5ADF45B0E76E727287C8DE57616C1E6E6141A2B2CBC7D8E4C", + // cacerts alias: entrustrootcaec1 + // DN: CN=Entrust Root Certification Authority - EC1, + // OU=(c) 2012 Entrust, Inc. - for authorized use only, + // OU=See www.entrust.net/legal-terms, O=Entrust, Inc., C=US + "02ED0EB28C14DA45165C566791700D6451D7FB56F0B2AB1D3B8EB070E56EDFF5", + // cacerts alias: entrustrootcag2 + // DN: CN=Entrust Root Certification Authority - G2, + // OU=(c) 2009 Entrust, Inc. - for authorized use only, + // OU=See www.entrust.net/legal-terms, O=Entrust, Inc., C=US + "43DF5774B03E7FEF5FE40D931A7BEDF1BB2E6B42738C4E6D3841103D3AA7F339", + // cacerts alias: entrustrootcag4 + // DN: CN=Entrust Root Certification Authority - G4 + // OU=(c) 2015 Entrust, Inc. - for authorized use only, + // OU=See www.entrust.net/legal-terms, O=Entrust, Inc., C=US, + "DB3517D1F6732A2D5AB97C533EC70779EE3270A62FB4AC4238372460E6F01E88", + // cacerts alias: entrust2048ca + // DN: CN=Entrust.net Certification Authority (2048), + // OU=(c) 1999 Entrust.net Limited, + // OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), + // O=Entrust.net + "6DC47172E01CBCB0BF62580D895FE2B8AC9AD4F873801E0C10B9C837D21EB177", + // cacerts alias: affirmtrustcommercialca + // DN: CN=AffirmTrust Commercial, O=AffirmTrust, C=US + "0376AB1D54C5F9803CE4B2E201A0EE7EEF7B57B636E8A93C9B8D4860C96F5FA7", + // cacerts alias: affirmtrustnetworkingca + // DN: CN=AffirmTrust Networking, O=AffirmTrust, C=US + "0A81EC5A929777F145904AF38D5D509F66B5E2C58FCDB531058B0E17F3F0B41B", + // cacerts alias: affirmtrustpremiumca + // DN: CN=AffirmTrust Premium, O=AffirmTrust, C=US + "70A73F7F376B60074248904534B11482D5BF0E698ECC498DF52577EBF2E93B9A", + // cacerts alias: affirmtrustpremiumeccca + // DN: CN=AffirmTrust Premium ECC, O=AffirmTrust, C=US + "BD71FDF6DA97E4CF62D1647ADD2581B07D79ADF8397EB4ECBA9C5E8488821423" + ); + + // Any TLS Server certificate that is anchored by one of the Entrust + // roots above and is issued after this date will be distrusted. + private static final LocalDate NOVEMBER_11_2024 = + LocalDate.of(2024, Month.NOVEMBER, 11); + + /** + * This method assumes the eeCert is a TLS Server Cert and chains back to + * the anchor. + * + * @param chain the end-entity's certificate chain. The end entity cert + * is at index 0, the trust anchor at index n-1. + * @throws ValidatorException if the certificate is distrusted + */ + static void checkDistrust(X509Certificate[] chain) + throws ValidatorException { + X509Certificate anchor = chain[chain.length-1]; + String fp = fingerprint(anchor); + if (fp == null) { + throw new ValidatorException("Cannot generate fingerprint for " + + "trust anchor of TLS server certificate"); + } + if (FINGERPRINTS.contains(fp)) { + Date notBefore = chain[0].getNotBefore(); + LocalDate ldNotBefore = LocalDate.ofInstant(notBefore.toInstant(), + ZoneOffset.UTC); + // reject if certificate is issued after November 11, 2024 + checkNotBefore(ldNotBefore, NOVEMBER_11_2024, anchor); + } + } + + private static String fingerprint(X509Certificate cert) { + return X509CertImpl.getFingerprint("SHA-256", cert, debug); + } + + private static void checkNotBefore(LocalDate notBeforeDate, + LocalDate distrustDate, X509Certificate anchor) + throws ValidatorException { + if (notBeforeDate.isAfter(distrustDate)) { + throw new ValidatorException + ("TLS Server certificate issued after " + distrustDate + + " and anchored by a distrusted legacy Entrust root CA: " + + anchor.getSubjectX500Principal(), + ValidatorException.T_UNTRUSTED_CERT, anchor); + } + } + + private EntrustTLSPolicy() {} +} diff --git a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties index 5daf1e07336..3559f793c54 100644 --- a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties +++ b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -287,6 +287,7 @@ ZAR=ZAR ZMK=ZMK ZMW=ZMW ZWD=ZWD +ZWG=ZWG ZWL=ZWL ZWN=ZWN ZWR=ZWR @@ -512,5 +513,6 @@ yum=Yugoslavian New Dinar (1994-2002) zar=South African Rand zmk=Zambian Kwacha zwd=Zimbabwean Dollar (1980-2008) +zwg=Zimbabwe Gold zwl=Zimbabwean Dollar (2009) zwr=Zimbabwean Dollar (2008) diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 5149edba0e5..7a5ca18daac 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1330,6 +1330,9 @@ jdk.sasl.disabledMechanisms= # A4FE7C7F15155F3F0AEF7AAA83CF6E06DEB97CA3F909DF920AC1490882D488ED # Distrust after December 31, 2019. # +# ENTRUST_TLS : Distrust TLS Server certificates anchored by +# an Entrust root CA and issued after November 11, 2024. +# # Leading and trailing whitespace surrounding each value are ignored. # Unknown values are ignored. If the property is commented out or set to the # empty String, no policies are enforced. @@ -1341,7 +1344,7 @@ jdk.sasl.disabledMechanisms= # jdk.certpath.disabledAlgorithms; those restrictions are still enforced even # if this property is not enabled. # -jdk.security.caDistrustPolicies=SYMANTEC_TLS +jdk.security.caDistrustPolicies=SYMANTEC_TLS,ENTRUST_TLS # # FilePermission path canonicalization diff --git a/src/java.base/share/data/cacerts/ssltlsrootecc2022 b/src/java.base/share/data/cacerts/ssltlsrootecc2022 new file mode 100644 index 00000000000..706e6aefb4e --- /dev/null +++ b/src/java.base/share/data/cacerts/ssltlsrootecc2022 @@ -0,0 +1,21 @@ +Owner: CN=SSL.com TLS ECC Root CA 2022, O=SSL Corporation, C=US +Issuer: CN=SSL.com TLS ECC Root CA 2022, O=SSL Corporation, C=US +Serial number: 1403f5abfb378b17405be243b2a5d1c4 +Valid from: Thu Aug 25 16:33:48 GMT 2022 until: Sun Aug 19 16:33:47 GMT 2046 +Signature algorithm name: SHA384withECDSA +Subject Public Key Algorithm: 384-bit EC (secp384r1) key +Version: 3 +-----BEGIN CERTIFICATE----- +MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT +U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 +MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh +dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm +acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN +SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME +GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW +uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp +15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN +b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/ssltlsrootrsa2022 b/src/java.base/share/data/cacerts/ssltlsrootrsa2022 new file mode 100644 index 00000000000..ad456b0b5f4 --- /dev/null +++ b/src/java.base/share/data/cacerts/ssltlsrootrsa2022 @@ -0,0 +1,39 @@ +Owner: CN=SSL.com TLS RSA Root CA 2022, O=SSL Corporation, C=US +Issuer: CN=SSL.com TLS RSA Root CA 2022, O=SSL Corporation, C=US +Serial number: 6fbedaad73bd0840e28b4dbed4f75b91 +Valid from: Thu Aug 25 16:34:22 GMT 2022 until: Sun Aug 19 16:34:21 GMT 2046 +Signature algorithm name: SHA256withRSA +Subject Public Key Algorithm: 4096-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO +MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD +DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX +DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw +b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP +L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY +t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins +S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 +PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO +L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 +R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w +dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS ++YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS +d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG +AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f +gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z +NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM +QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf +R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ +DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW +P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy +lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq +bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w +AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q +r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji +Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU +98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/currency/CurrencyData.properties b/src/java.base/share/data/currency/CurrencyData.properties index 26f4aa24d88..550662ec38a 100644 --- a/src/java.base/share/data/currency/CurrencyData.properties +++ b/src/java.base/share/data/currency/CurrencyData.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ formatVersion=3 # Version of the currency code information in this class. # It is a serial number that accompanies with each amendment. -dataVersion=176 +dataVersion=177 # List of all valid ISO 4217 currency codes. # To ensure compatibility, do not remove codes. @@ -56,8 +56,8 @@ all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036 TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-UYI940-\ UYU858-UZS860-VEB862-VED926-VEF937-VES928-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\ XBB956-XBC957-XBD958-XCD951-XCG532-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\ - XPT962-XSU994-XTS963-XUA965-XXX999-YER886-YUM891-ZAR710-ZMK894-ZMW967-ZWD716-ZWL932-\ - ZWN942-ZWR935 + XPT962-XSU994-XTS963-XUA965-XXX999-YER886-YUM891-ZAR710-ZMK894-ZMW967-ZWD716-ZWG924-\ + ZWL932-ZWN942-ZWR935 # Mappings from ISO 3166 country codes to ISO 4217 currency codes. @@ -582,7 +582,7 @@ YE=YER # ZAMBIA ZM=ZMW # ZIMBABWE -ZW=ZWL +ZW=ZWG # List of currencies with non-2digit decimals for minor units, diff --git a/src/java.base/share/data/lsrdata/language-subtag-registry.txt b/src/java.base/share/data/lsrdata/language-subtag-registry.txt index 4737c50e425..3079d77ed8b 100644 --- a/src/java.base/share/data/lsrdata/language-subtag-registry.txt +++ b/src/java.base/share/data/lsrdata/language-subtag-registry.txt @@ -1,4 +1,4 @@ -File-Date: 2024-03-07 +File-Date: 2024-06-14 %% Type: language Subtag: aa @@ -9402,6 +9402,7 @@ Macrolanguage: doi %% Type: language Subtag: dgr +Description: Tlicho Description: Dogrib Description: Tłı̨chǫ Added: 2005-10-16 @@ -15255,6 +15256,11 @@ Description: Isu (Menchum Division) Added: 2009-07-29 %% Type: language +Subtag: isv +Description: Interslavic +Added: 2024-05-15 +%% +Type: language Subtag: itb Description: Binongan Itneg Added: 2009-07-29 @@ -48003,7 +48009,9 @@ Type: variant Subtag: laukika Description: Classical Sanskrit Added: 2010-07-28 +Deprecated: 2024-06-08 Prefix: sa +Comments: Preferred tag is cls %% Type: variant Subtag: lemosin @@ -48379,9 +48387,11 @@ Type: variant Subtag: vaidika Description: Vedic Sanskrit Added: 2010-07-28 +Deprecated: 2024-06-08 Prefix: sa Comments: The most ancient dialect of Sanskrit used in verse and prose composed until about the 4th century B.C.E. +Comments: Preferred tag is vsn %% Type: variant Subtag: valbadia diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java index 7cab6d31690..98a49564e3d 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java @@ -882,6 +882,10 @@ void move(UnixPath source, UnixPath target, CopyOption... options) // get attributes of source file (don't follow links) try { sourceAttrs = UnixFileAttributes.get(source, false); + if (sourceAttrs.isDirectory()) { + // ensure source can be moved + access(source, W_OK); + } } catch (UnixException x) { x.rethrowAsIOException(source); } @@ -901,10 +905,9 @@ void move(UnixPath source, UnixPath target, CopyOption... options) if (targetExists) { if (sourceAttrs.isSameFile(targetAttrs)) return; // nothing to do as files are identical - if (!flags.replaceExisting) { + if (!flags.replaceExisting) throw new FileAlreadyExistsException( target.getPathForExceptionMessage()); - } // attempt to delete target try { @@ -1010,6 +1013,17 @@ void copy(final UnixPath source, sm.checkPermission(new LinkPermission("symbolic")); } + // ensure source can be copied + if (!sourceAttrs.isSymbolicLink() || flags.followLinks) { + try { + // the access(2) system call always follows links so it + // is suppressed if the source is an unfollowed link + access(source, R_OK); + } catch (UnixException exc) { + exc.rethrowAsIOException(source); + } + } + // get attributes of target file (don't follow links) try { targetAttrs = UnixFileAttributes.get(target, false); @@ -1028,6 +1042,7 @@ void copy(final UnixPath source, if (!flags.replaceExisting) throw new FileAlreadyExistsException( target.getPathForExceptionMessage()); + try { if (targetAttrs.isDirectory()) { rmdir(target); diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java index 9f5df28fcba..ddb649a63c1 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -495,7 +495,7 @@ public void createSymbolicLink(Path obj1, Path obj2, FileAttribute... attrs) if (attrs.length > 0) { UnixFileModeAttribute.toUnixMode(0, attrs); // may throw NPE or UOE throw new UnsupportedOperationException("Initial file attributes" + - "not supported when creating symbolic link"); + " not supported when creating symbolic link"); } // permission check diff --git a/src/java.base/unix/native/libjava/ProcessImpl_md.c b/src/java.base/unix/native/libjava/ProcessImpl_md.c index 558882f61e1..506b33aae96 100644 --- a/src/java.base/unix/native/libjava/ProcessImpl_md.c +++ b/src/java.base/unix/native/libjava/ProcessImpl_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -559,8 +559,17 @@ spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) } offset = copystrings(buf, 0, &c->argv[0]); offset = copystrings(buf, offset, &c->envv[0]); - memcpy(buf+offset, c->pdir, sp.dirlen); - offset += sp.dirlen; + if (c->pdir != NULL) { + if (sp.dirlen > 0) { + memcpy(buf+offset, c->pdir, sp.dirlen); + offset += sp.dirlen; + } + } else { + if (sp.dirlen > 0) { + free(buf); + return -1; + } + } offset = copystrings(buf, offset, parentPathv); assert(offset == bufsize); diff --git a/src/java.base/unix/native/libnet/DefaultProxySelector.c b/src/java.base/unix/native/libnet/DefaultProxySelector.c index dc5424e4b2d..fd54d817af9 100644 --- a/src/java.base/unix/native/libnet/DefaultProxySelector.c +++ b/src/java.base/unix/native/libnet/DefaultProxySelector.c @@ -91,13 +91,13 @@ g_type_init_func* my_g_type_init_func = NULL; typedef struct _GProxyResolver GProxyResolver; typedef struct _GSocketConnectable GSocketConnectable; typedef struct GError GError; -typedef GProxyResolver* g_proxy_resolver_get_default_func(); -typedef char** g_proxy_resolver_lookup_func(); -typedef GSocketConnectable* g_network_address_parse_uri_func(); -typedef const char* g_network_address_get_hostname_func(); -typedef unsigned short g_network_address_get_port_func(); -typedef void g_strfreev_func(); -typedef void g_clear_error_func(); +typedef GProxyResolver* g_proxy_resolver_get_default_func(void); +typedef char** g_proxy_resolver_lookup_func(GProxyResolver* resolver, char* uri, void *null, GError **error_p); +typedef GSocketConnectable* g_network_address_parse_uri_func(char* proxy, unsigned short default_port, GError **error_p); +typedef const char* g_network_address_get_hostname_func(GSocketConnectable* conn); +typedef unsigned short g_network_address_get_port_func(GSocketConnectable* conn); +typedef void g_strfreev_func(char** proxies); +typedef void g_clear_error_func(GError **error_p); static g_proxy_resolver_get_default_func* g_proxy_resolver_get_default = NULL; static g_proxy_resolver_lookup_func* g_proxy_resolver_lookup = NULL; diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index 6d933be4e6e..f863d6aca70 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -146,9 +146,10 @@ struct my_statx #define STATX_BTIME 0x00000800U #endif -#ifndef STATX_ALL -#define STATX_ALL (STATX_BTIME | STATX_BASIC_STATS) -#endif +// +// STATX_ALL is deprecated; use a different name to avoid confusion. +// +#define LOCAL_STATX_ALL (STATX_BASIC_STATS | STATX_BTIME) #ifndef AT_FDCWD #define AT_FDCWD -100 @@ -624,8 +625,19 @@ static void copy_statx_attributes(JNIEnv* env, struct my_statx* buf, jobject att (*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->stx_atime.tv_sec); (*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->stx_mtime.tv_sec); (*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->stx_ctime.tv_sec); - (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->stx_btime.tv_sec); - (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec, (jlong)buf->stx_btime.tv_nsec); + if ((buf->stx_mask & STATX_BTIME) != 0) { + // Birth time was filled in so use it + (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, + (jlong)buf->stx_btime.tv_sec); + (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec, + (jlong)buf->stx_btime.tv_nsec); + } else { + // Birth time was not filled in: fall back to last modification time + (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, + (jlong)buf->stx_mtime.tv_sec); + (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec, + (jlong)buf->stx_mtime.tv_nsec); + } (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->stx_atime.tv_nsec); (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->stx_mtime.tv_nsec); (*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->stx_ctime.tv_nsec); @@ -679,7 +691,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this, #if defined(__linux__) struct my_statx statx_buf; int flags = AT_STATX_SYNC_AS_STAT; - unsigned int mask = STATX_ALL; + unsigned int mask = LOCAL_STATX_ALL; if (my_statx_func != NULL) { // Prefer statx over stat64 on Linux if it's available @@ -711,7 +723,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this, #if defined(__linux__) struct my_statx statx_buf; int flags = AT_STATX_SYNC_AS_STAT | AT_SYMLINK_NOFOLLOW; - unsigned int mask = STATX_ALL; + unsigned int mask = LOCAL_STATX_ALL; if (my_statx_func != NULL) { // Prefer statx over stat64 on Linux if it's available @@ -742,7 +754,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_fstat0(JNIEnv* env, jclass this, jint fd, #if defined(__linux__) struct my_statx statx_buf; int flags = AT_EMPTY_PATH | AT_STATX_SYNC_AS_STAT; - unsigned int mask = STATX_ALL; + unsigned int mask = LOCAL_STATX_ALL; if (my_statx_func != NULL) { // statx supports FD use via dirfd iff pathname is an empty string and the @@ -775,7 +787,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd #if defined(__linux__) struct my_statx statx_buf; int flags = AT_STATX_SYNC_AS_STAT; - unsigned int mask = STATX_ALL; + unsigned int mask = LOCAL_STATX_ALL; if (my_statx_func != NULL) { // Prefer statx over stat64 on Linux if it's available diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsException.java b/src/java.base/windows/classes/sun/nio/fs/WindowsException.java index 1312d5a0938..f1eff69210b 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsException.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ import static sun.nio.fs.WindowsConstants.*; /** - * Internal exception thrown when a Win32 calls fails. + * Internal exception thrown when a Win32 call fails. */ class WindowsException extends Exception { diff --git a/src/java.desktop/macosx/classes/sun/font/CStrike.java b/src/java.desktop/macosx/classes/sun/font/CStrike.java index eb049c3d449..b0131711ca5 100644 --- a/src/java.desktop/macosx/classes/sun/font/CStrike.java +++ b/src/java.desktop/macosx/classes/sun/font/CStrike.java @@ -199,7 +199,7 @@ void getGlyphImageBounds(int glyphCode, Point2D.Float pt, Rectangle result) { getGlyphImageBounds(glyphCode, pt.x, pt.y, floatRect); if (floatRect.width == 0 && floatRect.height == 0) { - result.setRect(0, 0, -1, -1); + result.setRect(0, 0, 0, 0); return; } diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java index d4526324c58..2da02e34b45 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,10 +36,11 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.annotation.Native; -import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.concurrent.Callable; import java.util.Arrays; @@ -64,7 +65,6 @@ import javax.swing.JList; import javax.swing.JTree; import javax.swing.KeyStroke; -import javax.swing.tree.TreePath; import sun.awt.AWTAccessor; import sun.lwawt.LWWindowPeer; @@ -759,21 +759,6 @@ private static Object[] getChildrenAndRolesImpl(Accessible a, Component c, int w return new Object[]{childrenAndRoles.get(whichChildren * 2), childrenAndRoles.get((whichChildren * 2) + 1)}; } - private static Accessible createAccessibleTreeNode(JTree t, TreePath p) { - Accessible a = null; - - try { - Class accessibleJTreeNodeClass = Class.forName("javax.swing.JTree$AccessibleJTree$AccessibleJTreeNode"); - Constructor constructor = accessibleJTreeNodeClass.getConstructor(t.getAccessibleContext().getClass(), JTree.class, TreePath.class, Accessible.class); - constructor.setAccessible(true); - a = ((Accessible) constructor.newInstance(t.getAccessibleContext(), t, p, null)); - } catch (Exception e) { - e.printStackTrace(); - } - - return a; - } - // This method is called from the native // Each child takes up three entries in the array: one for itself, one for its role, and one for the recursion level private static Object[] getChildrenAndRolesRecursive(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored, final int level) { @@ -781,62 +766,21 @@ private static Object[] getChildrenAndRolesRecursive(final Accessible a, final C return invokeAndWait(new Callable() { public Object[] call() throws Exception { ArrayList allChildren = new ArrayList(); - - Accessible at = null; - if (a instanceof CAccessible) { - at = CAccessible.getSwingAccessible(a); - } else { - at = a; - } - - if (at instanceof JTree) { - JTree tree = ((JTree) at); - - if (whichChildren == JAVA_AX_ALL_CHILDREN) { - int count = tree.getRowCount(); - for (int i = 0; i < count; i++) { - TreePath path = tree.getPathForRow(i); - Accessible an = createAccessibleTreeNode(tree, path); - if (an != null) { - AccessibleContext ac = an.getAccessibleContext(); - if (ac != null) { - allChildren.add(an); - allChildren.add(ac.getAccessibleRole());; - allChildren.add(String.valueOf((tree.isRootVisible() ? path.getPathCount() : path.getPathCount() - 1))); - } - } - } - } - - if (whichChildren == JAVA_AX_SELECTED_CHILDREN) { - int count = tree.getSelectionCount(); - for (int i = 0; i < count; i++) { - TreePath path = tree.getSelectionPaths()[i]; - Accessible an = createAccessibleTreeNode(tree, path); - if (an != null) { - AccessibleContext ac = an.getAccessibleContext(); - if (ac != null) { - allChildren.add(an); - allChildren.add(ac.getAccessibleRole()); - allChildren.add(String.valueOf((tree.isRootVisible() ? path.getPathCount() : path.getPathCount() - 1))); - } - } - } - } - - return allChildren.toArray(); - } - ArrayList currentLevelChildren = new ArrayList(); ArrayList parentStack = new ArrayList(); + HashMap> childrenOfParent = new HashMap<>(); parentStack.add(a); ArrayList indexses = new ArrayList(); Integer index = 0; int currentLevel = level; while (!parentStack.isEmpty()) { Accessible p = parentStack.get(parentStack.size() - 1); - - currentLevelChildren.addAll(Arrays.asList(getChildrenAndRolesImpl(p, c, JAVA_AX_ALL_CHILDREN, allowIgnored, ChildrenOperations.COMMON))); + if (!childrenOfParent.containsKey(p)) { + childrenOfParent.put(p, Arrays.asList(getChildrenAndRolesImpl(p, + c, JAVA_AX_ALL_CHILDREN, allowIgnored, + ChildrenOperations.COMMON))); + } + currentLevelChildren.addAll(childrenOfParent.get(p)); if ((currentLevelChildren.size() == 0) || (index >= currentLevelChildren.size())) { if (!parentStack.isEmpty()) parentStack.remove(parentStack.size() - 1); if (!indexses.isEmpty()) index = indexses.remove(indexses.size() - 1); @@ -879,7 +823,6 @@ public Object[] call() throws Exception { currentLevel += 1; continue; } - } return allChildren.toArray(); diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h index 2992d82cbe4..8281f0b0213 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, JetBrains s.r.o.. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,12 @@ // This is a tree representation. See: https://developer.apple.com/documentation/appkit/nsoutlineview @interface OutlineAccessibility : ListAccessibility - +{ + NSMutableArray> *rowCache; + BOOL rowCacheValid; + NSMutableArray> *selectedRowCache; + BOOL selectedRowCacheValid; +} @property(readonly) BOOL isTreeRootVisible; @end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m index cdf6dbbd4ab..08240614bf7 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, JetBrains s.r.o.. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,4 +55,88 @@ - (NSString *)accessibilityLabel return [[super accessibilityLabel] isEqualToString:@"list"] ? @"tree" : [super accessibilityLabel]; } +- (nullable NSArray> *)accessibilityRows +{ + return [self accessibilityChildren]; +} + +- (nullable NSArray> *)accessibilitySelectedRows +{ + return [self accessibilitySelectedChildren]; +} + +- (nullable NSArray> *)accessibilityChildren +{ + if (![self isCacheValid]) { + NSArray *t = [super accessibilityChildren]; + if (t != nil) { + rowCache = [[NSMutableArray arrayWithArray:t] retain]; + } else { + rowCache = nil; + } + rowCacheValid = YES; + } + return rowCache; +} + +- (nullable NSArray> *)accessibilitySelectedChildren +{ + if (!selectedRowCacheValid) { + NSArray *t = [super accessibilitySelectedChildren]; + if (t != nil) { + selectedRowCache = [[NSMutableArray arrayWithArray:t] retain]; + } else { + selectedRowCache = nil; + } + selectedRowCacheValid = YES; + } + return selectedRowCache; +} + +- (BOOL)isCacheValid +{ + if (rowCacheValid && [[self parent] respondsToSelector:NSSelectorFromString(@"isCacheValid")]) { + return [[self parent] isCacheValid]; + } + return rowCacheValid; +} + +- (void)invalidateCache +{ + rowCacheValid = NO; +} + +- (void)invalidateSelectionCache +{ + selectedRowCacheValid = NO; +} + +- (void)postSelectionChanged +{ + AWT_ASSERT_APPKIT_THREAD; + [self invalidateSelectionCache]; + [super postSelectionChanged]; +} + +- (void)postTreeNodeCollapsed +{ + AWT_ASSERT_APPKIT_THREAD; + [self invalidateCache]; + [super postTreeNodeCollapsed]; +} + +- (void)postTreeNodeExpanded +{ + AWT_ASSERT_APPKIT_THREAD; + [self invalidateCache]; + [super postTreeNodeExpanded]; +} + +- (void)postSelectedCellsChanged +{ + AWT_ASSERT_APPKIT_THREAD; + [self invalidateSelectionCache]; + [super postSelectedCellsChanged]; +} + @end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m b/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m index f6e8fe6af55..ecdd6e4cdf8 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m @@ -1020,4 +1020,20 @@ @implementation CGGI_GlyphCanvas CTFontGetAdvancesForGlyphs(font, kCTFontDefaultOrientation, glyphs, advances, count); } } -} \ No newline at end of file + int MAX_SIZE = 1 << 30; + if (bboxes) { + for (int i = 0; i < count; i++) { + if (bboxes[i].origin.x > (double)MAX_SIZE) bboxes[i].origin.x = 0; + if (bboxes[i].origin.y > (double)MAX_SIZE) bboxes[i].origin.y = 0; + if (bboxes[i].size.width > (double)MAX_SIZE) bboxes[i].size.width = 0; + if (bboxes[i].size.height > (double)MAX_SIZE) bboxes[i].size.height = 0; + } + } + if (advances) { + for (int i = 0; i < count; i++) { + if (advances[i].width > (double)MAX_SIZE) advances[i].width = 0; + if (advances[i].height > (double)MAX_SIZE) advances[i].height = 0; + } + } +} + diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java index f7063bdc25f..551f4dc4d72 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/AdobeMarkerSegment.java @@ -55,15 +55,17 @@ class AdobeMarkerSegment extends MarkerSegment { AdobeMarkerSegment(JPEGBuffer buffer) throws IOException { super(buffer); - buffer.bufPtr += ID_SIZE; // Skip the id - version = (buffer.buf[buffer.bufPtr++] & 0xff) << 8; - version |= buffer.buf[buffer.bufPtr++] & 0xff; - flags0 = (buffer.buf[buffer.bufPtr++] & 0xff) << 8; - flags0 |= buffer.buf[buffer.bufPtr++] & 0xff; - flags1 = (buffer.buf[buffer.bufPtr++] & 0xff) << 8; - flags1 |= buffer.buf[buffer.bufPtr++] & 0xff; - transform = buffer.buf[buffer.bufPtr++] & 0xff; + int markPtr = buffer.bufPtr; + markPtr += ID_SIZE; // Skip the id + version = (buffer.buf[markPtr++] & 0xff) << 8; + version |= buffer.buf[markPtr++] & 0xff; + flags0 = (buffer.buf[markPtr++] & 0xff) << 8; + flags0 |= buffer.buf[markPtr++] & 0xff; + flags1 = (buffer.buf[markPtr++] & 0xff) << 8; + flags1 |= buffer.buf[markPtr++] & 0xff; + transform = buffer.buf[markPtr++] & 0xff; buffer.bufAvail -= length; + buffer.bufPtr += length; } AdobeMarkerSegment(Node node) throws IIOInvalidTreeException { diff --git a/src/java.desktop/share/classes/javax/swing/JEditorPane.java b/src/java.desktop/share/classes/javax/swing/JEditorPane.java index ee2f174206c..81ae7ba6d95 100644 --- a/src/java.desktop/share/classes/javax/swing/JEditorPane.java +++ b/src/java.desktop/share/classes/javax/swing/JEditorPane.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -619,35 +619,37 @@ void read(InputStream in, Document doc) throws IOException { String charset = (String) getClientProperty("charset"); try(Reader r = (charset != null) ? new InputStreamReader(in, charset) : new InputStreamReader(in)) { - kit.read(r, doc, 0); - } catch (BadLocationException e) { - throw new IOException(e.getMessage()); - } catch (ChangedCharSetException changedCharSetException) { - String charSetSpec = changedCharSetException.getCharSetSpec(); - if (changedCharSetException.keyEqualsCharSet()) { - putClientProperty("charset", charSetSpec); - } else { - setCharsetFromContentTypeParameters(charSetSpec); - } try { - in.reset(); - } catch (IOException exception) { - //mark was invalidated - in.close(); - URL url = (URL)doc.getProperty(Document.StreamDescriptionProperty); - if (url != null) { - URLConnection conn = url.openConnection(); - in = conn.getInputStream(); + kit.read(r, doc, 0); + } catch (BadLocationException e) { + throw new IOException(e.getMessage()); + } catch (ChangedCharSetException changedCharSetException) { + String charSetSpec = changedCharSetException.getCharSetSpec(); + if (changedCharSetException.keyEqualsCharSet()) { + putClientProperty("charset", charSetSpec); } else { - //there is nothing we can do to recover stream - throw changedCharSetException; + setCharsetFromContentTypeParameters(charSetSpec); } + try { + in.reset(); + } catch (IOException exception) { + //mark was invalidated + in.close(); + URL url = (URL)doc.getProperty(Document.StreamDescriptionProperty); + if (url != null) { + URLConnection conn = url.openConnection(); + in = conn.getInputStream(); + } else { + //there is nothing we can do to recover stream + throw changedCharSetException; + } + } + try { + doc.remove(0, doc.getLength()); + } catch (BadLocationException e) {} + doc.putProperty("IgnoreCharsetDirective", Boolean.valueOf(true)); + read(in, doc); } - try { - doc.remove(0, doc.getLength()); - } catch (BadLocationException e) {} - doc.putProperty("IgnoreCharsetDirective", Boolean.valueOf(true)); - read(in, doc); } } diff --git a/src/java.desktop/share/classes/javax/swing/ToolTipManager.java b/src/java.desktop/share/classes/javax/swing/ToolTipManager.java index b7f555b6644..2a4e4b71389 100644 --- a/src/java.desktop/share/classes/javax/swing/ToolTipManager.java +++ b/src/java.desktop/share/classes/javax/swing/ToolTipManager.java @@ -265,13 +265,19 @@ void showTipWindow() { toFind = new Point(screenLocation.x + preferredLocation.x, screenLocation.y + preferredLocation.y); } else { - toFind = mouseEvent.getLocationOnScreen(); + if (mouseEvent != null) { + toFind = mouseEvent.getLocationOnScreen(); + } else { + toFind = screenLocation; + } } GraphicsConfiguration gc = getDrawingGC(toFind); if (gc == null) { - toFind = mouseEvent.getLocationOnScreen(); - gc = getDrawingGC(toFind); + if (mouseEvent != null) { + toFind = mouseEvent.getLocationOnScreen(); + gc = getDrawingGC(toFind); + } if (gc == null) { gc = insideComponent.getGraphicsConfiguration(); } @@ -301,8 +307,12 @@ void showTipWindow() { location.x -= size.width; } } else { - location = new Point(screenLocation.x + mouseEvent.getX(), - screenLocation.y + mouseEvent.getY() + 20); + if (mouseEvent != null) { + location = new Point(screenLocation.x + mouseEvent.getX(), + screenLocation.y + mouseEvent.getY() + 20); + } else { + location = screenLocation; + } if (!leftToRight) { if(location.x - size.width>=0) { location.x -= size.width; diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java index 698175bb29c..6f0e678dcd6 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,10 +98,13 @@ public void propertyChange(PropertyChangeEvent e) { * This method is used to interrupt file loading thread. */ public void invalidateFileCache() { - if (filesLoader != null) { - filesLoader.loadThread.interrupt(); - filesLoader.cancelRunnables(); - filesLoader = null; + synchronized (this) { + if (filesLoader != null) { + filesLoader.loadThread.interrupt(); + filesLoader = null; + // Increment fetch ID to invalidate pending DoChangeContents + fetchID.incrementAndGet(); + } } } @@ -156,14 +159,15 @@ public void validateFileCache() { if (currentDirectory == null) { return; } - if (filesLoader != null) { - filesLoader.loadThread.interrupt(); - filesLoader.cancelRunnables(); - } + synchronized (this) { + if (filesLoader != null) { + filesLoader.loadThread.interrupt(); + } - int fid = fetchID.incrementAndGet(); - setBusy(true, fid); - filesLoader = new FilesLoader(currentDirectory, fid); + int fid = fetchID.incrementAndGet(); + setBusy(true, fid); + filesLoader = new FilesLoader(currentDirectory, fid); + } } /** @@ -276,7 +280,6 @@ private final class FilesLoader implements Runnable { private final boolean fileSelectionEnabled; private final int fid; private final File currentDirectory; - private volatile DoChangeContents runnable; private final Thread loadThread; private FilesLoader(File currentDirectory, int fid) { @@ -297,22 +300,20 @@ public void run() { } private void run0() { - FileSystemView fileSystem = fileSystemView; - if (loadThread.isInterrupted()) { return; } - File[] list = fileSystem.getFiles(currentDirectory, useFileHiding); + File[] list = fileSystemView.getFiles(currentDirectory, useFileHiding); if (loadThread.isInterrupted()) { return; } final Vector newFileCache = new Vector(); - Vector newFiles = new Vector(); + final Vector newFiles = new Vector(); - // run through the file list, add directories and selectable files to fileCache + // Run through the file list, add directories and selectable files to fileCache // Note that this block must be OUTSIDE of Invoker thread because of // deadlock possibility with custom synchronized FileSystemView for (File file : list) { @@ -339,66 +340,68 @@ private void run0() { // To avoid loads of synchronizations with Invoker and improve performance we // execute the whole block on the COM thread - runnable = ShellFolder.invoke(new Callable() { + DoChangeContents runnable = ShellFolder.invoke(new Callable() { public DoChangeContents call() { - int newSize = newFileCache.size(); - int oldSize = fileCache.size(); - - if (newSize > oldSize) { - //see if interval is added - int start = oldSize; - int end = newSize; - for (int i = 0; i < oldSize; i++) { - if (!newFileCache.get(i).equals(fileCache.get(i))) { - start = i; - for (int j = i; j < newSize; j++) { - if (newFileCache.get(j).equals(fileCache.get(i))) { - end = j; - break; + synchronized (fileCache) { + int newSize = newFileCache.size(); + int oldSize = fileCache.size(); + + if (newSize > oldSize) { + //see if interval is added + int start = oldSize; + int end = newSize; + for (int i = 0; i < oldSize; i++) { + if (!newFileCache.get(i).equals(fileCache.get(i))) { + start = i; + for (int j = i; j < newSize; j++) { + if (newFileCache.get(j).equals(fileCache.get(i))) { + end = j; + break; + } } + break; } - break; } - } - if (start >= 0 && end > start) { - List listStart_OldSize = new Vector<>(fileCache.subList(start, oldSize)); - if (newFileCache.subList(end, newSize).equals(listStart_OldSize)) { + if (start >= 0 && end > start + && newFileCache.subList(end, newSize) + .equals(fileCache.subList(start, oldSize))) { if (loadThread.isInterrupted()) { return null; } - return new DoChangeContents(newFileCache.subList(start, end), start, null, 0, fid); + return new DoChangeContents(newFileCache.subList(start, end), + start, null, 0, fid); } - } - } else if (newSize < oldSize) { - //see if interval is removed - int start = -1; - int end = -1; - for (int i = 0; i < newSize; i++) { - if (!newFileCache.get(i).equals(fileCache.get(i))) { - start = i; - end = i + oldSize - newSize; - break; + } else if (newSize < oldSize) { + //see if interval is removed + int start = -1; + int end = -1; + for (int i = 0; i < newSize; i++) { + if (!newFileCache.get(i).equals(fileCache.get(i))) { + start = i; + end = i + oldSize - newSize; + break; + } } - } - if (start >= 0 && end > start) { - List listEnd_OldSize = new Vector<>(fileCache.subList(end, oldSize)); - if (listEnd_OldSize.equals(newFileCache.subList(start, newSize))) { + if (start >= 0 && end > start + && fileCache.subList(end, oldSize) + .equals(newFileCache.subList(start, newSize))) { if (loadThread.isInterrupted()) { return null; } - return new DoChangeContents(null, 0, new Vector<>(fileCache.subList(start, end)), start, fid); + return new DoChangeContents(null, 0, + new Vector<>(fileCache.subList(start, end)), start, fid); } } - } - if (!fileCache.equals(newFileCache)) { - if (loadThread.isInterrupted()) { - cancelRunnables(); + if (!fileCache.equals(newFileCache)) { + if (loadThread.isInterrupted()) { + return null; + } + return new DoChangeContents(newFileCache, 0, fileCache, 0, fid); } - return new DoChangeContents(newFileCache, 0, fileCache, 0, fid); + return null; } - return null; } }); @@ -406,12 +409,6 @@ public DoChangeContents call() { SwingUtilities.invokeLater(runnable); } } - - private void cancelRunnables() { - if (runnable != null) { - runnable.cancel(); - } - } } @@ -520,13 +517,13 @@ public void run() { private final class DoChangeContents implements Runnable { private final List addFiles; private final List remFiles; - private boolean doFire = true; private final int fid; - private int addStart = 0; - private int remStart = 0; + private final int addStart; + private final int remStart; - DoChangeContents(List addFiles, int addStart, List remFiles, - int remStart, int fid) { + private DoChangeContents(List addFiles, int addStart, + List remFiles, int remStart, + int fid) { this.addFiles = addFiles; this.addStart = addStart; this.remFiles = remFiles; @@ -534,31 +531,32 @@ private final class DoChangeContents implements Runnable { this.fid = fid; } - synchronized void cancel() { - doFire = false; - } + @Override + public void run() { + if (fetchID.get() != fid) { + return; + } - public synchronized void run() { - if (fetchID.get() == fid && doFire) { - int remSize = (remFiles == null) ? 0 : remFiles.size(); - int addSize = (addFiles == null) ? 0 : addFiles.size(); - synchronized(fileCache) { - if (remSize > 0) { - fileCache.removeAll(remFiles); - } - if (addSize > 0) { - fileCache.addAll(addStart, addFiles); - } - files = null; - directories = null; + final int remSize = (remFiles == null) ? 0 : remFiles.size(); + final int addSize = (addFiles == null) ? 0 : addFiles.size(); + final int cacheSize; + synchronized (fileCache) { + if (remSize > 0) { + fileCache.removeAll(remFiles); } - if (remSize > 0 && addSize == 0) { - fireIntervalRemoved(BasicDirectoryModel.this, remStart, remStart + remSize - 1); - } else if (addSize > 0 && remSize == 0 && addStart + addSize <= fileCache.size()) { - fireIntervalAdded(BasicDirectoryModel.this, addStart, addStart + addSize - 1); - } else { - fireContentsChanged(); + if (addSize > 0) { + fileCache.addAll(addStart, addFiles); } + files = null; + directories = null; + cacheSize = fileCache.size(); + } + if (remSize > 0 && addSize == 0) { + fireIntervalRemoved(BasicDirectoryModel.this, remStart, remStart + remSize - 1); + } else if (addSize > 0 && remSize == 0 && addStart + addSize <= cacheSize) { + fireIntervalAdded(BasicDirectoryModel.this, addStart, addStart + addSize - 1); + } else { + fireContentsChanged(); } } } diff --git a/src/java.desktop/share/classes/javax/swing/text/html/CSS.java b/src/java.desktop/share/classes/javax/swing/text/html/CSS.java index 8a2b94dd9cf..01d20d5cbe3 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/CSS.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/CSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -841,6 +841,22 @@ Object getInternalCSSValue(CSS.Attribute key, String value) { return r != null ? r : conv.parseCssValue(key.getDefaultValue()); } + static Object mergeTextDecoration(String value) { + if (value.startsWith("none")) { + return null; + } + + boolean underline = value.contains("underline"); + boolean strikeThrough = value.contains("line-through"); + if (!underline && !strikeThrough) { + return null; + } + String newValue = underline && strikeThrough + ? "underline,line-through" + : (underline ? "underline" : "line-through"); + return new StringValue().parseCssValue(newValue); + } + /** * Maps from a StyleConstants to a CSS Attribute. */ diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java b/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java index 61463eb431f..ca5ca9f8aa7 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * 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,15 +25,43 @@ package javax.swing.text.html; import java.awt.font.TextAttribute; -import java.util.*; -import java.net.URL; +import java.io.IOException; +import java.io.StringReader; import java.net.MalformedURLException; -import java.io.*; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.undo.*; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Stack; +import java.util.Vector; + +import javax.swing.ButtonGroup; +import javax.swing.DefaultButtonModel; +import javax.swing.DefaultComboBoxModel; +import javax.swing.DefaultListModel; +import javax.swing.JToggleButton; +import javax.swing.ListSelectionModel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.EventListenerList; +import javax.swing.event.UndoableEditEvent; +import javax.swing.text.AbstractDocument; +import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultEditorKit; +import javax.swing.text.DefaultStyledDocument; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.ElementIterator; +import javax.swing.text.GapContent; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.PlainDocument; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.undo.UndoableEdit; + import sun.swing.SwingUtilities2; + import static sun.swing.SwingUtilities2.IMPLIED_CR; /** @@ -2471,9 +2499,9 @@ public HTMLReader(int offset, int popDepth, int pushDepth, tagMap.put(HTML.Tag.SCRIPT, ha); tagMap.put(HTML.Tag.SELECT, fa); tagMap.put(HTML.Tag.SMALL, ca); - tagMap.put(HTML.Tag.SPAN, ca); + tagMap.put(HTML.Tag.SPAN, new ConvertSpanAction()); tagMap.put(HTML.Tag.STRIKE, conv); - tagMap.put(HTML.Tag.S, ca); + tagMap.put(HTML.Tag.S, conv); tagMap.put(HTML.Tag.STRONG, ca); tagMap.put(HTML.Tag.STYLE, new StyleAction()); tagMap.put(HTML.Tag.SUB, conv); @@ -3395,11 +3423,43 @@ public void start(HTML.Tag t, MutableAttributeSet attr) { if (styleAttributes != null) { charAttr.addAttributes(styleAttributes); } + + convertAttributes(t, attr); } public void end(HTML.Tag t) { popCharacterStyle(); } + + /** + * Converts HTML tags to CSS attributes. + * @param t the current HTML tag + * @param attr the attributes of the HTML tag + */ + void convertAttributes(HTML.Tag t, MutableAttributeSet attr) { + } + } + + final class ConvertSpanAction extends CharacterAction { + @Override + void convertAttributes(HTML.Tag t, MutableAttributeSet attr) { + Object newDecoration = attr.getAttribute(CSS.Attribute.TEXT_DECORATION); + Object previousDecoration = + charAttrStack.peek() + .getAttribute(CSS.Attribute.TEXT_DECORATION); + + if (newDecoration != null + && !"none".equals(newDecoration.toString()) + && previousDecoration != null + && !"none".equals(previousDecoration.toString())) { + StyleSheet sheet = getStyleSheet(); + sheet.addCSSAttribute(charAttr, + CSS.Attribute.TEXT_DECORATION, + CSS.mergeTextDecoration(newDecoration + "," + + previousDecoration) + .toString()); + } + } } /** @@ -3407,35 +3467,9 @@ public void end(HTML.Tag t) { * mappings that have a corresponding StyleConstants * and CSS mapping. The conversion is to CSS attributes. */ - class ConvertAction extends TagAction { - - public void start(HTML.Tag t, MutableAttributeSet attr) { - pushCharacterStyle(); - if (!foundInsertTag) { - // Note that the third argument should really be based off - // inParagraph and impliedP. If we're wrong (that is - // insertTagDepthDelta shouldn't be changed), we'll end up - // removing an extra EndSpec, which won't matter anyway. - boolean insert = canInsertTag(t, attr, false); - if (foundInsertTag) { - if (!inParagraph) { - inParagraph = impliedP = true; - } - } - if (!insert) { - return; - } - } - if (attr.isDefined(IMPLIED)) { - attr.removeAttribute(IMPLIED); - } - if (styleAttributes != null) { - charAttr.addAttributes(styleAttributes); - } - // We also need to add attr, otherwise we lose custom - // attributes, including class/id for style lookups, and - // further confuse style lookup (doesn't have tag). - charAttr.addAttribute(t, attr.copyAttributes()); + final class ConvertAction extends CharacterAction { + @Override + void convertAttributes(HTML.Tag t, MutableAttributeSet attr) { StyleSheet sheet = getStyleSheet(); if (t == HTML.Tag.B) { sheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_WEIGHT, "bold"); @@ -3446,7 +3480,7 @@ public void start(HTML.Tag t, MutableAttributeSet attr) { String value = "underline"; value = (v != null) ? value + "," + v.toString() : value; sheet.addCSSAttribute(charAttr, CSS.Attribute.TEXT_DECORATION, value); - } else if (t == HTML.Tag.STRIKE) { + } else if (t == HTML.Tag.STRIKE || t == HTML.Tag.S) { Object v = charAttr.getAttribute(CSS.Attribute.TEXT_DECORATION); String value = "line-through"; value = (v != null) ? value + "," + v.toString() : value; @@ -3476,11 +3510,6 @@ public void start(HTML.Tag t, MutableAttributeSet attr) { } } } - - public void end(HTML.Tag t) { - popCharacterStyle(); - } - } class AnchorAction extends CharacterAction { diff --git a/src/java.desktop/share/classes/javax/swing/text/html/MuxingAttributeSet.java b/src/java.desktop/share/classes/javax/swing/text/html/MuxingAttributeSet.java index 9d423dcded9..4d6ae0e0ae1 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/MuxingAttributeSet.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/MuxingAttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,16 @@ */ package javax.swing.text.html; -import javax.swing.text.*; import java.io.Serializable; -import java.util.*; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.stream.Collectors; + +import javax.swing.text.AttributeSet; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.SimpleAttributeSet; /** * An implementation of AttributeSet that can multiplex @@ -196,15 +203,24 @@ public AttributeSet copyAttributes() { * @see AttributeSet#getAttribute */ public Object getAttribute(Object key) { - AttributeSet[] as = getAttributes(); - int n = as.length; - for (int i = 0; i < n; i++) { - Object o = as[i].getAttribute(key); - if (o != null) { - return o; + final AttributeSet[] as = getAttributes(); + final int n = as.length; + if (key != CSS.Attribute.TEXT_DECORATION) { + for (int i = 0; i < n; i++) { + Object o = as[i].getAttribute(key); + if (o != null) { + return o; + } } + return null; } - return null; + + String values = Arrays.stream(as) + .map(a -> a.getAttribute(key)) + .filter(Objects::nonNull) + .map(Object::toString) + .collect(Collectors.joining(",")); + return CSS.mergeTextDecoration(values); } /** diff --git a/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java b/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java index fd3c75829e8..0790060f5e8 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * 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,17 +24,53 @@ */ package javax.swing.text.html; -import sun.swing.SwingUtilities2; -import java.util.*; -import java.awt.*; -import java.io.*; -import java.net.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.Serializable; +import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.EmptyStackException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.Vector; + import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.UIManager; -import javax.swing.border.*; +import javax.swing.border.BevelBorder; +import javax.swing.border.Border; import javax.swing.event.ChangeListener; -import javax.swing.text.*; +import javax.swing.text.AttributeSet; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.Style; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyleContext; +import javax.swing.text.StyledDocument; +import javax.swing.text.View; + +import sun.swing.SwingUtilities2; /** * Support for defining the visual characteristics of @@ -2817,10 +2853,31 @@ public Object getAttribute(Object key) { return doGetAttribute(key); } + /** + * Merges the current value of the 'text-decoration' property + * with the value from parent. + */ + private Object getTextDecoration(Object value) { + AttributeSet parent = getResolveParent(); + if (parent == null) { + return value; + } + + Object parentValue = parent.getAttribute(CSS.Attribute.TEXT_DECORATION); + return parentValue == null + ? value + : CSS.mergeTextDecoration(value + "," + parentValue); + } + Object doGetAttribute(Object key) { Object retValue = super.getAttribute(key); if (retValue != null) { - return retValue; + if (key != CSS.Attribute.TEXT_DECORATION) { + return retValue; + } else { + // Merge current value with parent + return getTextDecoration(retValue); + } } if (key == CSS.Attribute.FONT_SIZE) { diff --git a/src/java.desktop/share/classes/sun/font/FileFontStrike.java b/src/java.desktop/share/classes/sun/font/FileFontStrike.java index ea2a1608f2d..bf98b8ca578 100644 --- a/src/java.desktop/share/classes/sun/font/FileFontStrike.java +++ b/src/java.desktop/share/classes/sun/font/FileFontStrike.java @@ -37,6 +37,7 @@ import java.awt.geom.Rectangle2D; import java.util.concurrent.ConcurrentHashMap; import static sun.awt.SunHints.*; +import sun.java2d.pipe.OutlineTextRenderer; public class FileFontStrike extends PhysicalStrike { @@ -107,6 +108,7 @@ public class FileFontStrike extends PhysicalStrike { boolean useNatives; NativeStrike[] nativeStrikes; + static final int MAX_IMAGE_SIZE = OutlineTextRenderer.THRESHHOLD; /* Used only for communication to native layer */ private int intPtSize; @@ -697,6 +699,20 @@ float getCodePointAdvance(int cp) { void getGlyphImageBounds(int glyphCode, Point2D.Float pt, Rectangle result) { + if (intPtSize > MAX_IMAGE_SIZE) { + Rectangle.Float obds = getGlyphOutlineBounds(glyphCode); + if (obds.isEmpty()) { + Rectangle bds = getGlyphOutline(glyphCode, pt.x, pt.y).getBounds(); + result.setBounds(bds); + } else { + result.x = (int)Math.floor(pt.x + obds.getX() + 0.5f); + result.y = (int)Math.floor(pt.y + obds.getY() + 0.5f); + result.width = (int)Math.floor(obds.getWidth() + 0.5f); + result.height = (int)Math.floor(obds.getHeight() + 0.5f); + } + return; + } + long ptr = getGlyphImagePtr(glyphCode); float topLeftX, topLeftY; diff --git a/src/java.desktop/share/classes/sun/font/Type1Font.java b/src/java.desktop/share/classes/sun/font/Type1Font.java index 1cd046eadd1..cc36c193de0 100644 --- a/src/java.desktop/share/classes/sun/font/Type1Font.java +++ b/src/java.desktop/share/classes/sun/font/Type1Font.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -187,7 +187,9 @@ public Type1Font(String platname, Object nativeNames, boolean createdCopy) private synchronized ByteBuffer getBuffer() throws FontFormatException { ByteBuffer bbuf = bufferRef.get(); if (bbuf == null) { - //System.out.println("open T1 " + platName); + if (FontUtilities.isLogging()) { + FontUtilities.logInfo("open Type 1 font: " + platName); + } try { @SuppressWarnings("removal") RandomAccessFile raf = (RandomAccessFile) @@ -229,6 +231,9 @@ protected void close() { void readFile(ByteBuffer buffer) { RandomAccessFile raf = null; FileChannel fc; + if (FontUtilities.isLogging()) { + FontUtilities.logInfo("open Type 1 font: " + platName); + } try { raf = (RandomAccessFile) java.security.AccessController.doPrivileged( diff --git a/src/java.desktop/share/classes/sun/swing/FilePane.java b/src/java.desktop/share/classes/sun/swing/FilePane.java index 1c8baf8861e..978d8ddb11a 100644 --- a/src/java.desktop/share/classes/sun/swing/FilePane.java +++ b/src/java.desktop/share/classes/sun/swing/FilePane.java @@ -1317,13 +1317,6 @@ public void tableChanged(TableModelEvent e) { detailsTable.addFocusListener(repaintListener); } - // TAB/SHIFT-TAB should transfer focus and ENTER should select an item. - // We don't want them to navigate within the table - ActionMap am = SwingUtilities.getUIActionMap(detailsTable); - am.remove("selectNextRowCell"); - am.remove("selectPreviousRowCell"); - am.remove("selectNextColumnCell"); - am.remove("selectPreviousColumnCell"); detailsTable.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null); detailsTable.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, diff --git a/src/java.desktop/share/legal/giflib.md b/src/java.desktop/share/legal/giflib.md index 0be4fb8226e..8b8fde8706d 100644 --- a/src/java.desktop/share/legal/giflib.md +++ b/src/java.desktop/share/legal/giflib.md @@ -1,4 +1,4 @@ -## GIFLIB v5.2.1 +## GIFLIB v5.2.2 ### GIFLIB License ``` @@ -24,7 +24,27 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -https://sourceforge.net/p/giflib/code/ci/master/tree/openbsd-reallocarray.c +tree/README -Copyright (c) 2008 Otto Moerbeek +== Authors == + +Gershon Elber +original giflib code + +Toshio Kuratomi +uncompressed gif writing code +former maintainer + +Eric Raymond +current as well as long time former maintainer of giflib code + +There have been many other contributors; see the attributions in the +version-control history to learn more. + + +tree/openbsd-reallocarray.c + +Copyright (C) 2008 Otto Moerbeek SPDX-License-Identifier: MIT + +``` diff --git a/src/java.desktop/share/legal/libpng.md b/src/java.desktop/share/legal/libpng.md index f420ccd94ed..cbffed81332 100644 --- a/src/java.desktop/share/legal/libpng.md +++ b/src/java.desktop/share/legal/libpng.md @@ -1,4 +1,4 @@ -## libpng v1.6.40 +## libpng v1.6.43 ### libpng License
@@ -9,11 +9,11 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
 PNG Reference Library License version 2
 ---------------------------------------
 
-Copyright (c) 1995-2023 The PNG Reference Library Authors.
-Copyright (c) 2018-2023 Cosmin Truta
-Copyright (c) 1998-2018 Glenn Randers-Pehrson
-Copyright (c) 1996-1997 Andreas Dilger
-Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
+Copyright (C) 1995-2024 The PNG Reference Library Authors.
+Copyright (C) 2018-2024 Cosmin Truta
+Copyright (C) 1998-2018 Glenn Randers-Pehrson
+Copyright (C) 1996-1997 Andreas Dilger
+Copyright (C) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
 
 The software is supplied "as is", without warranty of any kind,
 express or implied, including, without limitation, the warranties
@@ -157,7 +157,9 @@ PNG REFERENCE LIBRARY AUTHORS
 This is the list of PNG Reference Library ("libpng") Contributing
 Authors, for copyright and licensing purposes.
 
+ * Adam Richter
  * Andreas Dilger
+ * Chris Blume
  * Cosmin Truta
  * Dave Martindale
  * Eric S. Raymond
@@ -186,21 +188,28 @@ Authors, for copyright and licensing purposes.
  * Vadim Barkov
  * Willem van Schaik
  * Zhijie Liang
+ * Apple Inc.
+    - Zixu Wang (王子旭)
  * Arm Holdings
-   - Richard Townsend
+    - Richard Townsend
  * Google Inc.
-   - Dan Field
-   - Leon Scroggins III
-   - Matt Sarett
-   - Mike Klein
-   - Sami Boukortt
-   - Wan-Teh Chang
+    - Dan Field
+    - Leon Scroggins III
+    - Matt Sarett
+    - Mike Klein
+    - Sami Boukortt
+    - Wan-Teh Chang
+ * Loongson Technology Corporation Ltd.
+    - GuXiWei (顾希伟)
+    - JinBo (金波)
+    - ZhangLixia (张利霞)
 
 The build projects, the build scripts, the test scripts, and other
-files in the "ci", "projects", "scripts" and "tests" directories, have
+files in the "projects", "scripts" and "tests" directories, have
 other copyright owners, but are released under the libpng license.
 
-Some files in the "contrib" directory, and some tools-generated files
-that are distributed with libpng, have other copyright owners, and are
-released under other open source licenses.
+Some files in the "ci" and "contrib" directories, as well as some
+of the tools-generated files that are distributed with libpng, have
+other copyright owners, and are released under other open source
+licenses.
 ```
diff --git a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c
index 21ac280f0fb..f9ebacad66b 100644
--- a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c
+++ b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c
@@ -504,6 +504,8 @@ static double euclidianDistance(double a, double b) {
     return sqrt(a*a+b*b);
 }
 
+#define TOO_LARGE(a, b) (abs((int)(a / b)) > 32766)
+
 JNIEXPORT jlong JNICALL
 Java_sun_font_FreetypeFontScaler_createScalerContextNative(
         JNIEnv *env, jobject scaler, jlong pScaler, jdoubleArray matrix,
@@ -515,6 +517,7 @@ Java_sun_font_FreetypeFontScaler_createScalerContextNative(
              (FTScalerInfo*) jlong_to_ptr(pScaler);
 
     if (context == NULL) {
+        free(context);
         invalidateJavaScaler(env, scaler, NULL);
         return (jlong) 0;
     }
@@ -524,7 +527,18 @@ Java_sun_font_FreetypeFontScaler_createScalerContextNative(
         //text can not be smaller than 1 point
         ptsz = 1.0;
     }
+    if (ptsz > 16384) {
+        ptsz = 16384;    // far enough from 32767
+        fm = TEXT_FM_ON; // avoids calculations which might overflow
+    }
     context->ptsz = (int)(ptsz * 64);
+    if (TOO_LARGE(dmat[0], ptsz) || TOO_LARGE(dmat[1], ptsz) ||
+        TOO_LARGE(dmat[2], ptsz) || TOO_LARGE(dmat[3], ptsz))
+    {
+        free(context);
+        return (jlong)0;
+    }
+
     context->transform.xx =  FloatToFTFixed((float)(dmat[0]/ptsz));
     context->transform.yx = -FloatToFTFixed((float)(dmat[1]/ptsz));
     context->transform.xy = -FloatToFTFixed((float)(dmat[2]/ptsz));
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageScanPoly.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageScanPoly.c
index a643b9c111c..a6f4cfdd36e 100644
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageScanPoly.c
+++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageScanPoly.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -289,13 +289,15 @@ mlib_status mlib_AffineEdges(mlib_affine_param *param,
     mlib_d64 dX1 = coords[(topIdx - i) & 0x3][0];
     mlib_d64 dY2 = coords[(topIdx - i - 1) & 0x3][1];
     mlib_d64 dX2 = coords[(topIdx - i - 1) & 0x3][0];
-    mlib_d64 x = dX1, slope = (dX2 - dX1) / (dY2 - dY1);
+    mlib_d64 x = dX1, slope;
     mlib_s32 y1;
     mlib_s32 y2;
 
     if (dY1 == dY2)
       continue;
 
+    slope = (dX2 - dX1) / (dY2 - dY1);
+
     if (!(IS_FINITE(slope))) {
       continue;
     }
@@ -330,13 +332,15 @@ mlib_status mlib_AffineEdges(mlib_affine_param *param,
     mlib_d64 dX1 = coords[(topIdx + i) & 0x3][0];
     mlib_d64 dY2 = coords[(topIdx + i + 1) & 0x3][1];
     mlib_d64 dX2 = coords[(topIdx + i + 1) & 0x3][0];
-    mlib_d64 x = dX1, slope = (dX2 - dX1) / (dY2 - dY1);
+    mlib_d64 x = dX1, slope;
     mlib_s32 y1;
     mlib_s32 y2;
 
     if (dY1 == dY2)
       continue;
 
+    slope = (dX2 - dX1) / (dY2 - dY1);
+
     if (!(IS_FINITE(slope))) {
       continue;
     }
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/dgif_lib.c b/src/java.desktop/share/native/libsplashscreen/giflib/dgif_lib.c
index 6ddfb46060d..0b2860b4b50 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/dgif_lib.c
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/dgif_lib.c
@@ -34,11 +34,11 @@ SPDX-License-Identifier: MIT
 
 *****************************************************************************/
 
-#include 
+#include 
 #include 
 #include 
-#include 
 #include 
+#include 
 #include 
 
 #ifdef _WIN32
@@ -55,18 +55,19 @@ SPDX-License-Identifier: MIT
 
 /* avoid extra function call in case we use fread (TVT) */
 static int InternalRead(GifFileType *gif, GifByteType *buf, int len) {
-    //fprintf(stderr, "### Read: %d\n", len);
-    return
-    (((GifFilePrivateType*)gif->Private)->Read ?
-     ((GifFilePrivateType*)gif->Private)->Read(gif,buf,len) :
-     fread(buf,1,len,((GifFilePrivateType*)gif->Private)->File));
+    // fprintf(stderr, "### Read: %d\n", len);
+    return (((GifFilePrivateType *)gif->Private)->Read
+                ? ((GifFilePrivateType *)gif->Private)->Read(gif, buf, len)
+                : fread(buf, 1, len,
+                        ((GifFilePrivateType *)gif->Private)->File));
 }
 
 static int DGifGetWord(GifFileType *GifFile, GifWord *Word);
 static int DGifSetupDecompress(GifFileType *GifFile);
 static int DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,
                               int LineLen);
-static int DGifGetPrefixChar(GifPrefixType *Prefix, int Code, int ClearCode);
+static int DGifGetPrefixChar(const GifPrefixType *Prefix, int Code,
+                             int ClearCode);
 static int DGifDecompressInput(GifFileType *GifFile, int *Code);
 static int DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf,
                              GifByteType *NextByte);
@@ -76,15 +77,14 @@ static int DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf,
  Returns dynamically allocated GifFileType pointer which serves as the GIF
  info record.
 ******************************************************************************/
-GifFileType *
-DGifOpenFileName(const char *FileName, int *Error)
-{
+GifFileType *DGifOpenFileName(const char *FileName, int *Error) {
     int FileHandle;
     GifFileType *GifFile;
 
     if ((FileHandle = open(FileName, O_RDONLY)) == -1) {
-        if (Error != NULL)
+        if (Error != NULL) {
             *Error = D_GIF_ERR_OPEN_FAILED;
+        }
         return NULL;
     }
 
@@ -97,9 +97,7 @@ DGifOpenFileName(const char *FileName, int *Error)
  Returns dynamically allocated GifFileType pointer which serves as the GIF
  info record.
 ******************************************************************************/
-GifFileType *
-DGifOpenFileHandle(int FileHandle, int *Error)
-{
+GifFileType *DGifOpenFileHandle(int FileHandle, int *Error) {
     char Buf[GIF_STAMP_LEN + 1];
     GifFileType *GifFile;
     GifFilePrivateType *Private;
@@ -107,13 +105,14 @@ DGifOpenFileHandle(int FileHandle, int *Error)
 
     GifFile = (GifFileType *)malloc(sizeof(GifFileType));
     if (GifFile == NULL) {
-        if (Error != NULL)
+        if (Error != NULL) {
             *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+        }
         (void)close(FileHandle);
         return NULL;
     }
 
-    /*@i1@*/memset(GifFile, '\0', sizeof(GifFileType));
+    /*@i1@*/ memset(GifFile, '\0', sizeof(GifFileType));
 
     /* Belt and suspenders, in case the null pointer isn't zero */
     GifFile->SavedImages = NULL;
@@ -121,35 +120,38 @@ DGifOpenFileHandle(int FileHandle, int *Error)
 
     Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));
     if (Private == NULL) {
-        if (Error != NULL)
+        if (Error != NULL) {
             *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+        }
         (void)close(FileHandle);
         free((char *)GifFile);
         return NULL;
     }
 
-    /*@i1@*/memset(Private, '\0', sizeof(GifFilePrivateType));
+    /*@i1@*/ memset(Private, '\0', sizeof(GifFilePrivateType));
 
 #ifdef _WIN32
-    _setmode(FileHandle, O_BINARY);    /* Make sure it is in binary mode. */
-#endif /* _WIN32 */
+    _setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode. */
+#endif                                  /* _WIN32 */
 
-    f = fdopen(FileHandle, "rb");    /* Make it into a stream: */
+    f = fdopen(FileHandle, "rb"); /* Make it into a stream: */
 
     /*@-mustfreeonly@*/
     GifFile->Private = (void *)Private;
     Private->FileHandle = FileHandle;
     Private->File = f;
     Private->FileState = FILE_STATE_READ;
-    Private->Read = NULL;        /* don't use alternate input method (TVT) */
-    GifFile->UserData = NULL;    /* TVT */
+    Private->Read = NULL;     /* don't use alternate input method (TVT) */
+    GifFile->UserData = NULL; /* TVT */
     /*@=mustfreeonly@*/
 
     /* Let's see if this is a GIF file: */
     /* coverity[check_return] */
-    if (InternalRead(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) != GIF_STAMP_LEN) {
-        if (Error != NULL)
+    if (InternalRead(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) !=
+        GIF_STAMP_LEN) {
+        if (Error != NULL) {
             *Error = D_GIF_ERR_READ_FAILED;
+        }
         (void)fclose(f);
         free((char *)Private);
         free((char *)GifFile);
@@ -159,8 +161,9 @@ DGifOpenFileHandle(int FileHandle, int *Error)
     /* Check for GIF prefix at start of file */
     Buf[GIF_STAMP_LEN] = 0;
     if (strncmp(GIF_STAMP, Buf, GIF_VERSION_POS) != 0) {
-        if (Error != NULL)
+        if (Error != NULL) {
             *Error = D_GIF_ERR_NOT_GIF_FILE;
+        }
         (void)fclose(f);
         free((char *)Private);
         free((char *)GifFile);
@@ -177,7 +180,7 @@ DGifOpenFileHandle(int FileHandle, int *Error)
     GifFile->Error = 0;
 
     /* What version of GIF? */
-    Private->gif89 = (Buf[GIF_VERSION_POS] == '9');
+    Private->gif89 = (Buf[GIF_VERSION_POS + 1] == '9');
 
     return GifFile;
 }
@@ -185,17 +188,16 @@ DGifOpenFileHandle(int FileHandle, int *Error)
 /******************************************************************************
  GifFileType constructor with user supplied input function (TVT)
 ******************************************************************************/
-GifFileType *
-DGifOpen(void *userData, InputFunc readFunc, int *Error)
-{
+GifFileType *DGifOpen(void *userData, InputFunc readFunc, int *Error) {
     char Buf[GIF_STAMP_LEN + 1];
     GifFileType *GifFile;
     GifFilePrivateType *Private;
 
     GifFile = (GifFileType *)malloc(sizeof(GifFileType));
     if (GifFile == NULL) {
-        if (Error != NULL)
+        if (Error != NULL) {
             *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+        }
         return NULL;
     }
 
@@ -207,26 +209,29 @@ DGifOpen(void *userData, InputFunc readFunc, int *Error)
 
     Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));
     if (!Private) {
-        if (Error != NULL)
+        if (Error != NULL) {
             *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
+        }
         free((char *)GifFile);
         return NULL;
     }
-    /*@i1@*/memset(Private, '\0', sizeof(GifFilePrivateType));
+    /*@i1@*/ memset(Private, '\0', sizeof(GifFilePrivateType));
 
     GifFile->Private = (void *)Private;
     Private->FileHandle = 0;
     Private->File = NULL;
     Private->FileState = FILE_STATE_READ;
 
-    Private->Read = readFunc;    /* TVT */
-    GifFile->UserData = userData;    /* TVT */
+    Private->Read = readFunc;     /* TVT */
+    GifFile->UserData = userData; /* TVT */
 
     /* Lets see if this is a GIF file: */
     /* coverity[check_return] */
-    if (InternalRead(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) != GIF_STAMP_LEN) {
-        if (Error != NULL)
+    if (InternalRead(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) !=
+        GIF_STAMP_LEN) {
+        if (Error != NULL) {
             *Error = D_GIF_ERR_READ_FAILED;
+        }
         free((char *)Private);
         free((char *)GifFile);
         return NULL;
@@ -235,8 +240,9 @@ DGifOpen(void *userData, InputFunc readFunc, int *Error)
     /* Check for GIF prefix at start of file */
     Buf[GIF_STAMP_LEN] = '\0';
     if (strncmp(GIF_STAMP, Buf, GIF_VERSION_POS) != 0) {
-        if (Error != NULL)
+        if (Error != NULL) {
             *Error = D_GIF_ERR_NOT_GIF_FILE;
+        }
         free((char *)Private);
         free((char *)GifFile);
         return NULL;
@@ -245,15 +251,16 @@ DGifOpen(void *userData, InputFunc readFunc, int *Error)
     if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {
         free((char *)Private);
         free((char *)GifFile);
-        if (Error != NULL)
+        if (Error != NULL) {
             *Error = D_GIF_ERR_NO_SCRN_DSCR;
+        }
         return NULL;
     }
 
     GifFile->Error = 0;
 
     /* What version of GIF? */
-    Private->gif89 = (Buf[GIF_VERSION_POS] == '9');
+    Private->gif89 = (Buf[GIF_VERSION_POS + 1] == '9');
 
     return GifFile;
 }
@@ -262,9 +269,7 @@ DGifOpen(void *userData, InputFunc readFunc, int *Error)
  This routine should be called before any other DGif calls. Note that
  this routine is called automatically from DGif file open routines.
 ******************************************************************************/
-int
-DGifGetScreenDesc(GifFileType *GifFile)
-{
+int DGifGetScreenDesc(GifFileType *GifFile) {
     int BitsPerPixel;
     bool SortFlag;
     GifByteType Buf[3];
@@ -278,8 +283,9 @@ DGifGetScreenDesc(GifFileType *GifFile)
 
     /* Put the screen descriptor into the file: */
     if (DGifGetWord(GifFile, &GifFile->SWidth) == GIF_ERROR ||
-        DGifGetWord(GifFile, &GifFile->SHeight) == GIF_ERROR)
+        DGifGetWord(GifFile, &GifFile->SHeight) == GIF_ERROR) {
         return GIF_ERROR;
+    }
 
     if (InternalRead(GifFile, Buf, 3) != 3) {
         GifFile->Error = D_GIF_ERR_READ_FAILED;
@@ -292,7 +298,7 @@ DGifGetScreenDesc(GifFileType *GifFile)
     BitsPerPixel = (Buf[0] & 0x07) + 1;
     GifFile->SBackGroundColor = Buf[1];
     GifFile->AspectByte = Buf[2];
-    if (Buf[0] & 0x80) {    /* Do we have global color map? */
+    if (Buf[0] & 0x80) { /* Do we have global color map? */
         int i;
 
         GifFile->SColorMap = GifMakeMapObject(1 << BitsPerPixel, NULL);
@@ -327,23 +333,20 @@ DGifGetScreenDesc(GifFileType *GifFile)
     return GIF_OK;
 }
 
-const char *
-DGifGetGifVersion(GifFileType *GifFile)
-{
-    GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+const char *DGifGetGifVersion(GifFileType *GifFile) {
+    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    if (Private->gif89)
+    if (Private->gif89) {
         return GIF89_STAMP;
-    else
+    } else {
         return GIF87_STAMP;
+    }
 }
 
 /******************************************************************************
  This routine should be called before any attempt to read an image.
 ******************************************************************************/
-int
-DGifGetRecordType(GifFileType *GifFile, GifRecordType* Type)
-{
+int DGifGetRecordType(GifFileType *GifFile, GifRecordType *Type) {
     GifByteType Buf;
     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
@@ -359,29 +362,27 @@ DGifGetRecordType(GifFileType *GifFile, GifRecordType* Type)
         return GIF_ERROR;
     }
 
-    //fprintf(stderr, "### DGifGetRecordType: %02x\n", Buf);
+    // fprintf(stderr, "### DGifGetRecordType: %02x\n", Buf);
     switch (Buf) {
-      case DESCRIPTOR_INTRODUCER:
-          *Type = IMAGE_DESC_RECORD_TYPE;
-          break;
-      case EXTENSION_INTRODUCER:
-          *Type = EXTENSION_RECORD_TYPE;
-          break;
-      case TERMINATOR_INTRODUCER:
-          *Type = TERMINATE_RECORD_TYPE;
-          break;
-      default:
-          *Type = UNDEFINED_RECORD_TYPE;
-          GifFile->Error = D_GIF_ERR_WRONG_RECORD;
-          return GIF_ERROR;
+    case DESCRIPTOR_INTRODUCER:
+        *Type = IMAGE_DESC_RECORD_TYPE;
+        break;
+    case EXTENSION_INTRODUCER:
+        *Type = EXTENSION_RECORD_TYPE;
+        break;
+    case TERMINATOR_INTRODUCER:
+        *Type = TERMINATE_RECORD_TYPE;
+        break;
+    default:
+        *Type = UNDEFINED_RECORD_TYPE;
+        GifFile->Error = D_GIF_ERR_WRONG_RECORD;
+        return GIF_ERROR;
     }
 
     return GIF_OK;
 }
 
-int
-DGifGetImageHeader(GifFileType *GifFile)
-{
+int DGifGetImageHeader(GifFileType *GifFile) {
     unsigned int BitsPerPixel;
     GifByteType Buf[3];
     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
@@ -395,8 +396,9 @@ DGifGetImageHeader(GifFileType *GifFile)
     if (DGifGetWord(GifFile, &GifFile->Image.Left) == GIF_ERROR ||
         DGifGetWord(GifFile, &GifFile->Image.Top) == GIF_ERROR ||
         DGifGetWord(GifFile, &GifFile->Image.Width) == GIF_ERROR ||
-        DGifGetWord(GifFile, &GifFile->Image.Height) == GIF_ERROR)
+        DGifGetWord(GifFile, &GifFile->Image.Height) == GIF_ERROR) {
         return GIF_ERROR;
+    }
     if (InternalRead(GifFile, Buf, 1) != 1) {
         GifFile->Error = D_GIF_ERR_READ_FAILED;
         GifFreeMapObject(GifFile->Image.ColorMap);
@@ -415,7 +417,8 @@ DGifGetImageHeader(GifFileType *GifFile)
     if (Buf[0] & 0x80) {
         unsigned int i;
 
-        GifFile->Image.ColorMap = GifMakeMapObject(1 << BitsPerPixel, NULL);
+        GifFile->Image.ColorMap =
+            GifMakeMapObject(1 << BitsPerPixel, NULL);
         if (GifFile->Image.ColorMap == NULL) {
             GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
             return GIF_ERROR;
@@ -436,8 +439,8 @@ DGifGetImageHeader(GifFileType *GifFile)
         }
     }
 
-    Private->PixelCount = (long)GifFile->Image.Width *
-       (long)GifFile->Image.Height;
+    Private->PixelCount =
+        (long)GifFile->Image.Width * (long)GifFile->Image.Height;
 
     /* Reset decompress algorithm parameters. */
     return DGifSetupDecompress(GifFile);
@@ -447,9 +450,7 @@ DGifGetImageHeader(GifFileType *GifFile)
  This routine should be called before any attempt to read an image.
  Note it is assumed the Image desc. header has been read.
 ******************************************************************************/
-int
-DGifGetImageDesc(GifFileType *GifFile)
-{
+int DGifGetImageDesc(GifFileType *GifFile) {
     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
     SavedImage *sp;
 
@@ -464,9 +465,9 @@ DGifGetImageDesc(GifFileType *GifFile)
     }
 
     if (GifFile->SavedImages) {
-        SavedImage* new_saved_images =
-            (SavedImage *)reallocarray(GifFile->SavedImages,
-                            (GifFile->ImageCount + 1), sizeof(SavedImage));
+        SavedImage *new_saved_images = (SavedImage *)reallocarray(
+            GifFile->SavedImages, (GifFile->ImageCount + 1),
+            sizeof(SavedImage));
         if (new_saved_images == NULL) {
             GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
             return GIF_ERROR;
@@ -474,7 +475,7 @@ DGifGetImageDesc(GifFileType *GifFile)
         GifFile->SavedImages = new_saved_images;
     } else {
         if ((GifFile->SavedImages =
-             (SavedImage *) malloc(sizeof(SavedImage))) == NULL) {
+                 (SavedImage *)malloc(sizeof(SavedImage))) == NULL) {
             GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
             return GIF_ERROR;
         }
@@ -483,9 +484,9 @@ DGifGetImageDesc(GifFileType *GifFile)
     sp = &GifFile->SavedImages[GifFile->ImageCount];
     memcpy(&sp->ImageDesc, &GifFile->Image, sizeof(GifImageDesc));
     if (GifFile->Image.ColorMap != NULL) {
-        sp->ImageDesc.ColorMap = GifMakeMapObject(
-                                 GifFile->Image.ColorMap->ColorCount,
-                                 GifFile->Image.ColorMap->Colors);
+        sp->ImageDesc.ColorMap =
+            GifMakeMapObject(GifFile->Image.ColorMap->ColorCount,
+                             GifFile->Image.ColorMap->Colors);
         if (sp->ImageDesc.ColorMap == NULL) {
             GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
             return GIF_ERROR;
@@ -493,7 +494,7 @@ DGifGetImageDesc(GifFileType *GifFile)
     }
     sp->RasterBits = (unsigned char *)NULL;
     sp->ExtensionBlockCount = 0;
-    sp->ExtensionBlocks = (ExtensionBlock *) NULL;
+    sp->ExtensionBlocks = (ExtensionBlock *)NULL;
 
     GifFile->ImageCount++;
 
@@ -503,11 +504,9 @@ DGifGetImageDesc(GifFileType *GifFile)
 /******************************************************************************
  Get one full scanned line (Line) of length LineLen from GIF file.
 ******************************************************************************/
-int
-DGifGetLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
-{
+int DGifGetLine(GifFileType *GifFile, GifPixelType *Line, int LineLen) {
     GifByteType *Dummy;
-    GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
     if (!IS_READABLE(Private)) {
         /* This file was NOT open for reading: */
@@ -515,8 +514,9 @@ DGifGetLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
         return GIF_ERROR;
     }
 
-    if (!LineLen)
+    if (!LineLen) {
         LineLen = GifFile->Image.Width;
+    }
 
     if ((Private->PixelCount -= LineLen) > 0xffff0000UL) {
         GifFile->Error = D_GIF_ERR_DATA_TOO_BIG;
@@ -525,56 +525,59 @@ DGifGetLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
 
     if (DGifDecompressLine(GifFile, Line, LineLen) == GIF_OK) {
         if (Private->PixelCount == 0) {
-            /* We probably won't be called any more, so let's clean up
-             * everything before we return: need to flush out all the
-             * rest of image until an empty block (size 0)
+            /* We probably won't be called any more, so let's clean
+             * up everything before we return: need to flush out all
+             * the rest of image until an empty block (size 0)
              * detected. We use GetCodeNext.
              */
-            do
-                if (DGifGetCodeNext(GifFile, &Dummy) == GIF_ERROR)
+            do {
+                if (DGifGetCodeNext(GifFile, &Dummy) ==
+                    GIF_ERROR) {
                     return GIF_ERROR;
-            while (Dummy != NULL) ;
+                }
+            } while (Dummy != NULL);
         }
         return GIF_OK;
-    } else
+    } else {
         return GIF_ERROR;
+    }
 }
 
 /******************************************************************************
  Put one pixel (Pixel) into GIF file.
 ******************************************************************************/
-int
-DGifGetPixel(GifFileType *GifFile, GifPixelType Pixel)
-{
+int DGifGetPixel(GifFileType *GifFile, GifPixelType Pixel) {
     GifByteType *Dummy;
-    GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
     if (!IS_READABLE(Private)) {
         /* This file was NOT open for reading: */
         GifFile->Error = D_GIF_ERR_NOT_READABLE;
         return GIF_ERROR;
     }
-    if (--Private->PixelCount > 0xffff0000UL)
-    {
+    if (--Private->PixelCount > 0xffff0000UL) {
         GifFile->Error = D_GIF_ERR_DATA_TOO_BIG;
         return GIF_ERROR;
     }
 
     if (DGifDecompressLine(GifFile, &Pixel, 1) == GIF_OK) {
         if (Private->PixelCount == 0) {
-            /* We probably won't be called any more, so let's clean up
-             * everything before we return: need to flush out all the
-             * rest of image until an empty block (size 0)
+            /* We probably won't be called any more, so let's clean
+             * up everything before we return: need to flush out all
+             * the rest of image until an empty block (size 0)
              * detected. We use GetCodeNext.
              */
-            do
-                if (DGifGetCodeNext(GifFile, &Dummy) == GIF_ERROR)
+            do {
+                if (DGifGetCodeNext(GifFile, &Dummy) ==
+                    GIF_ERROR) {
                     return GIF_ERROR;
-            while (Dummy != NULL) ;
+                }
+            } while (Dummy != NULL);
         }
         return GIF_OK;
-    } else
+    } else {
         return GIF_ERROR;
+    }
 }
 
 /******************************************************************************
@@ -584,13 +587,12 @@ DGifGetPixel(GifFileType *GifFile, GifPixelType Pixel)
  The Extension should NOT be freed by the user (not dynamically allocated).
  Note it is assumed the Extension description header has been read.
 ******************************************************************************/
-int
-DGifGetExtension(GifFileType *GifFile, int *ExtCode, GifByteType **Extension)
-{
+int DGifGetExtension(GifFileType *GifFile, int *ExtCode,
+                     GifByteType **Extension) {
     GifByteType Buf;
     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    //fprintf(stderr, "### -> DGifGetExtension:\n");
+    // fprintf(stderr, "### -> DGifGetExtension:\n");
     if (!IS_READABLE(Private)) {
         /* This file was NOT open for reading: */
         GifFile->Error = D_GIF_ERR_NOT_READABLE;
@@ -603,7 +605,8 @@ DGifGetExtension(GifFileType *GifFile, int *ExtCode, GifByteType **Extension)
         return GIF_ERROR;
     }
     *ExtCode = Buf;
-    //fprintf(stderr, "### <- DGifGetExtension: %02x, about to call next\n", Buf);
+    // fprintf(stderr, "### <- DGifGetExtension: %02x, about to call
+    // next\n", Buf);
 
     return DGifGetExtensionNext(GifFile, Extension);
 }
@@ -613,30 +616,30 @@ DGifGetExtension(GifFileType *GifFile, int *ExtCode, GifByteType **Extension)
  routine should be called until NULL Extension is returned.
  The Extension should NOT be freed by the user (not dynamically allocated).
 ******************************************************************************/
-int
-DGifGetExtensionNext(GifFileType *GifFile, GifByteType ** Extension)
-{
+int DGifGetExtensionNext(GifFileType *GifFile, GifByteType **Extension) {
     GifByteType Buf;
     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
-    //fprintf(stderr, "### -> DGifGetExtensionNext\n");
+    // fprintf(stderr, "### -> DGifGetExtensionNext\n");
     if (InternalRead(GifFile, &Buf, 1) != 1) {
         GifFile->Error = D_GIF_ERR_READ_FAILED;
         return GIF_ERROR;
     }
-    //fprintf(stderr, "### DGifGetExtensionNext sees %d\n", Buf);
+    // fprintf(stderr, "### DGifGetExtensionNext sees %d\n", Buf);
 
     if (Buf > 0) {
-        *Extension = Private->Buf;    /* Use private unused buffer. */
-        (*Extension)[0] = Buf;  /* Pascal strings notation (pos. 0 is len.). */
-        /* coverity[tainted_data,check_return] */
+        *Extension = Private->Buf; /* Use private unused buffer. */
+        (*Extension)[0] =
+            Buf; /* Pascal strings notation (pos. 0 is len.). */
+                 /* coverity[tainted_data,check_return] */
         if (InternalRead(GifFile, &((*Extension)[1]), Buf) != Buf) {
             GifFile->Error = D_GIF_ERR_READ_FAILED;
             return GIF_ERROR;
         }
-    } else
+    } else {
         *Extension = NULL;
-    //fprintf(stderr, "### <- DGifGetExtensionNext: %p\n", Extension);
+    }
+    // fprintf(stderr, "### <- DGifGetExtensionNext: %p\n", Extension);
 
     return GIF_OK;
 }
@@ -647,19 +650,20 @@ DGifGetExtensionNext(GifFileType *GifFile, GifByteType ** Extension)
 
 int DGifExtensionToGCB(const size_t GifExtensionLength,
                        const GifByteType *GifExtension,
-                       GraphicsControlBlock *GCB)
-{
+                       GraphicsControlBlock *GCB) {
     if (GifExtensionLength != 4) {
         return GIF_ERROR;
     }
 
     GCB->DisposalMode = (GifExtension[0] >> 2) & 0x07;
     GCB->UserInputFlag = (GifExtension[0] & 0x02) != 0;
-    GCB->DelayTime = UNSIGNED_LITTLE_ENDIAN(GifExtension[1], GifExtension[2]);
-    if (GifExtension[0] & 0x01)
+    GCB->DelayTime =
+        UNSIGNED_LITTLE_ENDIAN(GifExtension[1], GifExtension[2]);
+    if (GifExtension[0] & 0x01) {
         GCB->TransparentColor = (int)GifExtension[3];
-    else
+    } else {
         GCB->TransparentColor = NO_TRANSPARENT_COLOR;
+    }
 
     return GIF_OK;
 }
@@ -668,23 +672,27 @@ int DGifExtensionToGCB(const size_t GifExtensionLength,
  Extract the Graphics Control Block for a saved image, if it exists.
 ******************************************************************************/
 
-int DGifSavedExtensionToGCB(GifFileType *GifFile,
-                int ImageIndex, GraphicsControlBlock *GCB)
-{
+int DGifSavedExtensionToGCB(GifFileType *GifFile, int ImageIndex,
+                            GraphicsControlBlock *GCB) {
     int i;
 
-    if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1)
+    if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1) {
         return GIF_ERROR;
+    }
 
     GCB->DisposalMode = DISPOSAL_UNSPECIFIED;
     GCB->UserInputFlag = false;
     GCB->DelayTime = 0;
     GCB->TransparentColor = NO_TRANSPARENT_COLOR;
 
-    for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount; i++) {
-        ExtensionBlock *ep = &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i];
-        if (ep->Function == GRAPHICS_EXT_FUNC_CODE)
-            return DGifExtensionToGCB(ep->ByteCount, ep->Bytes, GCB);
+    for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount;
+         i++) {
+        ExtensionBlock *ep =
+            &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i];
+        if (ep->Function == GRAPHICS_EXT_FUNC_CODE) {
+            return DGifExtensionToGCB(ep->ByteCount, ep->Bytes,
+                                      GCB);
+        }
     }
 
     return GIF_ERROR;
@@ -693,13 +701,12 @@ int DGifSavedExtensionToGCB(GifFileType *GifFile,
 /******************************************************************************
  This routine should be called last, to close the GIF file.
 ******************************************************************************/
-int
-DGifCloseFile(GifFileType *GifFile, int *ErrorCode)
-{
+int DGifCloseFile(GifFileType *GifFile, int *ErrorCode) {
     GifFilePrivateType *Private;
 
-    if (GifFile == NULL || GifFile->Private == NULL)
+    if (GifFile == NULL || GifFile->Private == NULL) {
         return GIF_ERROR;
+    }
 
     if (GifFile->Image.ColorMap) {
         GifFreeMapObject(GifFile->Image.ColorMap);
@@ -716,22 +723,25 @@ DGifCloseFile(GifFileType *GifFile, int *ErrorCode)
         GifFile->SavedImages = NULL;
     }
 
-    GifFreeExtensions(&GifFile->ExtensionBlockCount, &GifFile->ExtensionBlocks);
+    GifFreeExtensions(&GifFile->ExtensionBlockCount,
+                      &GifFile->ExtensionBlocks);
 
-    Private = (GifFilePrivateType *) GifFile->Private;
+    Private = (GifFilePrivateType *)GifFile->Private;
 
     if (!IS_READABLE(Private)) {
         /* This file was NOT open for reading: */
-        if (ErrorCode != NULL)
+        if (ErrorCode != NULL) {
             *ErrorCode = D_GIF_ERR_NOT_READABLE;
+        }
         free((char *)GifFile->Private);
         free(GifFile);
         return GIF_ERROR;
     }
 
     if (Private->File && (fclose(Private->File) != 0)) {
-        if (ErrorCode != NULL)
+        if (ErrorCode != NULL) {
             *ErrorCode = D_GIF_ERR_CLOSE_FAILED;
+        }
         free((char *)GifFile->Private);
         free(GifFile);
         return GIF_ERROR;
@@ -739,17 +749,16 @@ DGifCloseFile(GifFileType *GifFile, int *ErrorCode)
 
     free((char *)GifFile->Private);
     free(GifFile);
-    if (ErrorCode != NULL)
+    if (ErrorCode != NULL) {
         *ErrorCode = D_GIF_SUCCEEDED;
+    }
     return GIF_OK;
 }
 
 /******************************************************************************
  Get 2 bytes (word) from the given file:
 ******************************************************************************/
-static int
-DGifGetWord(GifFileType *GifFile, GifWord *Word)
-{
+static int DGifGetWord(GifFileType *GifFile, GifWord *Word) {
     unsigned char c[2];
 
     /* coverity[check_return] */
@@ -769,9 +778,7 @@ DGifGetWord(GifFileType *GifFile, GifWord *Word)
  to DGifGetCodeNext, until NULL block is returned.
  The block should NOT be freed by the user (not dynamically allocated).
 ******************************************************************************/
-int
-DGifGetCode(GifFileType *GifFile, int *CodeSize, GifByteType **CodeBlock)
-{
+int DGifGetCode(GifFileType *GifFile, int *CodeSize, GifByteType **CodeBlock) {
     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
     if (!IS_READABLE(Private)) {
@@ -790,9 +797,7 @@ DGifGetCode(GifFileType *GifFile, int *CodeSize, GifByteType **CodeBlock)
  called until NULL block is returned.
  The block should NOT be freed by the user (not dynamically allocated).
 ******************************************************************************/
-int
-DGifGetCodeNext(GifFileType *GifFile, GifByteType **CodeBlock)
-{
+int DGifGetCodeNext(GifFileType *GifFile, GifByteType **CodeBlock) {
     GifByteType Buf;
     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
@@ -805,17 +810,19 @@ DGifGetCodeNext(GifFileType *GifFile, GifByteType **CodeBlock)
 
     /* coverity[lower_bounds] */
     if (Buf > 0) {
-        *CodeBlock = Private->Buf;    /* Use private unused buffer. */
-        (*CodeBlock)[0] = Buf;  /* Pascal strings notation (pos. 0 is len.). */
-        /* coverity[tainted_data] */
+        *CodeBlock = Private->Buf; /* Use private unused buffer. */
+        (*CodeBlock)[0] =
+            Buf; /* Pascal strings notation (pos. 0 is len.). */
+                 /* coverity[tainted_data] */
         if (InternalRead(GifFile, &((*CodeBlock)[1]), Buf) != Buf) {
             GifFile->Error = D_GIF_ERR_READ_FAILED;
             return GIF_ERROR;
         }
     } else {
         *CodeBlock = NULL;
-        Private->Buf[0] = 0;    /* Make sure the buffer is empty! */
-        Private->PixelCount = 0;    /* And local info. indicate image read. */
+        Private->Buf[0] = 0; /* Make sure the buffer is empty! */
+        Private->PixelCount =
+            0; /* And local info. indicate image read. */
     }
 
     return GIF_OK;
@@ -824,41 +831,43 @@ DGifGetCodeNext(GifFileType *GifFile, GifByteType **CodeBlock)
 /******************************************************************************
  Setup the LZ decompression for this image:
 ******************************************************************************/
-static int
-DGifSetupDecompress(GifFileType *GifFile)
-{
+static int DGifSetupDecompress(GifFileType *GifFile) {
     int i, BitsPerPixel;
     GifByteType CodeSize;
     GifPrefixType *Prefix;
     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
     /* coverity[check_return] */
-    if (InternalRead(GifFile, &CodeSize, 1) < 1) {    /* Read Code size from file. */
-        return GIF_ERROR;    /* Failed to read Code size. */
+    if (InternalRead(GifFile, &CodeSize, 1) <
+        1) { /* Read Code size from file. */
+        GifFile->Error = D_GIF_ERR_READ_FAILED;
+        return GIF_ERROR; /* Failed to read Code size. */
     }
     BitsPerPixel = CodeSize;
 
     /* this can only happen on a severely malformed GIF */
     if (BitsPerPixel > 8) {
-        GifFile->Error = D_GIF_ERR_READ_FAILED;    /* somewhat bogus error code */
-        return GIF_ERROR;    /* Failed to read Code size. */
+        GifFile->Error =
+            D_GIF_ERR_READ_FAILED; /* somewhat bogus error code */
+        return GIF_ERROR;          /* Failed to read Code size. */
     }
 
-    Private->Buf[0] = 0;    /* Input Buffer empty. */
+    Private->Buf[0] = 0; /* Input Buffer empty. */
     Private->BitsPerPixel = BitsPerPixel;
     Private->ClearCode = (1 << BitsPerPixel);
     Private->EOFCode = Private->ClearCode + 1;
     Private->RunningCode = Private->EOFCode + 1;
-    Private->RunningBits = BitsPerPixel + 1;    /* Number of bits per code. */
-    Private->MaxCode1 = 1 << Private->RunningBits;    /* Max. code + 1. */
-    Private->StackPtr = 0;    /* No pixels on the pixel stack. */
+    Private->RunningBits = BitsPerPixel + 1; /* Number of bits per code. */
+    Private->MaxCode1 = 1 << Private->RunningBits; /* Max. code + 1. */
+    Private->StackPtr = 0; /* No pixels on the pixel stack. */
     Private->LastCode = NO_SUCH_CODE;
-    Private->CrntShiftState = 0;    /* No information in CrntShiftDWord. */
+    Private->CrntShiftState = 0; /* No information in CrntShiftDWord. */
     Private->CrntShiftDWord = 0;
 
     Prefix = Private->Prefix;
-    for (i = 0; i <= LZ_MAX_CODE; i++)
+    for (i = 0; i <= LZ_MAX_CODE; i++) {
         Prefix[i] = NO_SUCH_CODE;
+    }
 
     return GIF_OK;
 }
@@ -869,14 +878,13 @@ DGifSetupDecompress(GifFileType *GifFile)
  This routine can be called few times (one per scan line, for example), in
  order the complete the whole image.
 ******************************************************************************/
-static int
-DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
-{
+static int DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,
+                              int LineLen) {
     int i = 0;
     int j, CrntCode, EOFCode, ClearCode, CrntPrefix, LastCode, StackPtr;
     GifByteType *Stack, *Suffix;
     GifPrefixType *Prefix;
-    GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
+    GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
     StackPtr = Private->StackPtr;
     Prefix = Private->Prefix;
@@ -891,72 +899,88 @@ DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
     }
 
     if (StackPtr != 0) {
-        /* Let pop the stack off before continueing to read the GIF file: */
-        while (StackPtr != 0 && i < LineLen)
+        /* Let pop the stack off before continueing to read the GIF
+         * file: */
+        while (StackPtr != 0 && i < LineLen) {
             Line[i++] = Stack[--StackPtr];
+        }
     }
 
-    while (i < LineLen) {    /* Decode LineLen items. */
-        if (DGifDecompressInput(GifFile, &CrntCode) == GIF_ERROR)
+    while (i < LineLen) { /* Decode LineLen items. */
+        if (DGifDecompressInput(GifFile, &CrntCode) == GIF_ERROR) {
             return GIF_ERROR;
+        }
 
         if (CrntCode == EOFCode) {
-            /* Note however that usually we will not be here as we will stop
-             * decoding as soon as we got all the pixel, or EOF code will
-             * not be read at all, and DGifGetLine/Pixel clean everything.  */
+            /* Note however that usually we will not be here as we
+             * will stop decoding as soon as we got all the pixel,
+             * or EOF code will not be read at all, and
+             * DGifGetLine/Pixel clean everything.  */
             GifFile->Error = D_GIF_ERR_EOF_TOO_SOON;
             return GIF_ERROR;
         } else if (CrntCode == ClearCode) {
             /* We need to start over again: */
-            for (j = 0; j <= LZ_MAX_CODE; j++)
+            for (j = 0; j <= LZ_MAX_CODE; j++) {
                 Prefix[j] = NO_SUCH_CODE;
+            }
             Private->RunningCode = Private->EOFCode + 1;
             Private->RunningBits = Private->BitsPerPixel + 1;
             Private->MaxCode1 = 1 << Private->RunningBits;
             LastCode = Private->LastCode = NO_SUCH_CODE;
         } else {
-            /* Its regular code - if in pixel range simply add it to output
-             * stream, otherwise trace to codes linked list until the prefix
-             * is in pixel range: */
+            /* Its regular code - if in pixel range simply add it to
+             * output stream, otherwise trace to codes linked list
+             * until the prefix is in pixel range: */
             if (CrntCode < ClearCode) {
-                /* This is simple - its pixel scalar, so add it to output: */
+                /* This is simple - its pixel scalar, so add it
+                 * to output: */
                 Line[i++] = CrntCode;
             } else {
-                /* Its a code to needed to be traced: trace the linked list
-                 * until the prefix is a pixel, while pushing the suffix
-                 * pixels on our stack. If we done, pop the stack in reverse
-                 * (thats what stack is good for!) order to output.  */
+                /* Its a code to needed to be traced: trace the
+                 * linked list until the prefix is a pixel,
+                 * while pushing the suffix pixels on our stack.
+                 * If we done, pop the stack in reverse (thats
+                 * what stack is good for!) order to output.  */
                 if (Prefix[CrntCode] == NO_SUCH_CODE) {
                     CrntPrefix = LastCode;
 
-                    /* Only allowed if CrntCode is exactly the running code:
-                     * In that case CrntCode = XXXCode, CrntCode or the
-                     * prefix code is last code and the suffix char is
-                     * exactly the prefix of last code! */
-                    if (CrntCode == Private->RunningCode - 2) {
-                        Suffix[Private->RunningCode - 2] =
-                           Stack[StackPtr++] = DGifGetPrefixChar(Prefix,
-                                                                 LastCode,
-                                                                 ClearCode);
+                    /* Only allowed if CrntCode is exactly
+                     * the running code: In that case
+                     * CrntCode = XXXCode, CrntCode or the
+                     * prefix code is last code and the
+                     * suffix char is exactly the prefix of
+                     * last code! */
+                    if (CrntCode ==
+                        Private->RunningCode - 2) {
+                        Suffix[Private->RunningCode -
+                               2] = Stack[StackPtr++] =
+                            DGifGetPrefixChar(
+                                Prefix, LastCode,
+                                ClearCode);
                     } else {
-                        Suffix[Private->RunningCode - 2] =
-                           Stack[StackPtr++] = DGifGetPrefixChar(Prefix,
-                                                                 CrntCode,
-                                                                 ClearCode);
+                        Suffix[Private->RunningCode -
+                               2] = Stack[StackPtr++] =
+                            DGifGetPrefixChar(
+                                Prefix, CrntCode,
+                                ClearCode);
                     }
-                } else
+                } else {
                     CrntPrefix = CrntCode;
+                }
 
-                /* Now (if image is O.K.) we should not get a NO_SUCH_CODE
-                 * during the trace. As we might loop forever, in case of
-                 * defective image, we use StackPtr as loop counter and stop
-                 * before overflowing Stack[]. */
+                /* Now (if image is O.K.) we should not get a
+                 * NO_SUCH_CODE during the trace. As we might
+                 * loop forever, in case of defective image, we
+                 * use StackPtr as loop counter and stop before
+                 * overflowing Stack[]. */
                 while (StackPtr < LZ_MAX_CODE &&
-                       CrntPrefix > ClearCode && CrntPrefix <= LZ_MAX_CODE) {
+                       CrntPrefix > ClearCode &&
+                       CrntPrefix <= LZ_MAX_CODE) {
                     Stack[StackPtr++] = Suffix[CrntPrefix];
                     CrntPrefix = Prefix[CrntPrefix];
                 }
-                if (StackPtr >= LZ_MAX_CODE || CrntPrefix > LZ_MAX_CODE) {
+                if (StackPtr >= LZ_MAX_CODE ||
+                    CrntPrefix > LZ_MAX_CODE) {
                     GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
                     return GIF_ERROR;
                 }
@@ -964,22 +988,29 @@ DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
                 Stack[StackPtr++] = CrntPrefix;
 
                 /* Now lets pop all the stack into output: */
-                while (StackPtr != 0 && i < LineLen)
+                while (StackPtr != 0 && i < LineLen) {
                     Line[i++] = Stack[--StackPtr];
+                }
             }
-            if (LastCode != NO_SUCH_CODE && Private->RunningCode - 2 < (LZ_MAX_CODE+1) && Prefix[Private->RunningCode - 2] == NO_SUCH_CODE) {
+            if (LastCode != NO_SUCH_CODE &&
+                Private->RunningCode - 2 < (LZ_MAX_CODE + 1) &&
+                Prefix[Private->RunningCode - 2] == NO_SUCH_CODE) {
                 Prefix[Private->RunningCode - 2] = LastCode;
 
                 if (CrntCode == Private->RunningCode - 2) {
-                    /* Only allowed if CrntCode is exactly the running code:
-                     * In that case CrntCode = XXXCode, CrntCode or the
-                     * prefix code is last code and the suffix char is
-                     * exactly the prefix of last code! */
+                    /* Only allowed if CrntCode is exactly
+                     * the running code: In that case
+                     * CrntCode = XXXCode, CrntCode or the
+                     * prefix code is last code and the
+                     * suffix char is exactly the prefix of
+                     * last code! */
                     Suffix[Private->RunningCode - 2] =
-                       DGifGetPrefixChar(Prefix, LastCode, ClearCode);
+                        DGifGetPrefixChar(Prefix, LastCode,
+                                          ClearCode);
                 } else {
                     Suffix[Private->RunningCode - 2] =
-                       DGifGetPrefixChar(Prefix, CrntCode, ClearCode);
+                        DGifGetPrefixChar(Prefix, CrntCode,
+                                          ClearCode);
                 }
             }
             LastCode = CrntCode;
@@ -998,9 +1029,8 @@ DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
  If image is defective, we might loop here forever, so we limit the loops to
  the maximum possible if image O.k. - LZ_MAX_CODE times.
 ******************************************************************************/
-static int
-DGifGetPrefixChar(GifPrefixType *Prefix, int Code, int ClearCode)
-{
+static int DGifGetPrefixChar(const GifPrefixType *Prefix, int Code,
+                             int ClearCode) {
     int i = 0;
 
     while (Code > ClearCode && i++ <= LZ_MAX_CODE) {
@@ -1016,9 +1046,7 @@ DGifGetPrefixChar(GifPrefixType *Prefix, int Code, int ClearCode)
  Interface for accessing the LZ codes directly. Set Code to the real code
  (12bits), or to -1 if EOF code is returned.
 ******************************************************************************/
-int
-DGifGetLZCodes(GifFileType *GifFile, int *Code)
-{
+int DGifGetLZCodes(GifFileType *GifFile, int *Code) {
     GifByteType *CodeBlock;
     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
@@ -1028,15 +1056,18 @@ DGifGetLZCodes(GifFileType *GifFile, int *Code)
         return GIF_ERROR;
     }
 
-    if (DGifDecompressInput(GifFile, Code) == GIF_ERROR)
+    if (DGifDecompressInput(GifFile, Code) == GIF_ERROR) {
         return GIF_ERROR;
+    }
 
     if (*Code == Private->EOFCode) {
-        /* Skip rest of codes (hopefully only NULL terminating block): */
+        /* Skip rest of codes (hopefully only NULL terminating block):
+         */
         do {
-            if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR)
+            if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR) {
                 return GIF_ERROR;
-        } while (CodeBlock != NULL) ;
+            }
+        } while (CodeBlock != NULL);
 
         *Code = -1;
     } else if (*Code == Private->ClearCode) {
@@ -1055,15 +1086,10 @@ DGifGetLZCodes(GifFileType *GifFile, int *Code)
  8 bits (bytes) packets, into the real codes.
  Returns GIF_OK if read successfully.
 ******************************************************************************/
-static int
-DGifDecompressInput(GifFileType *GifFile, int *Code)
-{
+static int DGifDecompressInput(GifFileType *GifFile, int *Code) {
     static const unsigned short CodeMasks[] = {
-        0x0000, 0x0001, 0x0003, 0x0007,
-        0x000f, 0x001f, 0x003f, 0x007f,
-        0x00ff, 0x01ff, 0x03ff, 0x07ff,
-        0x0fff
-    };
+        0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f,
+        0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff};
 
     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
 
@@ -1077,11 +1103,12 @@ DGifDecompressInput(GifFileType *GifFile, int *Code)
 
     while (Private->CrntShiftState < Private->RunningBits) {
         /* Needs to get more bytes from input stream for next code: */
-        if (DGifBufferedInput(GifFile, Private->Buf, &NextByte) == GIF_ERROR) {
+        if (DGifBufferedInput(GifFile, Private->Buf, &NextByte) ==
+            GIF_ERROR) {
             return GIF_ERROR;
         }
-        Private->CrntShiftDWord |=
-            ((unsigned long)NextByte) << Private->CrntShiftState;
+        Private->CrntShiftDWord |= ((unsigned long)NextByte)
+                                   << Private->CrntShiftState;
         Private->CrntShiftState += 8;
     }
     *Code = Private->CrntShiftDWord & CodeMasks[Private->RunningBits];
@@ -1109,9 +1136,8 @@ DGifDecompressInput(GifFileType *GifFile, int *Code)
  The routine returns the next byte from its internal buffer (or read next
  block in if buffer empty) and returns GIF_OK if succesful.
 ******************************************************************************/
-static int
-DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf, GifByteType *NextByte)
-{
+static int DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf,
+                             GifByteType *NextByte) {
     if (Buf[0] == 0) {
         /* Needs to read the next buffer - this one is empty: */
         /* coverity[check_return] */
@@ -1120,8 +1146,8 @@ DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf, GifByteType *NextByte)
             return GIF_ERROR;
         }
         /* There shouldn't be any empty data blocks here as the LZW spec
-         * says the LZW termination code should come first.  Therefore we
-         * shouldn't be inside this routine at that point.
+         * says the LZW termination code should come first.  Therefore
+         * we shouldn't be inside this routine at that point.
          */
         if (Buf[0] == 0) {
             GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
@@ -1132,7 +1158,7 @@ DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf, GifByteType *NextByte)
             return GIF_ERROR;
         }
         *NextByte = Buf[1];
-        Buf[1] = 2;    /* We use now the second place as last char read! */
+        Buf[1] = 2; /* We use now the second place as last char read! */
         Buf[0]--;
     } else {
         *NextByte = Buf[Buf[1]++];
@@ -1142,14 +1168,32 @@ DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf, GifByteType *NextByte)
     return GIF_OK;
 }
 
+/******************************************************************************
+ This routine is called in case of error during parsing image. We need to
+ decrease image counter and reallocate memory for saved images. Not decreasing
+ ImageCount may lead to null pointer dereference, because the last element in
+ SavedImages may point to the spoilt image and null pointer buffers.
+*******************************************************************************/
+void DGifDecreaseImageCounter(GifFileType *GifFile) {
+    GifFile->ImageCount--;
+    if (GifFile->SavedImages[GifFile->ImageCount].RasterBits != NULL) {
+        free(GifFile->SavedImages[GifFile->ImageCount].RasterBits);
+    }
+
+    // Realloc array according to the new image counter.
+    SavedImage *correct_saved_images = (SavedImage *)reallocarray(
+        GifFile->SavedImages, GifFile->ImageCount, sizeof(SavedImage));
+    if (correct_saved_images != NULL) {
+        GifFile->SavedImages = correct_saved_images;
+    }
+}
+
 /******************************************************************************
  This routine reads an entire GIF into core, hanging all its state info off
  the GifFileType pointer.  Call DGifOpenFileName() or DGifOpenFileHandle()
  first to initialize I/O.  Its inverse is EGifSpew().
 *******************************************************************************/
-int
-DGifSlurp(GifFileType *GifFile)
-{
+int DGifSlurp(GifFileType *GifFile) {
     size_t ImageSize;
     GifRecordType RecordType;
     SavedImage *sp;
@@ -1160,103 +1204,130 @@ DGifSlurp(GifFileType *GifFile)
     GifFile->ExtensionBlockCount = 0;
 
     do {
-        if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR)
+        if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
             return (GIF_ERROR);
+        }
 
         switch (RecordType) {
-          case IMAGE_DESC_RECORD_TYPE:
-              if (DGifGetImageDesc(GifFile) == GIF_ERROR)
-                  return (GIF_ERROR);
-
-              sp = &GifFile->SavedImages[GifFile->ImageCount - 1];
-              /* Allocate memory for the image */
-              if (sp->ImageDesc.Width <= 0 || sp->ImageDesc.Height <= 0 ||
-                      sp->ImageDesc.Width > (INT_MAX / sp->ImageDesc.Height)) {
-                  return GIF_ERROR;
-              }
-              ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height;
-
-              if (ImageSize > (SIZE_MAX / sizeof(GifPixelType))) {
-                  return GIF_ERROR;
-              }
-              sp->RasterBits = (unsigned char *)reallocarray(NULL, ImageSize,
-                      sizeof(GifPixelType));
-
-              if (sp->RasterBits == NULL) {
-                  return GIF_ERROR;
-              }
-
-              if (sp->ImageDesc.Interlace) {
-                  int i, j;
-                   /*
-                    * The way an interlaced image should be read -
-                    * offsets and jumps...
-                    */
-                  int InterlacedOffset[] = { 0, 4, 2, 1 };
-                  int InterlacedJumps[] = { 8, 8, 4, 2 };
-                  /* Need to perform 4 passes on the image */
-                  for (i = 0; i < 4; i++)
-                      for (j = InterlacedOffset[i];
-                       j < sp->ImageDesc.Height;
-                       j += InterlacedJumps[i]) {
-                      if (DGifGetLine(GifFile,
-                              sp->RasterBits+j*sp->ImageDesc.Width,
-                              sp->ImageDesc.Width) == GIF_ERROR)
-                          return GIF_ERROR;
-                      }
-              }
-              else {
-                  if (DGifGetLine(GifFile,sp->RasterBits,ImageSize)==GIF_ERROR)
-                      return (GIF_ERROR);
-              }
-
-              if (GifFile->ExtensionBlocks) {
-                  sp->ExtensionBlocks = GifFile->ExtensionBlocks;
-                  sp->ExtensionBlockCount = GifFile->ExtensionBlockCount;
-
-                  GifFile->ExtensionBlocks = NULL;
-                  GifFile->ExtensionBlockCount = 0;
-              }
-              break;
-
-          case EXTENSION_RECORD_TYPE:
-              if (DGifGetExtension(GifFile,&ExtFunction,&ExtData) == GIF_ERROR)
-                  return (GIF_ERROR);
-              /* Create an extension block with our data */
-              if (ExtData != NULL) {
-                  if (GifAddExtensionBlock(&GifFile->ExtensionBlockCount,
-                               &GifFile->ExtensionBlocks,
-                               ExtFunction, ExtData[0], &ExtData[1])
-                      == GIF_ERROR)
-                      return (GIF_ERROR);
-              }
-              for (;;) {
-                  if (DGifGetExtensionNext(GifFile, &ExtData) == GIF_ERROR)
-                      return (GIF_ERROR);
-                  if (ExtData == NULL)
-                      break;
-                  /* Continue the extension block */
-                  if (ExtData != NULL)
-                      if (GifAddExtensionBlock(&GifFile->ExtensionBlockCount,
-                                   &GifFile->ExtensionBlocks,
-                                   CONTINUE_EXT_FUNC_CODE,
-                                   ExtData[0], &ExtData[1]) == GIF_ERROR)
-                              return (GIF_ERROR);
-              }
-              break;
-
-          case TERMINATE_RECORD_TYPE:
-              break;
-
-          default:    /* Should be trapped by DGifGetRecordType */
-              break;
+        case IMAGE_DESC_RECORD_TYPE:
+            if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
+                return (GIF_ERROR);
+            }
+
+            sp = &GifFile->SavedImages[GifFile->ImageCount - 1];
+            /* Allocate memory for the image */
+            if (sp->ImageDesc.Width <= 0 ||
+                sp->ImageDesc.Height <= 0 ||
+                sp->ImageDesc.Width >
+                    (INT_MAX / sp->ImageDesc.Height)) {
+                DGifDecreaseImageCounter(GifFile);
+                return GIF_ERROR;
+            }
+            ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height;
+
+            if (ImageSize > (SIZE_MAX / sizeof(GifPixelType))) {
+                DGifDecreaseImageCounter(GifFile);
+                return GIF_ERROR;
+            }
+            sp->RasterBits = (unsigned char *)reallocarray(
+                NULL, ImageSize, sizeof(GifPixelType));
+
+            if (sp->RasterBits == NULL) {
+                DGifDecreaseImageCounter(GifFile);
+                return GIF_ERROR;
+            }
+
+            if (sp->ImageDesc.Interlace) {
+                int i, j;
+                /*
+                 * The way an interlaced image should be read -
+                 * offsets and jumps...
+                 */
+                static const int InterlacedOffset[] = {0, 4, 2,
+                                                       1};
+                static const int InterlacedJumps[] = {8, 8, 4,
+                                                      2};
+                /* Need to perform 4 passes on the image */
+                for (i = 0; i < 4; i++) {
+                    for (j = InterlacedOffset[i];
+                         j < sp->ImageDesc.Height;
+                         j += InterlacedJumps[i]) {
+                        if (DGifGetLine(
+                                GifFile,
+                                sp->RasterBits +
+                                    j * sp->ImageDesc
+                                            .Width,
+                                sp->ImageDesc.Width) ==
+                            GIF_ERROR) {
+                            DGifDecreaseImageCounter(
+                                GifFile);
+                            return GIF_ERROR;
+                        }
+                    }
+                }
+            } else {
+                if (DGifGetLine(GifFile, sp->RasterBits,
+                                ImageSize) == GIF_ERROR) {
+                    DGifDecreaseImageCounter(GifFile);
+                    return GIF_ERROR;
+                }
+            }
+
+            if (GifFile->ExtensionBlocks) {
+                sp->ExtensionBlocks = GifFile->ExtensionBlocks;
+                sp->ExtensionBlockCount =
+                    GifFile->ExtensionBlockCount;
+
+                GifFile->ExtensionBlocks = NULL;
+                GifFile->ExtensionBlockCount = 0;
+            }
+            break;
+
+        case EXTENSION_RECORD_TYPE:
+            if (DGifGetExtension(GifFile, &ExtFunction, &ExtData) ==
+                GIF_ERROR) {
+                return (GIF_ERROR);
+            }
+            /* Create an extension block with our data */
+            if (ExtData != NULL) {
+                if (GifAddExtensionBlock(
+                        &GifFile->ExtensionBlockCount,
+                        &GifFile->ExtensionBlocks, ExtFunction,
+                        ExtData[0], &ExtData[1]) == GIF_ERROR) {
+                    return (GIF_ERROR);
+                }
+            }
+            for (;;) {
+                if (DGifGetExtensionNext(GifFile, &ExtData) ==
+                    GIF_ERROR) {
+                    return (GIF_ERROR);
+                }
+                if (ExtData == NULL) {
+                    break;
+                }
+                /* Continue the extension block */
+                if (GifAddExtensionBlock(
+                        &GifFile->ExtensionBlockCount,
+                        &GifFile->ExtensionBlocks,
+                        CONTINUE_EXT_FUNC_CODE, ExtData[0],
+                        &ExtData[1]) == GIF_ERROR) {
+                    return (GIF_ERROR);
+                }
+            }
+            break;
+
+        case TERMINATE_RECORD_TYPE:
+            break;
+
+        default: /* Should be trapped by DGifGetRecordType */
+            break;
         }
     } while (RecordType != TERMINATE_RECORD_TYPE);
 
     /* Sanity check for corrupted file */
     if (GifFile->ImageCount == 0) {
         GifFile->Error = D_GIF_ERR_NO_IMAG_DSCR;
-        return(GIF_ERROR);
+        return (GIF_ERROR);
     }
 
     return (GIF_OK);
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/gif_err.c b/src/java.desktop/share/native/libsplashscreen/giflib/gif_err.c
index db08838efff..3b6785f7c63 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/gif_err.c
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/gif_err.c
@@ -38,82 +38,80 @@ SPDX-License-Identifier: MIT
 /*****************************************************************************
  Return a string description of  the last GIF error
 *****************************************************************************/
-const char *
-GifErrorString(int ErrorCode)
-{
+const char *GifErrorString(int ErrorCode) {
     const char *Err;
 
     switch (ErrorCode) {
-      case E_GIF_ERR_OPEN_FAILED:
+    case E_GIF_ERR_OPEN_FAILED:
         Err = "Failed to open given file";
         break;
-      case E_GIF_ERR_WRITE_FAILED:
+    case E_GIF_ERR_WRITE_FAILED:
         Err = "Failed to write to given file";
         break;
-      case E_GIF_ERR_HAS_SCRN_DSCR:
+    case E_GIF_ERR_HAS_SCRN_DSCR:
         Err = "Screen descriptor has already been set";
         break;
-      case E_GIF_ERR_HAS_IMAG_DSCR:
+    case E_GIF_ERR_HAS_IMAG_DSCR:
         Err = "Image descriptor is still active";
         break;
-      case E_GIF_ERR_NO_COLOR_MAP:
+    case E_GIF_ERR_NO_COLOR_MAP:
         Err = "Neither global nor local color map";
         break;
-      case E_GIF_ERR_DATA_TOO_BIG:
+    case E_GIF_ERR_DATA_TOO_BIG:
         Err = "Number of pixels bigger than width * height";
         break;
-      case E_GIF_ERR_NOT_ENOUGH_MEM:
+    case E_GIF_ERR_NOT_ENOUGH_MEM:
         Err = "Failed to allocate required memory";
         break;
-      case E_GIF_ERR_DISK_IS_FULL:
+    case E_GIF_ERR_DISK_IS_FULL:
         Err = "Write failed (disk full?)";
         break;
-      case E_GIF_ERR_CLOSE_FAILED:
+    case E_GIF_ERR_CLOSE_FAILED:
         Err = "Failed to close given file";
         break;
-      case E_GIF_ERR_NOT_WRITEABLE:
+    case E_GIF_ERR_NOT_WRITEABLE:
         Err = "Given file was not opened for write";
         break;
-      case D_GIF_ERR_OPEN_FAILED:
+    case D_GIF_ERR_OPEN_FAILED:
         Err = "Failed to open given file";
         break;
-      case D_GIF_ERR_READ_FAILED:
+    case D_GIF_ERR_READ_FAILED:
         Err = "Failed to read from given file";
         break;
-      case D_GIF_ERR_NOT_GIF_FILE:
+    case D_GIF_ERR_NOT_GIF_FILE:
         Err = "Data is not in GIF format";
         break;
-      case D_GIF_ERR_NO_SCRN_DSCR:
+    case D_GIF_ERR_NO_SCRN_DSCR:
         Err = "No screen descriptor detected";
         break;
-      case D_GIF_ERR_NO_IMAG_DSCR:
+    case D_GIF_ERR_NO_IMAG_DSCR:
         Err = "No Image Descriptor detected";
         break;
-      case D_GIF_ERR_NO_COLOR_MAP:
+    case D_GIF_ERR_NO_COLOR_MAP:
         Err = "Neither global nor local color map";
         break;
-      case D_GIF_ERR_WRONG_RECORD:
+    case D_GIF_ERR_WRONG_RECORD:
         Err = "Wrong record type detected";
         break;
-      case D_GIF_ERR_DATA_TOO_BIG:
+    case D_GIF_ERR_DATA_TOO_BIG:
         Err = "Number of pixels bigger than width * height";
         break;
-      case D_GIF_ERR_NOT_ENOUGH_MEM:
+    case D_GIF_ERR_NOT_ENOUGH_MEM:
         Err = "Failed to allocate required memory";
         break;
-      case D_GIF_ERR_CLOSE_FAILED:
+    case D_GIF_ERR_CLOSE_FAILED:
         Err = "Failed to close given file";
         break;
-      case D_GIF_ERR_NOT_READABLE:
+    case D_GIF_ERR_NOT_READABLE:
         Err = "Given file was not opened for read";
         break;
-      case D_GIF_ERR_IMAGE_DEFECT:
+    case D_GIF_ERR_IMAGE_DEFECT:
         Err = "Image is defective, decoding aborted";
         break;
-      case D_GIF_ERR_EOF_TOO_SOON:
+    case D_GIF_ERR_EOF_TOO_SOON:
         Err = "Image EOF detected before image complete";
         break;
-      default:
+    default:
         Err = NULL;
         break;
     }
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/gif_hash.h b/src/java.desktop/share/native/libsplashscreen/giflib/gif_hash.h
index 6cabd0866ed..bd00af64161 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/gif_hash.h
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/gif_hash.h
@@ -33,27 +33,25 @@ SPDX-License-Identifier: MIT
 #ifndef _GIF_HASH_H_
 #define _GIF_HASH_H_
 
-/** Begin JDK modifications to support building on Windows **/
 #ifndef _WIN32
 #include 
-#endif
-/** End JDK modifications to support building on Windows **/
+#endif /* _WIN32 */
 #include 
 
-#define HT_SIZE         8192    /* 12bits = 4096 or twice as big! */
-#define HT_KEY_MASK     0x1FFF  /* 13bits keys */
-#define HT_KEY_NUM_BITS 13      /* 13bits keys */
-#define HT_MAX_KEY      8191    /* 13bits - 1, maximal code possible */
-#define HT_MAX_CODE     4095    /* Biggest code possible in 12 bits. */
+#define HT_SIZE 8192       /* 12bits = 4096 or twice as big! */
+#define HT_KEY_MASK 0x1FFF /* 13bits keys */
+#define HT_KEY_NUM_BITS 13 /* 13bits keys */
+#define HT_MAX_KEY 8191    /* 13bits - 1, maximal code possible */
+#define HT_MAX_CODE 4095   /* Biggest code possible in 12 bits. */
 
 /* The 32 bits of the long are divided into two parts for the key & code:   */
 /* 1. The code is 12 bits as our compression algorithm is limited to 12bits */
-/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits.           */
+/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits.        */
 /* The key is the upper 20 bits.  The code is the lower 12. */
-#define HT_GET_KEY(l)    (l >> 12)
-#define HT_GET_CODE(l)   (l & 0x0FFF)
-#define HT_PUT_KEY(l)    (l << 12)
-#define HT_PUT_CODE(l)   (l & 0x0FFF)
+#define HT_GET_KEY(l) (l >> 12)
+#define HT_GET_CODE(l) (l & 0x0FFF)
+#define HT_PUT_KEY(l) (l << 12)
+#define HT_PUT_CODE(l) (l & 0x0FFF)
 
 typedef struct GifHashTableType {
     uint32_t HTable[HT_SIZE];
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib.h b/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib.h
index f739b36adfd..74a2e969c0d 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib.h
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib.h
@@ -39,27 +39,19 @@ extern "C" {
 
 #define GIFLIB_MAJOR 5
 #define GIFLIB_MINOR 2
-#define GIFLIB_RELEASE 1
+#define GIFLIB_RELEASE 2
 
-#define GIF_ERROR   0
-#define GIF_OK      1
+#define GIF_ERROR 0
+#define GIF_OK 1
 
+#include 
 #include 
-/** Begin JDK modifications to support building using old compilers**/
-//#include 
-#ifdef bool
-#undef bool
-#endif
-typedef int bool;
-#define false 0
-#define true 1
-/** End JDK modifications to support building using old compilers**/
-
-#define GIF_STAMP "GIFVER"          /* First chars in file - GIF stamp.  */
+
+#define GIF_STAMP "GIFVER" /* First chars in file - GIF stamp.  */
 #define GIF_STAMP_LEN sizeof(GIF_STAMP) - 1
-#define GIF_VERSION_POS 3           /* Version first character in stamp. */
-#define GIF87_STAMP "GIF87a"        /* First chars in file - GIF stamp.  */
-#define GIF89_STAMP "GIF89a"        /* First chars in file - GIF stamp.  */
+#define GIF_VERSION_POS 3    /* Version first character in stamp. */
+#define GIF87_STAMP "GIF87a" /* First chars in file - GIF stamp.  */
+#define GIF89_STAMP "GIF89a" /* First chars in file - GIF stamp.  */
 
 typedef unsigned char GifPixelType;
 typedef unsigned char *GifRowType;
@@ -75,24 +67,24 @@ typedef struct ColorMapObject {
     int ColorCount;
     int BitsPerPixel;
     bool SortFlag;
-    GifColorType *Colors;    /* on malloc(3) heap */
+    GifColorType *Colors; /* on malloc(3) heap */
 } ColorMapObject;
 
 typedef struct GifImageDesc {
-    GifWord Left, Top, Width, Height;   /* Current image dimensions. */
-    bool Interlace;                     /* Sequential/Interlaced lines. */
-    ColorMapObject *ColorMap;           /* The local color map */
+    GifWord Left, Top, Width, Height; /* Current image dimensions. */
+    bool Interlace;                   /* Sequential/Interlaced lines. */
+    ColorMapObject *ColorMap;         /* The local color map */
 } GifImageDesc;
 
 typedef struct ExtensionBlock {
     int ByteCount;
-    GifByteType *Bytes; /* on malloc(3) heap */
-    int Function;       /* The block function code */
-#define CONTINUE_EXT_FUNC_CODE    0x00    /* continuation subblock */
-#define COMMENT_EXT_FUNC_CODE     0xfe    /* comment */
-#define GRAPHICS_EXT_FUNC_CODE    0xf9    /* graphics control (GIF89) */
-#define PLAINTEXT_EXT_FUNC_CODE   0x01    /* plaintext */
-#define APPLICATION_EXT_FUNC_CODE 0xff    /* application block (GIF89) */
+    GifByteType *Bytes;            /* on malloc(3) heap */
+    int Function;                  /* The block function code */
+#define CONTINUE_EXT_FUNC_CODE 0x00    /* continuation subblock */
+#define COMMENT_EXT_FUNC_CODE 0xfe     /* comment */
+#define GRAPHICS_EXT_FUNC_CODE 0xf9    /* graphics control (GIF89) */
+#define PLAINTEXT_EXT_FUNC_CODE 0x01   /* plaintext */
+#define APPLICATION_EXT_FUNC_CODE 0xff /* application block (GIF89) */
 } ExtensionBlock;
 
 typedef struct SavedImage {
@@ -103,22 +95,22 @@ typedef struct SavedImage {
 } SavedImage;
 
 typedef struct GifFileType {
-    GifWord SWidth, SHeight;         /* Size of virtual canvas */
-    GifWord SColorResolution;        /* How many colors can we generate? */
-    GifWord SBackGroundColor;        /* Background color for virtual canvas */
-    GifByteType AspectByte;          /* Used to compute pixel aspect ratio */
-    ColorMapObject *SColorMap;       /* Global colormap, NULL if nonexistent. */
-    int ImageCount;                  /* Number of current image (both APIs) */
-    GifImageDesc Image;              /* Current image (low-level API) */
-    SavedImage *SavedImages;         /* Image sequence (high-level API) */
-    int ExtensionBlockCount;         /* Count extensions past last image */
+    GifWord SWidth, SHeight;   /* Size of virtual canvas */
+    GifWord SColorResolution;  /* How many colors can we generate? */
+    GifWord SBackGroundColor;  /* Background color for virtual canvas */
+    GifByteType AspectByte;    /* Used to compute pixel aspect ratio */
+    ColorMapObject *SColorMap; /* Global colormap, NULL if nonexistent. */
+    int ImageCount;            /* Number of current image (both APIs) */
+    GifImageDesc Image;        /* Current image (low-level API) */
+    SavedImage *SavedImages;   /* Image sequence (high-level API) */
+    int ExtensionBlockCount;   /* Count extensions past last image */
     ExtensionBlock *ExtensionBlocks; /* Extensions past last image */
     int Error;                       /* Last error condition reported */
     void *UserData;                  /* hook to attach user data (TVT) */
     void *Private;                   /* Don't mess with this! */
 } GifFileType;
 
-#define GIF_ASPECT_RATIO(n)    ((n)+15.0/64.0)
+#define GIF_ASPECT_RATIO(n) ((n) + 15.0 / 64.0)
 
 typedef enum {
     UNDEFINED_RECORD_TYPE,
@@ -129,12 +121,12 @@ typedef enum {
 } GifRecordType;
 
 /* func type to read gif data from arbitrary sources (TVT) */
-typedef int (*InputFunc) (GifFileType *, GifByteType *, int);
+typedef int (*InputFunc)(GifFileType *, GifByteType *, int);
 
 /* func type to write gif data to arbitrary targets.
  * Returns count of bytes written. (MRB)
  */
-typedef int (*OutputFunc) (GifFileType *, const GifByteType *, int);
+typedef int (*OutputFunc)(GifFileType *, const GifByteType *, int);
 
 /******************************************************************************
  GIF89 structures
@@ -142,14 +134,14 @@ typedef int (*OutputFunc) (GifFileType *, const GifByteType *, int);
 
 typedef struct GraphicsControlBlock {
     int DisposalMode;
-#define DISPOSAL_UNSPECIFIED      0       /* No disposal specified. */
-#define DISPOSE_DO_NOT            1       /* Leave image in place */
-#define DISPOSE_BACKGROUND        2       /* Set area too background color */
-#define DISPOSE_PREVIOUS          3       /* Restore to previous content */
-    bool UserInputFlag;      /* User confirmation required before disposal */
-    int DelayTime;           /* pre-display delay in 0.01sec units */
-    int TransparentColor;    /* Palette index for transparency, -1 if none */
-#define NO_TRANSPARENT_COLOR    -1
+#define DISPOSAL_UNSPECIFIED 0 /* No disposal specified. */
+#define DISPOSE_DO_NOT 1       /* Leave image in place */
+#define DISPOSE_BACKGROUND 2   /* Set area too background color */
+#define DISPOSE_PREVIOUS 3     /* Restore to previous content */
+    bool UserInputFlag;    /* User confirmation required before disposal */
+    int DelayTime;         /* pre-display delay in 0.01sec units */
+    int TransparentColor;  /* Palette index for transparency, -1 if none */
+#define NO_TRANSPARENT_COLOR -1
 } GraphicsControlBlock;
 
 /******************************************************************************
@@ -161,49 +153,44 @@ GifFileType *EGifOpenFileName(const char *GifFileName,
                               const bool GifTestExistence, int *Error);
 GifFileType *EGifOpenFileHandle(const int GifFileHandle, int *Error);
 GifFileType *EGifOpen(void *userPtr, OutputFunc writeFunc, int *Error);
-int EGifSpew(GifFileType * GifFile);
+int EGifSpew(GifFileType *GifFile);
 const char *EGifGetGifVersion(GifFileType *GifFile); /* new in 5.x */
 int EGifCloseFile(GifFileType *GifFile, int *ErrorCode);
 
-#define E_GIF_SUCCEEDED          0
-#define E_GIF_ERR_OPEN_FAILED    1    /* And EGif possible errors. */
-#define E_GIF_ERR_WRITE_FAILED   2
-#define E_GIF_ERR_HAS_SCRN_DSCR  3
-#define E_GIF_ERR_HAS_IMAG_DSCR  4
-#define E_GIF_ERR_NO_COLOR_MAP   5
-#define E_GIF_ERR_DATA_TOO_BIG   6
+#define E_GIF_SUCCEEDED 0
+#define E_GIF_ERR_OPEN_FAILED 1 /* And EGif possible errors. */
+#define E_GIF_ERR_WRITE_FAILED 2
+#define E_GIF_ERR_HAS_SCRN_DSCR 3
+#define E_GIF_ERR_HAS_IMAG_DSCR 4
+#define E_GIF_ERR_NO_COLOR_MAP 5
+#define E_GIF_ERR_DATA_TOO_BIG 6
 #define E_GIF_ERR_NOT_ENOUGH_MEM 7
-#define E_GIF_ERR_DISK_IS_FULL   8
-#define E_GIF_ERR_CLOSE_FAILED   9
-#define E_GIF_ERR_NOT_WRITEABLE  10
+#define E_GIF_ERR_DISK_IS_FULL 8
+#define E_GIF_ERR_CLOSE_FAILED 9
+#define E_GIF_ERR_NOT_WRITEABLE 10
 
 /* These are legacy.  You probably do not want to call them directly */
-int EGifPutScreenDesc(GifFileType *GifFile,
-                      const int GifWidth, const int GifHeight,
-                      const int GifColorRes,
+int EGifPutScreenDesc(GifFileType *GifFile, const int GifWidth,
+                      const int GifHeight, const int GifColorRes,
                       const int GifBackGround,
                       const ColorMapObject *GifColorMap);
-int EGifPutImageDesc(GifFileType *GifFile,
-                     const int GifLeft, const int GifTop,
+int EGifPutImageDesc(GifFileType *GifFile, const int GifLeft, const int GifTop,
                      const int GifWidth, const int GifHeight,
                      const bool GifInterlace,
                      const ColorMapObject *GifColorMap);
 void EGifSetGifVersion(GifFileType *GifFile, const bool gif89);
-int EGifPutLine(GifFileType *GifFile, GifPixelType *GifLine,
-                int GifLineLen);
+int EGifPutLine(GifFileType *GifFile, GifPixelType *GifLine, int GifLineLen);
 int EGifPutPixel(GifFileType *GifFile, const GifPixelType GifPixel);
 int EGifPutComment(GifFileType *GifFile, const char *GifComment);
 int EGifPutExtensionLeader(GifFileType *GifFile, const int GifExtCode);
-int EGifPutExtensionBlock(GifFileType *GifFile,
-                         const int GifExtLen, const void *GifExtension);
+int EGifPutExtensionBlock(GifFileType *GifFile, const int GifExtLen,
+                          const void *GifExtension);
 int EGifPutExtensionTrailer(GifFileType *GifFile);
 int EGifPutExtension(GifFileType *GifFile, const int GifExtCode,
-                     const int GifExtLen,
-                     const void *GifExtension);
+                     const int GifExtLen, const void *GifExtension);
 int EGifPutCode(GifFileType *GifFile, int GifCodeSize,
                 const GifByteType *GifCodeBlock);
-int EGifPutCodeNext(GifFileType *GifFile,
-                    const GifByteType *GifCodeBlock);
+int EGifPutCodeNext(GifFileType *GifFile, const GifByteType *GifCodeBlock);
 
 /******************************************************************************
  GIF decoding routines
@@ -212,24 +199,25 @@ int EGifPutCodeNext(GifFileType *GifFile,
 /* Main entry points */
 GifFileType *DGifOpenFileName(const char *GifFileName, int *Error);
 GifFileType *DGifOpenFileHandle(int GifFileHandle, int *Error);
-int DGifSlurp(GifFileType * GifFile);
-GifFileType *DGifOpen(void *userPtr, InputFunc readFunc, int *Error);    /* new one (TVT) */
-    int DGifCloseFile(GifFileType * GifFile, int *ErrorCode);
-
-#define D_GIF_SUCCEEDED          0
-#define D_GIF_ERR_OPEN_FAILED    101    /* And DGif possible errors. */
-#define D_GIF_ERR_READ_FAILED    102
-#define D_GIF_ERR_NOT_GIF_FILE   103
-#define D_GIF_ERR_NO_SCRN_DSCR   104
-#define D_GIF_ERR_NO_IMAG_DSCR   105
-#define D_GIF_ERR_NO_COLOR_MAP   106
-#define D_GIF_ERR_WRONG_RECORD   107
-#define D_GIF_ERR_DATA_TOO_BIG   108
+int DGifSlurp(GifFileType *GifFile);
+GifFileType *DGifOpen(void *userPtr, InputFunc readFunc,
+                      int *Error); /* new one (TVT) */
+int DGifCloseFile(GifFileType *GifFile, int *ErrorCode);
+
+#define D_GIF_SUCCEEDED 0
+#define D_GIF_ERR_OPEN_FAILED 101 /* And DGif possible errors. */
+#define D_GIF_ERR_READ_FAILED 102
+#define D_GIF_ERR_NOT_GIF_FILE 103
+#define D_GIF_ERR_NO_SCRN_DSCR 104
+#define D_GIF_ERR_NO_IMAG_DSCR 105
+#define D_GIF_ERR_NO_COLOR_MAP 106
+#define D_GIF_ERR_WRONG_RECORD 107
+#define D_GIF_ERR_DATA_TOO_BIG 108
 #define D_GIF_ERR_NOT_ENOUGH_MEM 109
-#define D_GIF_ERR_CLOSE_FAILED   110
-#define D_GIF_ERR_NOT_READABLE   111
-#define D_GIF_ERR_IMAGE_DEFECT   112
-#define D_GIF_ERR_EOF_TOO_SOON   113
+#define D_GIF_ERR_CLOSE_FAILED 110
+#define D_GIF_ERR_NOT_READABLE 111
+#define D_GIF_ERR_IMAGE_DEFECT 112
+#define D_GIF_ERR_EOF_TOO_SOON 113
 
 /* These are legacy.  You probably do not want to call them directly */
 int DGifGetScreenDesc(GifFileType *GifFile);
@@ -247,11 +235,10 @@ int DGifGetCodeNext(GifFileType *GifFile, GifByteType **GifCodeBlock);
 int DGifGetLZCodes(GifFileType *GifFile, int *GifCode);
 const char *DGifGetGifVersion(GifFileType *GifFile);
 
-
 /******************************************************************************
  Error handling and reporting.
 ******************************************************************************/
-extern const char *GifErrorString(int ErrorCode);     /* new in 2012 - ESR */
+extern const char *GifErrorString(int ErrorCode); /* new in 2012 - ESR */
 
 /*****************************************************************************
  Everything below this point is new after version 1.2, supporting `slurp
@@ -263,26 +250,26 @@ extern const char *GifErrorString(int ErrorCode);     /* new in 2012 - ESR */
 ******************************************************************************/
 
 extern ColorMapObject *GifMakeMapObject(int ColorCount,
-                                     const GifColorType *ColorMap);
+                                        const GifColorType *ColorMap);
 extern void GifFreeMapObject(ColorMapObject *Object);
 extern ColorMapObject *GifUnionColorMap(const ColorMapObject *ColorIn1,
-                                     const ColorMapObject *ColorIn2,
-                                     GifPixelType ColorTransIn2[]);
+                                        const ColorMapObject *ColorIn2,
+                                        GifPixelType ColorTransIn2[]);
 extern int GifBitSize(int n);
 
 /******************************************************************************
  Support for the in-core structures allocation (slurp mode).
 ******************************************************************************/
 
-extern void GifApplyTranslation(SavedImage *Image, GifPixelType Translation[]);
+extern void GifApplyTranslation(SavedImage *Image,
+                                const GifPixelType Translation[]);
 extern int GifAddExtensionBlock(int *ExtensionBlock_Count,
-                                ExtensionBlock **ExtensionBlocks,
-                                int Function,
+                                ExtensionBlock **ExtensionBlocks, int Function,
                                 unsigned int Len, unsigned char ExtData[]);
 extern void GifFreeExtensions(int *ExtensionBlock_Count,
                               ExtensionBlock **ExtensionBlocks);
 extern SavedImage *GifMakeSavedImage(GifFileType *GifFile,
-                                  const SavedImage *CopyFrom);
+                                     const SavedImage *CopyFrom);
 extern void GifFreeSavedImages(GifFileType *GifFile);
 
 /******************************************************************************
@@ -295,37 +282,31 @@ int DGifExtensionToGCB(const size_t GifExtensionLength,
 size_t EGifGCBToExtension(const GraphicsControlBlock *GCB,
                           GifByteType *GifExtension);
 
-int DGifSavedExtensionToGCB(GifFileType *GifFile,
-                            int ImageIndex,
+int DGifSavedExtensionToGCB(GifFileType *GifFile, int ImageIndex,
                             GraphicsControlBlock *GCB);
 int EGifGCBToSavedExtension(const GraphicsControlBlock *GCB,
-                            GifFileType *GifFile,
-                            int ImageIndex);
+                            GifFileType *GifFile, int ImageIndex);
 
 /******************************************************************************
  The library's internal utility font
 ******************************************************************************/
 
-#define GIF_FONT_WIDTH  8
+#define GIF_FONT_WIDTH 8
 #define GIF_FONT_HEIGHT 8
 extern const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH];
 
-extern void GifDrawText8x8(SavedImage *Image,
-                     const int x, const int y,
-                     const char *legend, const int color);
+extern void GifDrawText8x8(SavedImage *Image, const int x, const int y,
+                           const char *legend, const int color);
 
-extern void GifDrawBox(SavedImage *Image,
-                    const int x, const int y,
-                    const int w, const int d, const int color);
+extern void GifDrawBox(SavedImage *Image, const int x, const int y, const int w,
+                       const int d, const int color);
 
-extern void GifDrawRectangle(SavedImage *Image,
-                   const int x, const int y,
-                   const int w, const int d, const int color);
+extern void GifDrawRectangle(SavedImage *Image, const int x, const int y,
+                             const int w, const int d, const int color);
 
-extern void GifDrawBoxedText8x8(SavedImage *Image,
-                          const int x, const int y,
-                          const char *legend,
-                          const int border, const int bg, const int fg);
+extern void GifDrawBoxedText8x8(SavedImage *Image, const int x, const int y,
+                                const char *legend, const int border,
+                                const int bg, const int fg);
 
 #ifdef __cplusplus
 }
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib_private.h b/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib_private.h
index 4f832676ffc..f905e0d7b48 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib_private.h
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/gif_lib_private.h
@@ -33,52 +33,54 @@ SPDX-License-Identifier: MIT
 #ifndef _GIF_LIB_PRIVATE_H
 #define _GIF_LIB_PRIVATE_H
 
-#include "gif_lib.h"
 #include "gif_hash.h"
+#include "gif_lib.h"
 
 #ifndef SIZE_MAX
-    #define SIZE_MAX     UINTPTR_MAX
+#define SIZE_MAX UINTPTR_MAX
 #endif
 
-#define EXTENSION_INTRODUCER      0x21
-#define DESCRIPTOR_INTRODUCER     0x2c
-#define TERMINATOR_INTRODUCER     0x3b
+#define EXTENSION_INTRODUCER 0x21
+#define DESCRIPTOR_INTRODUCER 0x2c
+#define TERMINATOR_INTRODUCER 0x3b
 
-#define LZ_MAX_CODE         4095    /* Biggest code possible in 12 bits. */
-#define LZ_BITS             12
+#define LZ_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
+#define LZ_BITS 12
 
-#define FLUSH_OUTPUT        4096    /* Impossible code, to signal flush. */
-#define FIRST_CODE          4097    /* Impossible code, to signal first. */
-#define NO_SUCH_CODE        4098    /* Impossible code, to signal empty. */
+#define FLUSH_OUTPUT 4096 /* Impossible code, to signal flush. */
+#define FIRST_CODE 4097   /* Impossible code, to signal first. */
+#define NO_SUCH_CODE 4098 /* Impossible code, to signal empty. */
 
-#define FILE_STATE_WRITE    0x01
-#define FILE_STATE_SCREEN   0x02
-#define FILE_STATE_IMAGE    0x04
-#define FILE_STATE_READ     0x08
+#define FILE_STATE_WRITE 0x01
+#define FILE_STATE_SCREEN 0x02
+#define FILE_STATE_IMAGE 0x04
+#define FILE_STATE_READ 0x08
 
-#define IS_READABLE(Private)    (Private->FileState & FILE_STATE_READ)
-#define IS_WRITEABLE(Private)   (Private->FileState & FILE_STATE_WRITE)
+#define IS_READABLE(Private) (Private->FileState & FILE_STATE_READ)
+#define IS_WRITEABLE(Private) (Private->FileState & FILE_STATE_WRITE)
 
 typedef struct GifFilePrivateType {
-    GifWord FileState, FileHandle,  /* Where all this data goes to! */
-      BitsPerPixel,     /* Bits per pixel (Codes uses at least this + 1). */
-      ClearCode,   /* The CLEAR LZ code. */
-      EOFCode,     /* The EOF LZ code. */
-      RunningCode, /* The next code algorithm can generate. */
-      RunningBits, /* The number of bits required to represent RunningCode. */
-      MaxCode1,    /* 1 bigger than max. possible code, in RunningBits bits. */
-      LastCode,    /* The code before the current code. */
-      CrntCode,    /* Current algorithm code. */
-      StackPtr,    /* For character stack (see below). */
-      CrntShiftState;    /* Number of bits in CrntShiftDWord. */
-    unsigned long CrntShiftDWord;   /* For bytes decomposition into codes. */
-    unsigned long PixelCount;   /* Number of pixels in image. */
-    FILE *File;    /* File as stream. */
-    InputFunc Read;     /* function to read gif input (TVT) */
-    OutputFunc Write;   /* function to write gif output (MRB) */
-    GifByteType Buf[256];   /* Compressed input is buffered here. */
+    GifWord FileState, FileHandle, /* Where all this data goes to! */
+        BitsPerPixel, /* Bits per pixel (Codes uses at least this + 1). */
+        ClearCode,    /* The CLEAR LZ code. */
+        EOFCode,      /* The EOF LZ code. */
+        RunningCode,  /* The next code algorithm can generate. */
+        RunningBits,  /* The number of bits required to represent
+                         RunningCode. */
+        MaxCode1, /* 1 bigger than max. possible code, in RunningBits bits.
+                   */
+        LastCode, /* The code before the current code. */
+        CrntCode, /* Current algorithm code. */
+        StackPtr, /* For character stack (see below). */
+        CrntShiftState;           /* Number of bits in CrntShiftDWord. */
+    unsigned long CrntShiftDWord; /* For bytes decomposition into codes. */
+    unsigned long PixelCount;     /* Number of pixels in image. */
+    FILE *File;                   /* File as stream. */
+    InputFunc Read;               /* function to read gif input (TVT) */
+    OutputFunc Write;             /* function to write gif output (MRB) */
+    GifByteType Buf[256];         /* Compressed input is buffered here. */
     GifByteType Stack[LZ_MAX_CODE]; /* Decoded pixels are stacked here. */
-    GifByteType Suffix[LZ_MAX_CODE + 1];    /* So we can trace the codes. */
+    GifByteType Suffix[LZ_MAX_CODE + 1]; /* So we can trace the codes. */
     GifPrefixType Prefix[LZ_MAX_CODE + 1];
     GifHashTableType *HashTable;
     bool gif89;
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/gifalloc.c b/src/java.desktop/share/native/libsplashscreen/giflib/gifalloc.c
index 75b74b4fba0..5aef3044558 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/gifalloc.c
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/gifalloc.c
@@ -30,59 +30,59 @@ SPDX-License-Identifier: MIT
 
 ****************************************************************************/
 
-#include 
 #include 
+#include 
 #include 
 
 #include "gif_lib.h"
 #include "gif_lib_private.h"
 
-#define MAX(x, y)    (((x) > (y)) ? (x) : (y))
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
 
 /******************************************************************************
  Miscellaneous utility functions
 ******************************************************************************/
 
 /* return smallest bitfield size n will fit in */
-int
-GifBitSize(int n)
-{
+int GifBitSize(int n) {
     register int i;
 
-    for (i = 1; i <= 8; i++)
-        if ((1 << i) >= n)
+    for (i = 1; i <= 8; i++) {
+        if ((1 << i) >= n) {
             break;
+        }
+    }
     return (i);
 }
 
 /******************************************************************************
-  Color map object functions
+ Color map object functions
 ******************************************************************************/
 
 /*
  * Allocate a color map of given size; initialize with contents of
  * ColorMap if that pointer is non-NULL.
  */
-ColorMapObject *
-GifMakeMapObject(int ColorCount, const GifColorType *ColorMap)
-{
+ColorMapObject *GifMakeMapObject(int ColorCount, const GifColorType *ColorMap) {
     ColorMapObject *Object;
 
     /*** FIXME: Our ColorCount has to be a power of two.  Is it necessary to
-     * make the user know that or should we automatically round up instead? */
+     * make the user know that or should we automatically round up instead?
+     */
     if (ColorCount != (1 << GifBitSize(ColorCount))) {
-        return ((ColorMapObject *) NULL);
+        return ((ColorMapObject *)NULL);
     }
 
     Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
-    if (Object == (ColorMapObject *) NULL) {
-        return ((ColorMapObject *) NULL);
+    if (Object == (ColorMapObject *)NULL) {
+        return ((ColorMapObject *)NULL);
     }
 
-    Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
-    if (Object->Colors == (GifColorType *) NULL) {
+    Object->Colors =
+        (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
+    if (Object->Colors == (GifColorType *)NULL) {
         free(Object);
-        return ((ColorMapObject *) NULL);
+        return ((ColorMapObject *)NULL);
     }
 
     Object->ColorCount = ColorCount;
@@ -90,19 +90,17 @@ GifMakeMapObject(int ColorCount, const GifColorType *ColorMap)
     Object->SortFlag = false;
 
     if (ColorMap != NULL) {
-        memcpy((char *)Object->Colors,
-               (char *)ColorMap, ColorCount * sizeof(GifColorType));
+        memcpy((char *)Object->Colors, (char *)ColorMap,
+               ColorCount * sizeof(GifColorType));
     }
 
     return (Object);
 }
 
 /*******************************************************************************
-Free a color map object
+ Free a color map object
 *******************************************************************************/
-void
-GifFreeMapObject(ColorMapObject *Object)
-{
+void GifFreeMapObject(ColorMapObject *Object) {
     if (Object != NULL) {
         (void)free(Object->Colors);
         (void)free(Object);
@@ -110,17 +108,14 @@ GifFreeMapObject(ColorMapObject *Object)
 }
 
 #ifdef DEBUG
-void
-DumpColorMap(ColorMapObject *Object,
-             FILE * fp)
-{
+void DumpColorMap(ColorMapObject *Object, FILE *fp) {
     if (Object != NULL) {
         int i, j, Len = Object->ColorCount;
 
         for (i = 0; i < Len; i += 4) {
             for (j = 0; j < 4 && j < Len; j++) {
-                (void)fprintf(fp, "%3d: %02x %02x %02x   ", i + j,
-                              Object->Colors[i + j].Red,
+                (void)fprintf(fp, "%3d: %02x %02x %02x   ",
+                              i + j, Object->Colors[i + j].Red,
                               Object->Colors[i + j].Green,
                               Object->Colors[i + j].Blue);
             }
@@ -137,11 +132,9 @@ DumpColorMap(ColorMapObject *Object,
  copied iff they didn't exist before.  ColorTransIn2 maps the old
  ColorIn2 into the ColorUnion color map table./
 *******************************************************************************/
-ColorMapObject *
-GifUnionColorMap(const ColorMapObject *ColorIn1,
-              const ColorMapObject *ColorIn2,
-              GifPixelType ColorTransIn2[])
-{
+ColorMapObject *GifUnionColorMap(const ColorMapObject *ColorIn1,
+                                 const ColorMapObject *ColorIn2,
+                                 GifPixelType ColorTransIn2[]) {
     int i, j, CrntSlot, RoundUpTo, NewGifBitSize;
     ColorMapObject *ColorUnion;
 
@@ -152,17 +145,19 @@ GifUnionColorMap(const ColorMapObject *ColorIn1,
      */
 
     /* Allocate table which will hold the result for sure. */
-    ColorUnion = GifMakeMapObject(MAX(ColorIn1->ColorCount,
-                               ColorIn2->ColorCount) * 2, NULL);
+    ColorUnion = GifMakeMapObject(
+        MAX(ColorIn1->ColorCount, ColorIn2->ColorCount) * 2, NULL);
 
-    if (ColorUnion == NULL)
+    if (ColorUnion == NULL) {
         return (NULL);
+    }
 
     /*
      * Copy ColorIn1 to ColorUnion.
      */
-    for (i = 0; i < ColorIn1->ColorCount; i++)
+    for (i = 0; i < ColorIn1->ColorCount; i++) {
         ColorUnion->Colors[i] = ColorIn1->Colors[i];
+    }
     CrntSlot = ColorIn1->ColorCount;
 
     /*
@@ -172,22 +167,25 @@ GifUnionColorMap(const ColorMapObject *ColorIn1,
      * of table 1.  This is very useful if your display is limited to
      * 16 colors.
      */
-    while (ColorIn1->Colors[CrntSlot - 1].Red == 0
-           && ColorIn1->Colors[CrntSlot - 1].Green == 0
-           && ColorIn1->Colors[CrntSlot - 1].Blue == 0)
+    while (ColorIn1->Colors[CrntSlot - 1].Red == 0 &&
+           ColorIn1->Colors[CrntSlot - 1].Green == 0 &&
+           ColorIn1->Colors[CrntSlot - 1].Blue == 0) {
         CrntSlot--;
+    }
 
     /* Copy ColorIn2 to ColorUnion (use old colors if they exist): */
     for (i = 0; i < ColorIn2->ColorCount && CrntSlot <= 256; i++) {
         /* Let's see if this color already exists: */
-        for (j = 0; j < ColorIn1->ColorCount; j++)
-            if (memcmp (&ColorIn1->Colors[j], &ColorIn2->Colors[i],
-                        sizeof(GifColorType)) == 0)
+        for (j = 0; j < ColorIn1->ColorCount; j++) {
+            if (memcmp(&ColorIn1->Colors[j], &ColorIn2->Colors[i],
+                       sizeof(GifColorType)) == 0) {
                 break;
+            }
+        }
 
-        if (j < ColorIn1->ColorCount)
-            ColorTransIn2[i] = j;    /* color exists in Color1 */
-        else {
+        if (j < ColorIn1->ColorCount) {
+            ColorTransIn2[i] = j; /* color exists in Color1 */
+        } else {
             /* Color is new - copy it to a new slot: */
             ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i];
             ColorTransIn2[i] = CrntSlot++;
@@ -196,7 +194,7 @@ GifUnionColorMap(const ColorMapObject *ColorIn1,
 
     if (CrntSlot > 256) {
         GifFreeMapObject(ColorUnion);
-        return ((ColorMapObject *) NULL);
+        return ((ColorMapObject *)NULL);
     }
 
     NewGifBitSize = GifBitSize(CrntSlot);
@@ -210,16 +208,17 @@ GifUnionColorMap(const ColorMapObject *ColorIn1,
          * We know these slots exist because of the way ColorUnion's
          * start dimension was computed.
          */
-        for (j = CrntSlot; j < RoundUpTo; j++)
+        for (j = CrntSlot; j < RoundUpTo; j++) {
             Map[j].Red = Map[j].Green = Map[j].Blue = 0;
+        }
 
         /* perhaps we can shrink the map? */
         if (RoundUpTo < ColorUnion->ColorCount) {
-            GifColorType *new_map = (GifColorType *)reallocarray(Map,
-                                 RoundUpTo, sizeof(GifColorType));
-            if( new_map == NULL ) {
+            GifColorType *new_map = (GifColorType *)reallocarray(
+                Map, RoundUpTo, sizeof(GifColorType));
+            if (new_map == NULL) {
                 GifFreeMapObject(ColorUnion);
-                return ((ColorMapObject *) NULL);
+                return ((ColorMapObject *)NULL);
             }
             ColorUnion->Colors = new_map;
         }
@@ -234,49 +233,49 @@ GifUnionColorMap(const ColorMapObject *ColorIn1,
 /*******************************************************************************
  Apply a given color translation to the raster bits of an image
 *******************************************************************************/
-void
-GifApplyTranslation(SavedImage *Image, GifPixelType Translation[])
-{
+void GifApplyTranslation(SavedImage *Image, const GifPixelType Translation[]) {
     register int i;
-    register int RasterSize = Image->ImageDesc.Height * Image->ImageDesc.Width;
+    register int RasterSize =
+        Image->ImageDesc.Height * Image->ImageDesc.Width;
 
-    for (i = 0; i < RasterSize; i++)
+    for (i = 0; i < RasterSize; i++) {
         Image->RasterBits[i] = Translation[Image->RasterBits[i]];
+    }
 }
 
 /******************************************************************************
  Extension record functions
 ******************************************************************************/
-int
-GifAddExtensionBlock(int *ExtensionBlockCount,
-                     ExtensionBlock **ExtensionBlocks,
-                     int Function,
-                     unsigned int Len,
-                     unsigned char ExtData[])
-{
+int GifAddExtensionBlock(int *ExtensionBlockCount,
+                         ExtensionBlock **ExtensionBlocks, int Function,
+                         unsigned int Len, unsigned char ExtData[]) {
     ExtensionBlock *ep;
 
-    if (*ExtensionBlocks == NULL)
-        *ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
-    else {
-        ExtensionBlock* ep_new = (ExtensionBlock *)reallocarray
-                                      (*ExtensionBlocks, (*ExtensionBlockCount + 1),
-                                      sizeof(ExtensionBlock));
-        if( ep_new == NULL )
+    if (*ExtensionBlocks == NULL) {
+        *ExtensionBlocks =
+            (ExtensionBlock *)malloc(sizeof(ExtensionBlock));
+    } else {
+        ExtensionBlock *ep_new = (ExtensionBlock *)reallocarray(
+            *ExtensionBlocks, (*ExtensionBlockCount + 1),
+            sizeof(ExtensionBlock));
+        if (ep_new == NULL) {
             return (GIF_ERROR);
+        }
         *ExtensionBlocks = ep_new;
     }
 
-    if (*ExtensionBlocks == NULL)
+    if (*ExtensionBlocks == NULL) {
         return (GIF_ERROR);
+    }
 
     ep = &(*ExtensionBlocks)[(*ExtensionBlockCount)++];
 
     ep->Function = Function;
-    ep->ByteCount=Len;
+    ep->ByteCount = Len;
     ep->Bytes = (GifByteType *)malloc(ep->ByteCount);
-    if (ep->Bytes == NULL)
+    if (ep->Bytes == NULL) {
         return (GIF_ERROR);
+    }
 
     if (ExtData != NULL) {
         memcpy(ep->Bytes, ExtData, Len);
@@ -285,38 +284,36 @@ GifAddExtensionBlock(int *ExtensionBlockCount,
     return (GIF_OK);
 }
 
-void
-GifFreeExtensions(int *ExtensionBlockCount,
-                  ExtensionBlock **ExtensionBlocks)
-{
+void GifFreeExtensions(int *ExtensionBlockCount,
+                       ExtensionBlock **ExtensionBlocks) {
     ExtensionBlock *ep;
 
-    if (*ExtensionBlocks == NULL)
+    if (*ExtensionBlocks == NULL) {
         return;
+    }
 
     for (ep = *ExtensionBlocks;
-         ep < (*ExtensionBlocks + *ExtensionBlockCount);
-         ep++)
+         ep < (*ExtensionBlocks + *ExtensionBlockCount); ep++) {
         (void)free((char *)ep->Bytes);
+    }
     (void)free((char *)*ExtensionBlocks);
     *ExtensionBlocks = NULL;
     *ExtensionBlockCount = 0;
 }
 
 /******************************************************************************
- Image block allocation functions
+   Image block allocation functions
 ******************************************************************************/
 
 /* Private Function:
  * Frees the last image in the GifFile->SavedImages array
  */
-void
-FreeLastSavedImage(GifFileType *GifFile)
-{
+void FreeLastSavedImage(GifFileType *GifFile) {
     SavedImage *sp;
 
-    if ((GifFile == NULL) || (GifFile->SavedImages == NULL))
+    if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
         return;
+    }
 
     /* Remove one SavedImage from the GifFile */
     GifFile->ImageCount--;
@@ -329,54 +326,58 @@ FreeLastSavedImage(GifFileType *GifFile)
     }
 
     /* Deallocate the image data */
-    if (sp->RasterBits != NULL)
+    if (sp->RasterBits != NULL) {
         free((char *)sp->RasterBits);
+    }
 
     /* Deallocate any extensions */
     GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
 
     /*** FIXME: We could realloc the GifFile->SavedImages structure but is
      * there a point to it? Saves some memory but we'd have to do it every
-     * time.  If this is used in GifFreeSavedImages then it would be inefficient
-     * (The whole array is going to be deallocated.)  If we just use it when
-     * we want to free the last Image it's convenient to do it here.
+     * time.  If this is used in GifFreeSavedImages then it would be
+     * inefficient (The whole array is going to be deallocated.)  If we just
+     * use it when we want to free the last Image it's convenient to do it
+     * here.
      */
 }
 
 /*
  * Append an image block to the SavedImages array
  */
-SavedImage *
-GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom)
-{
-    if (GifFile->SavedImages == NULL)
+SavedImage *GifMakeSavedImage(GifFileType *GifFile,
+                              const SavedImage *CopyFrom) {
+    // cppcheck-suppress ctunullpointer
+    if (GifFile->SavedImages == NULL) {
         GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
-    else {
-        SavedImage* newSavedImages = (SavedImage *)reallocarray(GifFile->SavedImages,
-                               (GifFile->ImageCount + 1), sizeof(SavedImage));
-        if( newSavedImages == NULL)
+    } else {
+        SavedImage *newSavedImages = (SavedImage *)reallocarray(
+            GifFile->SavedImages, (GifFile->ImageCount + 1),
+            sizeof(SavedImage));
+        if (newSavedImages == NULL) {
             return ((SavedImage *)NULL);
+        }
         GifFile->SavedImages = newSavedImages;
     }
-    if (GifFile->SavedImages == NULL)
+    if (GifFile->SavedImages == NULL) {
         return ((SavedImage *)NULL);
-    else {
+    } else {
         SavedImage *sp = &GifFile->SavedImages[GifFile->ImageCount++];
 
         if (CopyFrom != NULL) {
             memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
 
             /*
-             * Make our own allocated copies of the heap fields in the
-             * copied record.  This guards against potential aliasing
-             * problems.
+             * Make our own allocated copies of the heap fields in
+             * the copied record.  This guards against potential
+             * aliasing problems.
              */
 
             /* first, the local color map */
             if (CopyFrom->ImageDesc.ColorMap != NULL) {
                 sp->ImageDesc.ColorMap = GifMakeMapObject(
-                                         CopyFrom->ImageDesc.ColorMap->ColorCount,
-                                         CopyFrom->ImageDesc.ColorMap->Colors);
+                    CopyFrom->ImageDesc.ColorMap->ColorCount,
+                    CopyFrom->ImageDesc.ColorMap->Colors);
                 if (sp->ImageDesc.ColorMap == NULL) {
                     FreeLastSavedImage(GifFile);
                     return (SavedImage *)(NULL);
@@ -384,32 +385,36 @@ GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom)
             }
 
             /* next, the raster */
-            sp->RasterBits = (unsigned char *)reallocarray(NULL,
-                                                  (CopyFrom->ImageDesc.Height *
-                                                  CopyFrom->ImageDesc.Width),
-                                                  sizeof(GifPixelType));
+            sp->RasterBits = (unsigned char *)reallocarray(
+                NULL,
+                (CopyFrom->ImageDesc.Height *
+                 CopyFrom->ImageDesc.Width),
+                sizeof(GifPixelType));
             if (sp->RasterBits == NULL) {
                 FreeLastSavedImage(GifFile);
                 return (SavedImage *)(NULL);
             }
             memcpy(sp->RasterBits, CopyFrom->RasterBits,
-                   sizeof(GifPixelType) * CopyFrom->ImageDesc.Height *
-                   CopyFrom->ImageDesc.Width);
+                   sizeof(GifPixelType) *
+                       CopyFrom->ImageDesc.Height *
+                       CopyFrom->ImageDesc.Width);
 
             /* finally, the extension blocks */
             if (CopyFrom->ExtensionBlocks != NULL) {
-                sp->ExtensionBlocks = (ExtensionBlock *)reallocarray(NULL,
-                                      CopyFrom->ExtensionBlockCount,
-                                      sizeof(ExtensionBlock));
+                sp->ExtensionBlocks =
+                    (ExtensionBlock *)reallocarray(
+                        NULL, CopyFrom->ExtensionBlockCount,
+                        sizeof(ExtensionBlock));
                 if (sp->ExtensionBlocks == NULL) {
                     FreeLastSavedImage(GifFile);
                     return (SavedImage *)(NULL);
                 }
-                memcpy(sp->ExtensionBlocks, CopyFrom->ExtensionBlocks,
-                       sizeof(ExtensionBlock) * CopyFrom->ExtensionBlockCount);
+                memcpy(sp->ExtensionBlocks,
+                       CopyFrom->ExtensionBlocks,
+                       sizeof(ExtensionBlock) *
+                           CopyFrom->ExtensionBlockCount);
             }
-        }
-        else {
+        } else {
             memset((char *)sp, '\0', sizeof(SavedImage));
         }
 
@@ -417,9 +422,7 @@ GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom)
     }
 }
 
-void
-GifFreeSavedImages(GifFileType *GifFile)
-{
+void GifFreeSavedImages(GifFileType *GifFile) {
     SavedImage *sp;
 
     if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
@@ -432,10 +435,12 @@ GifFreeSavedImages(GifFileType *GifFile)
             sp->ImageDesc.ColorMap = NULL;
         }
 
-        if (sp->RasterBits != NULL)
+        if (sp->RasterBits != NULL) {
             free((char *)sp->RasterBits);
+        }
 
-        GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
+        GifFreeExtensions(&sp->ExtensionBlockCount,
+                          &sp->ExtensionBlocks);
     }
     free((char *)GifFile->SavedImages);
     GifFile->SavedImages = NULL;
diff --git a/src/java.desktop/share/native/libsplashscreen/giflib/openbsd-reallocarray.c b/src/java.desktop/share/native/libsplashscreen/giflib/openbsd-reallocarray.c
index 452df69d7cd..7420af674c5 100644
--- a/src/java.desktop/share/native/libsplashscreen/giflib/openbsd-reallocarray.c
+++ b/src/java.desktop/share/native/libsplashscreen/giflib/openbsd-reallocarray.c
@@ -28,24 +28,22 @@
  * SPDX-License-Identifier: MIT
  */
 
-#include 
 #include 
 #include 
 #include 
+#include 
 
 #ifndef SIZE_MAX
-    #define SIZE_MAX     UINTPTR_MAX
+#define SIZE_MAX UINTPTR_MAX
 #endif
 
 /*
  * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
  * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
  */
-#define MUL_NO_OVERFLOW    ((size_t)1 << (sizeof(size_t) * 4))
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
 
-void *
-openbsd_reallocarray(void *optr, size_t nmemb, size_t size)
-{
+void *openbsd_reallocarray(void *optr, size_t nmemb, size_t size) {
     if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
         nmemb > 0 && SIZE_MAX / nmemb < size) {
         errno = ENOMEM;
@@ -93,7 +91,8 @@ openbsd_reallocarray(void *optr, size_t nmemb, size_t size)
      * fuzzing on one platform may not detect zero-size allocation
      * problems on other platforms.
      */
-    if (size == 0 || nmemb == 0)
+    if (size == 0 || nmemb == 0) {
         return NULL;
+    }
     return realloc(optr, size * nmemb);
 }
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
index 2d8c585c0e7..441b57ecf1a 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
@@ -6129,6 +6129,73 @@ Version 1.6.40 [June 21, 2023]
   Updated the configurations and the scripts for continuous integration.
   Cleaned up the code, the build scripts, and the documentation.
 
+Version 1.6.41 [January 24, 2024]
+  Added SIMD-optimized code for the LoongArch LSX hardware.
+    (Contributed by GuXiWei, JinBo and ZhangLixia)
+  Fixed the run-time discovery of MIPS MSA hardware.
+    (Contributed by Sui Jingfeng)
+  Fixed an off-by-one error in the function png_do_check_palette_indexes(),
+    which failed to recognize errors that might have existed in the first
+    column of a broken palette-encoded image. This was a benign regression
+    accidentally introduced in libpng-1.6.33. No pixel was harmed.
+    (Contributed by Adam Richter; reviewed by John Bowler)
+  Fixed, improved and modernized the contrib/pngminus programs, i.e.,
+    png2pnm.c and pnm2png.c
+  Removed old and peculiar portability hacks that were meant to silence
+    warnings issued by gcc version 7.1 alone.
+    (Contributed by John Bowler)
+  Fixed and modernized the CMake file, and raised the minimum required
+    CMake version from 3.1 to 3.6.
+    (Contributed by Clinton Ingram, Timothy Lyanguzov, Tyler Kropp, et al.)
+  Allowed the configure script to disable the building of auxiliary tools
+    and tests, thus catching up with the CMake file.
+    (Contributed by Carlo Bramini)
+  Fixed a build issue on Mac.
+    (Contributed by Zixu Wang)
+  Moved the Autoconf macro files to scripts/autoconf.
+  Moved the CMake files (except for the main CMakeLists.txt) to
+    scripts/cmake and moved the list of their contributing authors to
+    scripts/cmake/AUTHORS.md
+  Updated the CI configurations and scripts.
+  Relicensed the CI scripts to the MIT License.
+  Improved the test coverage.
+    (Contributed by John Bowler)
+
+Version 1.6.42 [January 29, 2024]
+  Fixed the implementation of the macro function png_check_sig().
+    This was an API regression, introduced in libpng-1.6.41.
+    (Reported by Matthieu Darbois)
+  Fixed and updated the libpng manual.
+
+Version 1.6.43 [February 23, 2024]
+  Fixed the row width check in png_check_IHDR().
+    This corrected a bug that was specific to the 16-bit platforms,
+    and removed a spurious compiler warning from the 64-bit builds.
+    (Reported by Jacek Caban; fixed by John Bowler)
+  Added eXIf chunk support to the push-mode reader in pngpread.c.
+    (Contributed by Chris Blume)
+  Added contrib/pngexif for the benefit of the users who would like
+    to inspect the content of eXIf chunks.
+  Added contrib/conftest/basic.dfa, a basic build-time configuration.
+    (Contributed by John Bowler)
+  Fixed a preprocessor condition in pngread.c that broke build-time
+    configurations like contrib/conftest/pngcp.dfa.
+    (Contributed by John Bowler)
+  Added CMake build support for LoongArch LSX.
+    (Contributed by GuXiWei)
+  Fixed a CMake build error that occurred under a peculiar state of the
+    dependency tree. This was a regression introduced in libpng-1.6.41.
+    (Contributed by Dan Rosser)
+  Marked the installed libpng headers as system headers in CMake.
+    (Contributed by Benjamin Buch)
+  Updated the build support for RISCOS.
+    (Contributed by Cameron Cawley)
+  Updated the makefiles to allow cross-platform builds to initialize
+    conventional make variables like AR and ARFLAGS.
+  Added various improvements to the CI scripts in areas like version
+    consistency verification and text linting.
+  Added version consistency verification to pngtest.c also.
+
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
 Subscription is required; visit
 https://lists.sourceforge.net/lists/listinfo/png-mng-implement
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/LICENSE b/src/java.desktop/share/native/libsplashscreen/libpng/LICENSE
index 086d1c2fda6..25f298f0fcf 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/LICENSE
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/LICENSE
@@ -4,8 +4,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
 PNG Reference Library License version 2
 ---------------------------------------
 
- * Copyright (c) 1995-2023 The PNG Reference Library Authors.
- * Copyright (c) 2018-2023 Cosmin Truta.
+ * Copyright (c) 1995-2024 The PNG Reference Library Authors.
+ * Copyright (c) 2018-2024 Cosmin Truta.
  * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
  * Copyright (c) 1996-1997 Andreas Dilger.
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/README b/src/java.desktop/share/native/libsplashscreen/libpng/README
index dedd2c1639e..a6ca3ae9f94 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/README
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/README
@@ -1,4 +1,4 @@
-README for libpng version 1.6.40
+README for libpng version 1.6.43
 ================================
 
 See the note about version numbers near the top of `png.h`.
@@ -142,10 +142,11 @@ Files included in this distribution
     pngwrite.c    =>  High-level write functions
     pngwtran.c    =>  Write data transformations
     pngwutil.c    =>  Write utility functions
-    arm/          =>  Optimized code for the ARM platform
-    intel/        =>  Optimized code for the INTEL-SSE2 platform
-    mips/         =>  Optimized code for the MIPS platform
-    powerpc/      =>  Optimized code for the PowerPC platform
+    arm/          =>  Optimized code for ARM Neon
+    intel/        =>  Optimized code for INTEL SSE2
+    loongarch/    =>  Optimized code for LoongArch LSX
+    mips/         =>  Optimized code for MIPS MSA and MIPS MMI
+    powerpc/      =>  Optimized code for PowerPC VSX
     ci/           =>  Scripts for continuous integration
     contrib/      =>  External contributions
         arm-neon/     =>  Optimized code for the ARM-NEON platform
@@ -158,6 +159,7 @@ Files included in this distribution
         libtests/     =>  Test programs
         oss-fuzz/     =>  Files used by the OSS-Fuzz project for fuzz-testing
                           libpng
+        pngexif/      =>  Program to inspect the EXIF information in PNG files
         pngminim/     =>  Minimal decoder, encoder, and progressive decoder
                           programs demonstrating the use of pngusr.dfa
         pngminus/     =>  Simple pnm2png and png2pnm programs
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/UPDATING.txt b/src/java.desktop/share/native/libsplashscreen/libpng/UPDATING.txt
index 93c8f5bb703..88200db5d73 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/UPDATING.txt
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/UPDATING.txt
@@ -37,18 +37,21 @@ and instead just tweak the existing one.
 
 First cd into the libpng folder and run the following script.
 
+    shopt -s nullglob
     for f in *.c *.h;
-    do
-      # replace tabs with spaces
-      expand ${f} > ${f}.tmp;
-      mv ${f}.tmp $f;
-
-      # fix line endings to LF
-      sed -i -e 's/\r$//g' ${f};
-
-      # remove trailing spaces
-      sed -i -e 's/[ ]* $//g' ${f};
-    done
+         do
+            # replace tabs with spaces
+            expand ${f} > ${f}.tmp
+            mv ${f}.tmp $f
+
+            # fix line endings to LF
+            sed -e 's/\r$//g' ${f} > ${f}.tmp
+            mv ${f}.tmp $f
+
+            # remove trailing spaces
+            sed -e 's/[ ]* $//g' ${f} > ${f}.tmp
+            mv ${f}.tmp $f
+         done
 
 6) As with all native code, run it through the official build systems, in case
 the updated code trigger any fatal warnings with the official compilers.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.c b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
index 91a92e5f718..232dff876c7 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2023 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -42,27 +42,7 @@
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_40 Your_png_h_is_not_version_1_6_40;
-
-#ifdef __GNUC__
-/* The version tests may need to be added to, but the problem warning has
- * consistently been fixed in GCC versions which obtain wide-spread release.
- * The problem is that many versions of GCC rearrange comparison expressions in
- * the optimizer in such a way that the results of the comparison will change
- * if signed integer overflow occurs.  Such comparisons are not permitted in
- * ANSI C90, however GCC isn't clever enough to work out that that do not occur
- * below in png_ascii_from_fp and png_muldiv, so it produces a warning with
- * -Wextra.  Unfortunately this is highly dependent on the optimizer and the
- * machine architecture so the warning comes and goes unpredictably and is
- * impossible to "fix", even were that a good idea.
- */
-#if __GNUC__ == 7 && __GNUC_MINOR__ == 1
-#define GCC_STRICT_OVERFLOW 1
-#endif /* GNU 7.1.x */
-#endif /* GNU */
-#ifndef GCC_STRICT_OVERFLOW
-#define GCC_STRICT_OVERFLOW 0
-#endif
+typedef png_libpng_version_1_6_43 Your_png_h_is_not_version_1_6_43;
 
 /* Tells libpng that we have already handled the first "num_bytes" bytes
  * of the PNG file signature.  If the PNG data is embedded into another
@@ -101,21 +81,21 @@ png_set_sig_bytes(png_structrp png_ptr, int num_bytes)
 int PNGAPI
 png_sig_cmp(png_const_bytep sig, size_t start, size_t num_to_check)
 {
-   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+   static const png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
 
    if (num_to_check > 8)
       num_to_check = 8;
 
    else if (num_to_check < 1)
-      return (-1);
+      return -1;
 
    if (start > 7)
-      return (-1);
+      return -1;
 
    if (start + num_to_check > 8)
       num_to_check = 8 - start;
 
-   return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check)));
+   return memcmp(&sig[start], &png_signature[start], num_to_check);
 }
 
 #endif /* READ */
@@ -475,7 +455,6 @@ png_info_init_3,(png_infopp ptr_ptr, size_t png_info_struct_size),
    memset(info_ptr, 0, (sizeof *info_ptr));
 }
 
-/* The following API is not called internally */
 void PNGAPI
 png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr,
     int freer, png_uint_32 mask)
@@ -714,9 +693,9 @@ png_voidp PNGAPI
 png_get_io_ptr(png_const_structrp png_ptr)
 {
    if (png_ptr == NULL)
-      return (NULL);
+      return NULL;
 
-   return (png_ptr->io_ptr);
+   return png_ptr->io_ptr;
 }
 
 #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
@@ -780,7 +759,7 @@ png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime)
 
    {
       size_t pos = 0;
-      char number_buf[5]; /* enough for a four-digit year */
+      char number_buf[5] = {0, 0, 0, 0, 0}; /* enough for a four-digit year */
 
 #     define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string))
 #     define APPEND_NUMBER(format, value)\
@@ -843,8 +822,8 @@ png_get_copyright(png_const_structrp png_ptr)
    return PNG_STRING_COPYRIGHT
 #else
    return PNG_STRING_NEWLINE \
-      "libpng version 1.6.40" PNG_STRING_NEWLINE \
-      "Copyright (c) 2018-2023 Cosmin Truta" PNG_STRING_NEWLINE \
+      "libpng version 1.6.43" PNG_STRING_NEWLINE \
+      "Copyright (c) 2018-2024 Cosmin Truta" PNG_STRING_NEWLINE \
       "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
       PNG_STRING_NEWLINE \
       "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
@@ -1005,7 +984,7 @@ png_reset_zstream(png_structrp png_ptr)
       return Z_STREAM_ERROR;
 
    /* WARNING: this resets the window bits to the maximum! */
-   return (inflateReset(&png_ptr->zstream));
+   return inflateReset(&png_ptr->zstream);
 }
 #endif /* READ */
 
@@ -1014,7 +993,7 @@ png_uint_32 PNGAPI
 png_access_version_number(void)
 {
    /* Version of *.c files used when building libpng */
-   return((png_uint_32)PNG_LIBPNG_VER);
+   return (png_uint_32)PNG_LIBPNG_VER;
 }
 
 #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
@@ -1870,14 +1849,14 @@ png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,
    }
 #  ifdef PNG_WARNINGS_SUPPORTED
    else
-      {
-         char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114 */
+   {
+      char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114 */
 
-         pos = png_safecat(message, (sizeof message), pos,
-             png_format_number(number, number+(sizeof number),
-             PNG_NUMBER_FORMAT_x, value));
-         pos = png_safecat(message, (sizeof message), pos, "h: "); /* +2 = 116 */
-      }
+      pos = png_safecat(message, (sizeof message), pos,
+          png_format_number(number, number+(sizeof number),
+          PNG_NUMBER_FORMAT_x, value));
+      pos = png_safecat(message, (sizeof message), pos, "h: "); /* +2 = 116 */
+   }
 #  endif
    /* The 'reason' is an arbitrary message, allow +79 maximum 195 */
    pos = png_safecat(message, (sizeof message), pos, reason);
@@ -2560,17 +2539,6 @@ png_colorspace_set_rgb_coefficients(png_structrp png_ptr)
 
 #endif /* COLORSPACE */
 
-#ifdef __GNUC__
-/* This exists solely to work round a warning from GNU C. */
-static int /* PRIVATE */
-png_gt(size_t a, size_t b)
-{
-   return a > b;
-}
-#else
-#   define png_gt(a,b) ((a) > (b))
-#endif
-
 void /* PRIVATE */
 png_check_IHDR(png_const_structrp png_ptr,
     png_uint_32 width, png_uint_32 height, int bit_depth,
@@ -2592,8 +2560,16 @@ png_check_IHDR(png_const_structrp png_ptr,
       error = 1;
    }
 
-   if (png_gt(((width + 7) & (~7U)),
-       ((PNG_SIZE_MAX
+   /* The bit mask on the first line below must be at least as big as a
+    * png_uint_32.  "~7U" is not adequate on 16-bit systems because it will
+    * be an unsigned 16-bit value.  Casting to (png_alloc_size_t) makes the
+    * type of the result at least as bit (in bits) as the RHS of the > operator
+    * which also avoids a common warning on 64-bit systems that the comparison
+    * of (png_uint_32) against the constant value on the RHS will always be
+    * false.
+    */
+   if (((width + 7) & ~(png_alloc_size_t)7) >
+       (((PNG_SIZE_MAX
            - 48        /* big_row_buf hack */
            - 1)        /* filter byte */
            / 8)        /* 8-byte RGBA pixels */
@@ -2919,14 +2895,6 @@ png_pow10(int power)
 /* Function to format a floating point value in ASCII with a given
  * precision.
  */
-#if GCC_STRICT_OVERFLOW
-#pragma GCC diagnostic push
-/* The problem arises below with exp_b10, which can never overflow because it
- * comes, originally, from frexp and is therefore limited to a range which is
- * typically +/-710 (log2(DBL_MAX)/log2(DBL_MIN)).
- */
-#pragma GCC diagnostic warning "-Wstrict-overflow=2"
-#endif /* GCC_STRICT_OVERFLOW */
 void /* PRIVATE */
 png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size,
     double fp, unsigned int precision)
@@ -3248,10 +3216,6 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size,
    /* Here on buffer too small. */
    png_error(png_ptr, "ASCII conversion buffer too small");
 }
-#if GCC_STRICT_OVERFLOW
-#pragma GCC diagnostic pop
-#endif /* GCC_STRICT_OVERFLOW */
-
 #  endif /* FLOATING_POINT */
 
 #  ifdef PNG_FIXED_POINT_SUPPORTED
@@ -3279,7 +3243,7 @@ png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii,
       if (num <= 0x80000000) /* else overflowed */
       {
          unsigned int ndigits = 0, first = 16 /* flag value */;
-         char digits[10];
+         char digits[10] = {0};
 
          while (num)
          {
@@ -3364,15 +3328,6 @@ png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text)
  * the nearest .00001).  Overflow and divide by zero are signalled in
  * the result, a boolean - true on success, false on overflow.
  */
-#if GCC_STRICT_OVERFLOW /* from above */
-/* It is not obvious which comparison below gets optimized in such a way that
- * signed overflow would change the result; looking through the code does not
- * reveal any tests which have the form GCC complains about, so presumably the
- * optimizer is moving an add or subtract into the 'if' somewhere.
- */
-#pragma GCC diagnostic push
-#pragma GCC diagnostic warning "-Wstrict-overflow=2"
-#endif /* GCC_STRICT_OVERFLOW */
 int
 png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
     png_int_32 divisor)
@@ -3487,9 +3442,6 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
 
    return 0;
 }
-#if GCC_STRICT_OVERFLOW
-#pragma GCC diagnostic pop
-#endif /* GCC_STRICT_OVERFLOW */
 #endif /* READ_GAMMA || INCH_CONVERSIONS */
 
 #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.h b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
index 578841c9580..9f61a773c1d 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
@@ -29,9 +29,9 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.40
+ * libpng version 1.6.43
  *
- * Copyright (c) 2018-2023 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -43,7 +43,7 @@
  *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
  *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:
  *     Glenn Randers-Pehrson
- *   libpng versions 1.6.36, December 2018, through 1.6.40, June 2023:
+ *   libpng versions 1.6.36, December 2018, through 1.6.43, February 2024:
  *     Cosmin Truta
  *   See also "Contributing Authors", below.
  */
@@ -55,8 +55,8 @@
  * PNG Reference Library License version 2
  * ---------------------------------------
  *
- *  * Copyright (c) 1995-2023 The PNG Reference Library Authors.
- *  * Copyright (c) 2018-2023 Cosmin Truta.
+ *  * Copyright (c) 1995-2024 The PNG Reference Library Authors.
+ *  * Copyright (c) 2018-2024 Cosmin Truta.
  *  * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
  *  * Copyright (c) 1996-1997 Andreas Dilger.
  *  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -267,7 +267,7 @@
  *    ...
  *    1.5.30                  15    10530  15.so.15.30[.0]
  *    ...
- *    1.6.40                  16    10640  16.so.16.40[.0]
+ *    1.6.43                  16    10643  16.so.16.43[.0]
  *
  *    Henceforth the source version will match the shared-library major and
  *    minor numbers; the shared-library major version number will be used for
@@ -283,9 +283,6 @@
  *    to the info_ptr or png_ptr members through png.h, and the compiled
  *    application is loaded with a different version of the library.
  *
- *    DLLNUM will change each time there are forward or backward changes
- *    in binary compatibility (e.g., when a new feature is added).
- *
  * See libpng.txt or libpng.3 for more information.  The PNG specification
  * is available as a W3C Recommendation and as an ISO/IEC Standard; see
  * 
@@ -306,19 +303,21 @@
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.40"
-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.40 - June 21, 2023\n"
+#define PNG_LIBPNG_VER_STRING "1.6.43"
+#define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
 
-#define PNG_LIBPNG_VER_SONUM   16
-#define PNG_LIBPNG_VER_DLLNUM  16
+/* The versions of shared library builds should stay in sync, going forward */
+#define PNG_LIBPNG_VER_SHAREDLIB 16
+#define PNG_LIBPNG_VER_SONUM     PNG_LIBPNG_VER_SHAREDLIB /* [Deprecated] */
+#define PNG_LIBPNG_VER_DLLNUM    PNG_LIBPNG_VER_SHAREDLIB /* [Deprecated] */
 
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   6
-#define PNG_LIBPNG_VER_RELEASE 40
+#define PNG_LIBPNG_VER_RELEASE 43
 
 /* This should be zero for a public release, or non-zero for a
- * development version.  [Deprecated]
+ * development version.
  */
 #define PNG_LIBPNG_VER_BUILD  0
 
@@ -346,7 +345,7 @@
  * From version 1.0.1 it is:
  * XXYYZZ, where XX=major, YY=minor, ZZ=release
  */
-#define PNG_LIBPNG_VER 10640 /* 1.6.40 */
+#define PNG_LIBPNG_VER 10643 /* 1.6.43 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
@@ -456,7 +455,7 @@ extern "C" {
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char* png_libpng_version_1_6_40;
+typedef char* png_libpng_version_1_6_43;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *
@@ -877,7 +876,7 @@ PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef);
 #define PNG_TRANSFORM_GRAY_TO_RGB   0x2000      /* read only */
 /* Added to libpng-1.5.4 */
 #define PNG_TRANSFORM_EXPAND_16     0x4000      /* read only */
-#if INT_MAX >= 0x8000 /* else this might break */
+#if ~0U > 0xffffU /* or else this might break on a 16-bit machine */
 #define PNG_TRANSFORM_SCALE_16      0x8000      /* read only */
 #endif
 
@@ -936,15 +935,15 @@ PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes));
 /* Check sig[start] through sig[start + num_to_check - 1] to see if it's a
  * PNG file.  Returns zero if the supplied bytes match the 8-byte PNG
  * signature, and non-zero otherwise.  Having num_to_check == 0 or
- * start > 7 will always fail (ie return non-zero).
+ * start > 7 will always fail (i.e. return non-zero).
  */
 PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, size_t start,
     size_t num_to_check));
 
 /* Simple signature checking function.  This is the same as calling
- * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n).
+ * png_check_sig(sig, n) := (png_sig_cmp(sig, 0, n) == 0).
  */
-#define png_check_sig(sig, n) !png_sig_cmp((sig), 0, (n))
+#define png_check_sig(sig, n) (png_sig_cmp((sig), 0, (n)) == 0) /* DEPRECATED */
 
 /* Allocate and initialize png_ptr struct for reading, and any other memory. */
 PNG_EXPORTA(4, png_structp, png_create_read_struct,
@@ -1758,12 +1757,9 @@ PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr));
 PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr,
     png_inforp info_ptr, png_uint_32 free_me, int num));
 
-/* Reassign responsibility for freeing existing data, whether allocated
+/* Reassign the responsibility for freeing existing data, whether allocated
  * by libpng or by the application; this works on the png_info structure passed
- * in, it does not change the state for other png_info structures.
- *
- * It is unlikely that this function works correctly as of 1.6.0 and using it
- * may result either in memory leaks or double free of allocated data.
+ * in, without changing the state for other png_info structures.
  */
 PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr,
     png_inforp info_ptr, int freer, png_uint_32 mask));
@@ -3235,11 +3231,18 @@ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory,
 #ifdef PNG_MIPS_MSA_API_SUPPORTED
 #  define PNG_MIPS_MSA   6 /* HARDWARE: MIPS Msa SIMD instructions supported */
 #endif
-#define PNG_IGNORE_ADLER32 8
+#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
+#  define PNG_IGNORE_ADLER32 8 /* SOFTWARE: disable Adler32 check on IDAT */
+#endif
 #ifdef PNG_POWERPC_VSX_API_SUPPORTED
-#  define PNG_POWERPC_VSX   10 /* HARDWARE: PowerPC VSX SIMD instructions supported */
+#  define PNG_POWERPC_VSX   10 /* HARDWARE: PowerPC VSX SIMD instructions
+                                * supported */
 #endif
-#define PNG_OPTION_NEXT  12 /* Next option - numbers must be even */
+#ifdef PNG_MIPS_MMI_API_SUPPORTED
+#  define PNG_MIPS_MMI   12 /* HARDWARE: MIPS MMI SIMD instructions supported */
+#endif
+
+#define PNG_OPTION_NEXT  14 /* Next option - numbers must be even */
 
 /* Return values: NOTE: there are four values and 'off' is *not* zero */
 #define PNG_OPTION_UNSET   0 /* Unset - defaults to off */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
index 41cbc91d398..b3b441b1122 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
@@ -29,9 +29,9 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.40
+ * libpng version 1.6.43
  *
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
index 623735f06f1..ea8dd172197 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngerror.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -283,7 +283,7 @@ void
 png_warning_parameter_unsigned(png_warning_parameters p, int number, int format,
     png_alloc_size_t value)
 {
-   char buffer[PNG_NUMBER_BUFFER_SIZE];
+   char buffer[PNG_NUMBER_BUFFER_SIZE] = {0};
    png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value));
 }
 
@@ -293,7 +293,7 @@ png_warning_parameter_signed(png_warning_parameters p, int number, int format,
 {
    png_alloc_size_t u;
    png_charp str;
-   char buffer[PNG_NUMBER_BUFFER_SIZE];
+   char buffer[PNG_NUMBER_BUFFER_SIZE] = {0};
 
    /* Avoid overflow by doing the negate in a png_alloc_size_t: */
    u = (png_alloc_size_t)value;
@@ -886,7 +886,7 @@ png_get_error_ptr(png_const_structrp png_ptr)
    if (png_ptr == NULL)
       return NULL;
 
-   return ((png_voidp)png_ptr->error_ptr);
+   return (png_voidp)png_ptr->error_ptr;
 }
 
 
@@ -961,31 +961,25 @@ png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message)
 #endif
 
 int /* PRIVATE */
-png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg)
+png_safe_execute(png_imagep image, int (*function)(png_voidp), png_voidp arg)
 {
-   volatile png_imagep image = image_in;
-   volatile int result;
-   volatile png_voidp saved_error_buf;
+   png_voidp saved_error_buf = image->opaque->error_buf;
    jmp_buf safe_jmpbuf;
+   int result;
 
-   /* Safely execute function(arg) with png_error returning to this function. */
-   saved_error_buf = image->opaque->error_buf;
-   result = setjmp(safe_jmpbuf) == 0;
-
-   if (result != 0)
+   /* Safely execute function(arg), with png_error returning back here. */
+   if (setjmp(safe_jmpbuf) == 0)
    {
-
       image->opaque->error_buf = safe_jmpbuf;
       result = function(arg);
+      image->opaque->error_buf = saved_error_buf;
+      return result;
    }
 
+   /* On png_error, return via longjmp, pop the jmpbuf, and free the image. */
    image->opaque->error_buf = saved_error_buf;
-
-   /* And do the cleanup prior to any failure return. */
-   if (result == 0)
-      png_image_free(image);
-
-   return result;
+   png_image_free(image);
+   return 0;
 }
 #endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */
 #endif /* READ || WRITE */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
index 6e510b27327..41e0a5abc3a 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2023 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -56,22 +56,22 @@ png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr,
        * valid tRNS chunk in this case.
        */
       if (flag == PNG_INFO_tRNS && png_ptr->num_trans == 0)
-         return(0);
+         return 0;
 #endif
 
-      return(info_ptr->valid & flag);
+      return info_ptr->valid & flag;
    }
 
-   return(0);
+   return 0;
 }
 
 size_t PNGAPI
 png_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr)
 {
    if (png_ptr != NULL && info_ptr != NULL)
-      return(info_ptr->rowbytes);
+      return info_ptr->rowbytes;
 
-   return(0);
+   return 0;
 }
 
 #ifdef PNG_INFO_IMAGE_SUPPORTED
@@ -79,9 +79,9 @@ png_bytepp PNGAPI
 png_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr)
 {
    if (png_ptr != NULL && info_ptr != NULL)
-      return(info_ptr->row_pointers);
+      return info_ptr->row_pointers;
 
-   return(0);
+   return 0;
 }
 #endif
 
@@ -93,7 +93,7 @@ png_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr)
    if (png_ptr != NULL && info_ptr != NULL)
       return info_ptr->width;
 
-   return (0);
+   return 0;
 }
 
 png_uint_32 PNGAPI
@@ -102,7 +102,7 @@ png_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr)
    if (png_ptr != NULL && info_ptr != NULL)
       return info_ptr->height;
 
-   return (0);
+   return 0;
 }
 
 png_byte PNGAPI
@@ -111,7 +111,7 @@ png_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr)
    if (png_ptr != NULL && info_ptr != NULL)
       return info_ptr->bit_depth;
 
-   return (0);
+   return 0;
 }
 
 png_byte PNGAPI
@@ -120,7 +120,7 @@ png_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
    if (png_ptr != NULL && info_ptr != NULL)
       return info_ptr->color_type;
 
-   return (0);
+   return 0;
 }
 
 png_byte PNGAPI
@@ -129,7 +129,7 @@ png_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
    if (png_ptr != NULL && info_ptr != NULL)
       return info_ptr->filter_type;
 
-   return (0);
+   return 0;
 }
 
 png_byte PNGAPI
@@ -138,7 +138,7 @@ png_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
    if (png_ptr != NULL && info_ptr != NULL)
       return info_ptr->interlace_type;
 
-   return (0);
+   return 0;
 }
 
 png_byte PNGAPI
@@ -147,7 +147,7 @@ png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
    if (png_ptr != NULL && info_ptr != NULL)
       return info_ptr->compression_type;
 
-   return (0);
+   return 0;
 }
 
 png_uint_32 PNGAPI
@@ -155,21 +155,20 @@ png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp
    info_ptr)
 {
 #ifdef PNG_pHYs_SUPPORTED
+   png_debug(1, "in png_get_x_pixels_per_meter");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_pHYs) != 0)
-      {
-         png_debug1(1, "in %s retrieval function",
-             "png_get_x_pixels_per_meter");
-
-         if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)
-            return (info_ptr->x_pixels_per_unit);
-      }
+   {
+      if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)
+         return info_ptr->x_pixels_per_unit;
+   }
 #else
    PNG_UNUSED(png_ptr)
    PNG_UNUSED(info_ptr)
 #endif
 
-   return (0);
+   return 0;
 }
 
 png_uint_32 PNGAPI
@@ -177,42 +176,41 @@ png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp
     info_ptr)
 {
 #ifdef PNG_pHYs_SUPPORTED
+   png_debug(1, "in png_get_y_pixels_per_meter");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_pHYs) != 0)
    {
-      png_debug1(1, "in %s retrieval function",
-          "png_get_y_pixels_per_meter");
-
       if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)
-         return (info_ptr->y_pixels_per_unit);
+         return info_ptr->y_pixels_per_unit;
    }
 #else
    PNG_UNUSED(png_ptr)
    PNG_UNUSED(info_ptr)
 #endif
 
-   return (0);
+   return 0;
 }
 
 png_uint_32 PNGAPI
 png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr)
 {
 #ifdef PNG_pHYs_SUPPORTED
+   png_debug(1, "in png_get_pixels_per_meter");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_pHYs) != 0)
    {
-      png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter");
-
       if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER &&
           info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit)
-         return (info_ptr->x_pixels_per_unit);
+         return info_ptr->x_pixels_per_unit;
    }
 #else
    PNG_UNUSED(png_ptr)
    PNG_UNUSED(info_ptr)
 #endif
 
-   return (0);
+   return 0;
 }
 
 #ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -221,21 +219,21 @@ png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp
    info_ptr)
 {
 #ifdef PNG_READ_pHYs_SUPPORTED
+   png_debug(1, "in png_get_pixel_aspect_ratio");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_pHYs) != 0)
    {
-      png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio");
-
       if (info_ptr->x_pixels_per_unit != 0)
-         return ((float)((float)info_ptr->y_pixels_per_unit
-             /(float)info_ptr->x_pixels_per_unit));
+         return (float)info_ptr->y_pixels_per_unit
+              / (float)info_ptr->x_pixels_per_unit;
    }
 #else
    PNG_UNUSED(png_ptr)
    PNG_UNUSED(info_ptr)
 #endif
 
-   return ((float)0.0);
+   return (float)0.0;
 }
 #endif
 
@@ -245,6 +243,8 @@ png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr,
     png_const_inforp info_ptr)
 {
 #ifdef PNG_READ_pHYs_SUPPORTED
+   png_debug(1, "in png_get_pixel_aspect_ratio_fixed");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_pHYs) != 0 &&
        info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 &&
@@ -253,8 +253,6 @@ png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr,
    {
       png_fixed_point res;
 
-      png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio_fixed");
-
       /* The following casts work because a PNG 4 byte integer only has a valid
        * range of 0..2^31-1; otherwise the cast might overflow.
        */
@@ -275,80 +273,80 @@ png_int_32 PNGAPI
 png_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr)
 {
 #ifdef PNG_oFFs_SUPPORTED
+   png_debug(1, "in png_get_x_offset_microns");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_oFFs) != 0)
    {
-      png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns");
-
       if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)
-         return (info_ptr->x_offset);
+         return info_ptr->x_offset;
    }
 #else
    PNG_UNUSED(png_ptr)
    PNG_UNUSED(info_ptr)
 #endif
 
-   return (0);
+   return 0;
 }
 
 png_int_32 PNGAPI
 png_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr)
 {
 #ifdef PNG_oFFs_SUPPORTED
+   png_debug(1, "in png_get_y_offset_microns");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_oFFs) != 0)
    {
-      png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns");
-
       if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)
-         return (info_ptr->y_offset);
+         return info_ptr->y_offset;
    }
 #else
    PNG_UNUSED(png_ptr)
    PNG_UNUSED(info_ptr)
 #endif
 
-   return (0);
+   return 0;
 }
 
 png_int_32 PNGAPI
 png_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr)
 {
 #ifdef PNG_oFFs_SUPPORTED
+   png_debug(1, "in png_get_x_offset_pixels");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_oFFs) != 0)
    {
-      png_debug1(1, "in %s retrieval function", "png_get_x_offset_pixels");
-
       if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)
-         return (info_ptr->x_offset);
+         return info_ptr->x_offset;
    }
 #else
    PNG_UNUSED(png_ptr)
    PNG_UNUSED(info_ptr)
 #endif
 
-   return (0);
+   return 0;
 }
 
 png_int_32 PNGAPI
 png_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr)
 {
 #ifdef PNG_oFFs_SUPPORTED
+   png_debug(1, "in png_get_y_offset_pixels");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_oFFs) != 0)
    {
-      png_debug1(1, "in %s retrieval function", "png_get_y_offset_pixels");
-
       if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)
-         return (info_ptr->y_offset);
+         return info_ptr->y_offset;
    }
 #else
    PNG_UNUSED(png_ptr)
    PNG_UNUSED(info_ptr)
 #endif
 
-   return (0);
+   return 0;
 }
 
 #ifdef PNG_INCH_CONVERSIONS_SUPPORTED
@@ -462,11 +460,11 @@ png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr,
 {
    png_uint_32 retval = 0;
 
+   png_debug1(1, "in %s retrieval function", "pHYs");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_pHYs) != 0)
    {
-      png_debug1(1, "in %s retrieval function", "pHYs");
-
       if (res_x != NULL)
       {
          *res_x = info_ptr->x_pixels_per_unit;
@@ -492,7 +490,7 @@ png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr,
       }
    }
 
-   return (retval);
+   return retval;
 }
 #endif /* pHYs */
 #endif /* INCH_CONVERSIONS */
@@ -506,9 +504,9 @@ png_byte PNGAPI
 png_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr)
 {
    if (png_ptr != NULL && info_ptr != NULL)
-      return(info_ptr->channels);
+      return info_ptr->channels;
 
-   return (0);
+   return 0;
 }
 
 #ifdef PNG_READ_SUPPORTED
@@ -516,9 +514,9 @@ png_const_bytep PNGAPI
 png_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr)
 {
    if (png_ptr != NULL && info_ptr != NULL)
-      return(info_ptr->signature);
+      return info_ptr->signature;
 
-   return (NULL);
+   return NULL;
 }
 #endif
 
@@ -527,17 +525,17 @@ png_uint_32 PNGAPI
 png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,
     png_color_16p *background)
 {
+   png_debug1(1, "in %s retrieval function", "bKGD");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_bKGD) != 0 &&
        background != NULL)
    {
-      png_debug1(1, "in %s retrieval function", "bKGD");
-
       *background = &(info_ptr->background);
-      return (PNG_INFO_bKGD);
+      return PNG_INFO_bKGD;
    }
 
-   return (0);
+   return 0;
 }
 #endif
 
@@ -552,6 +550,8 @@ png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr,
     double *white_x, double *white_y, double *red_x, double *red_y,
     double *green_x, double *green_y, double *blue_x, double *blue_y)
 {
+   png_debug1(1, "in %s retrieval function", "cHRM");
+
    /* Quiet API change: this code used to only return the end points if a cHRM
     * chunk was present, but the end points can also come from iCCP or sRGB
     * chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and
@@ -561,8 +561,6 @@ png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr,
    if (png_ptr != NULL && info_ptr != NULL &&
       (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
    {
-      png_debug1(1, "in %s retrieval function", "cHRM");
-
       if (white_x != NULL)
          *white_x = png_float(png_ptr,
              info_ptr->colorspace.end_points_xy.whitex, "cHRM white X");
@@ -587,10 +585,10 @@ png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr,
       if (blue_y != NULL)
          *blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey,
              "cHRM blue Y");
-      return (PNG_INFO_cHRM);
+      return PNG_INFO_cHRM;
    }
 
-   return (0);
+   return 0;
 }
 
 png_uint_32 PNGAPI
@@ -599,11 +597,11 @@ png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr,
     double *green_Y, double *green_Z, double *blue_X, double *blue_Y,
     double *blue_Z)
 {
+   png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
    {
-      png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)");
-
       if (red_X != NULL)
          *red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X,
              "cHRM red X");
@@ -631,10 +629,10 @@ png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr,
       if (blue_Z != NULL)
          *blue_Z = png_float(png_ptr,
              info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z");
-      return (PNG_INFO_cHRM);
+      return PNG_INFO_cHRM;
    }
 
-   return (0);
+   return 0;
 }
 #  endif
 
@@ -647,11 +645,11 @@ png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
     png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
     png_fixed_point *int_blue_Z)
 {
+   png_debug1(1, "in %s retrieval function", "cHRM_XYZ");
+
    if (png_ptr != NULL && info_ptr != NULL &&
       (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
    {
-      png_debug1(1, "in %s retrieval function", "cHRM_XYZ");
-
       if (int_red_X != NULL)
          *int_red_X = info_ptr->colorspace.end_points_XYZ.red_X;
       if (int_red_Y != NULL)
@@ -670,10 +668,10 @@ png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
          *int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y;
       if (int_blue_Z != NULL)
          *int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z;
-      return (PNG_INFO_cHRM);
+      return PNG_INFO_cHRM;
    }
 
-   return (0);
+   return 0;
 }
 
 png_uint_32 PNGAPI
@@ -703,10 +701,10 @@ png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
          *blue_x = info_ptr->colorspace.end_points_xy.bluex;
       if (blue_y != NULL)
          *blue_y = info_ptr->colorspace.end_points_xy.bluey;
-      return (PNG_INFO_cHRM);
+      return PNG_INFO_cHRM;
    }
 
-   return (0);
+   return 0;
 }
 #  endif
 #endif
@@ -724,10 +722,10 @@ png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
        file_gamma != NULL)
    {
       *file_gamma = info_ptr->colorspace.gamma;
-      return (PNG_INFO_gAMA);
+      return PNG_INFO_gAMA;
    }
 
-   return (0);
+   return 0;
 }
 #  endif
 
@@ -744,10 +742,10 @@ png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr,
    {
       *file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma,
           "png_get_gAMA");
-      return (PNG_INFO_gAMA);
+      return PNG_INFO_gAMA;
    }
 
-   return (0);
+   return 0;
 }
 #  endif
 #endif
@@ -763,10 +761,10 @@ png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr,
       (info_ptr->valid & PNG_INFO_sRGB) != 0 && file_srgb_intent != NULL)
    {
       *file_srgb_intent = info_ptr->colorspace.rendering_intent;
-      return (PNG_INFO_sRGB);
+      return PNG_INFO_sRGB;
    }
 
-   return (0);
+   return 0;
 }
 #endif
 
@@ -790,10 +788,10 @@ png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
        */
       if (compression_type != NULL)
          *compression_type = PNG_COMPRESSION_TYPE_BASE;
-      return (PNG_INFO_iCCP);
+      return PNG_INFO_iCCP;
    }
 
-   return (0);
+   return 0;
 
 }
 #endif
@@ -803,13 +801,15 @@ int PNGAPI
 png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr,
     png_sPLT_tpp spalettes)
 {
+   png_debug1(1, "in %s retrieval function", "sPLT");
+
    if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL)
    {
       *spalettes = info_ptr->splt_palettes;
       return info_ptr->splt_palettes_num;
    }
 
-   return (0);
+   return 0;
 }
 #endif
 
@@ -835,10 +835,10 @@ png_get_eXIf_1(png_const_structrp png_ptr, png_const_inforp info_ptr,
    {
       *num_exif = info_ptr->num_exif;
       *exif = info_ptr->exif;
-      return (PNG_INFO_eXIf);
+      return PNG_INFO_eXIf;
    }
 
-   return (0);
+   return 0;
 }
 #endif
 
@@ -853,10 +853,10 @@ png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
        (info_ptr->valid & PNG_INFO_hIST) != 0 && hist != NULL)
    {
       *hist = info_ptr->hist;
-      return (PNG_INFO_hIST);
+      return PNG_INFO_hIST;
    }
 
-   return (0);
+   return 0;
 }
 #endif
 
@@ -869,7 +869,7 @@ png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr,
    png_debug1(1, "in %s retrieval function", "IHDR");
 
    if (png_ptr == NULL || info_ptr == NULL)
-      return (0);
+      return 0;
 
    if (width != NULL)
        *width = info_ptr->width;
@@ -901,7 +901,7 @@ png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr,
        info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,
        info_ptr->compression_type, info_ptr->filter_type);
 
-   return (1);
+   return 1;
 }
 
 #ifdef PNG_oFFs_SUPPORTED
@@ -918,10 +918,10 @@ png_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr,
       *offset_x = info_ptr->x_offset;
       *offset_y = info_ptr->y_offset;
       *unit_type = (int)info_ptr->offset_unit_type;
-      return (PNG_INFO_oFFs);
+      return PNG_INFO_oFFs;
    }
 
-   return (0);
+   return 0;
 }
 #endif
 
@@ -945,10 +945,10 @@ png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
       *nparams = (int)info_ptr->pcal_nparams;
       *units = info_ptr->pcal_units;
       *params = info_ptr->pcal_params;
-      return (PNG_INFO_pCAL);
+      return PNG_INFO_pCAL;
    }
 
-   return (0);
+   return 0;
 }
 #endif
 
@@ -960,6 +960,8 @@ png_uint_32 PNGAPI
 png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
     int *unit, png_fixed_point *width, png_fixed_point *height)
 {
+   png_debug1(1, "in %s retrieval function", "sCAL");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_sCAL) != 0)
    {
@@ -971,10 +973,10 @@ png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
       *width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), "sCAL width");
       *height = png_fixed(png_ptr, atof(info_ptr->scal_s_height),
           "sCAL height");
-      return (PNG_INFO_sCAL);
+      return PNG_INFO_sCAL;
    }
 
-   return(0);
+   return 0;
 }
 #    endif /* FLOATING_ARITHMETIC */
 #  endif /* FIXED_POINT */
@@ -983,32 +985,36 @@ png_uint_32 PNGAPI
 png_get_sCAL(png_const_structrp png_ptr, png_const_inforp info_ptr,
     int *unit, double *width, double *height)
 {
+   png_debug1(1, "in %s retrieval function", "sCAL(float)");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_sCAL) != 0)
    {
       *unit = info_ptr->scal_unit;
       *width = atof(info_ptr->scal_s_width);
       *height = atof(info_ptr->scal_s_height);
-      return (PNG_INFO_sCAL);
+      return PNG_INFO_sCAL;
    }
 
-   return(0);
+   return 0;
 }
 #  endif /* FLOATING POINT */
 png_uint_32 PNGAPI
 png_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr,
     int *unit, png_charpp width, png_charpp height)
 {
+   png_debug1(1, "in %s retrieval function", "sCAL(str)");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_sCAL) != 0)
    {
       *unit = info_ptr->scal_unit;
       *width = info_ptr->scal_s_width;
       *height = info_ptr->scal_s_height;
-      return (PNG_INFO_sCAL);
+      return PNG_INFO_sCAL;
    }
 
-   return(0);
+   return 0;
 }
 #endif /* sCAL */
 
@@ -1043,7 +1049,7 @@ png_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr,
       }
    }
 
-   return (retval);
+   return retval;
 }
 #endif /* pHYs */
 
@@ -1059,10 +1065,10 @@ png_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr,
       *palette = info_ptr->palette;
       *num_palette = info_ptr->num_palette;
       png_debug1(3, "num_palette = %d", *num_palette);
-      return (PNG_INFO_PLTE);
+      return PNG_INFO_PLTE;
    }
 
-   return (0);
+   return 0;
 }
 
 #ifdef PNG_sBIT_SUPPORTED
@@ -1076,10 +1082,10 @@ png_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,
        (info_ptr->valid & PNG_INFO_sBIT) != 0 && sig_bit != NULL)
    {
       *sig_bit = &(info_ptr->sig_bit);
-      return (PNG_INFO_sBIT);
+      return PNG_INFO_sBIT;
    }
 
-   return (0);
+   return 0;
 }
 #endif
 
@@ -1090,7 +1096,7 @@ png_get_text(png_const_structrp png_ptr, png_inforp info_ptr,
 {
    if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0)
    {
-      png_debug1(1, "in 0x%lx retrieval function",
+      png_debug1(1, "in text retrieval function, chunk typeid = 0x%lx",
          (unsigned long)png_ptr->chunk_name);
 
       if (text_ptr != NULL)
@@ -1105,7 +1111,7 @@ png_get_text(png_const_structrp png_ptr, png_inforp info_ptr,
    if (num_text != NULL)
       *num_text = 0;
 
-   return(0);
+   return 0;
 }
 #endif
 
@@ -1120,10 +1126,10 @@ png_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr,
        (info_ptr->valid & PNG_INFO_tIME) != 0 && mod_time != NULL)
    {
       *mod_time = &(info_ptr->mod_time);
-      return (PNG_INFO_tIME);
+      return PNG_INFO_tIME;
    }
 
-   return (0);
+   return 0;
 }
 #endif
 
@@ -1133,11 +1139,12 @@ png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr,
     png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color)
 {
    png_uint_32 retval = 0;
+
+   png_debug1(1, "in %s retrieval function", "tRNS");
+
    if (png_ptr != NULL && info_ptr != NULL &&
        (info_ptr->valid & PNG_INFO_tRNS) != 0)
    {
-      png_debug1(1, "in %s retrieval function", "tRNS");
-
       if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
       {
          if (trans_alpha != NULL)
@@ -1169,7 +1176,7 @@ png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr,
       }
    }
 
-   return (retval);
+   return retval;
 }
 #endif
 
@@ -1184,7 +1191,7 @@ png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr,
       return info_ptr->unknown_chunks_num;
    }
 
-   return (0);
+   return 0;
 }
 #endif
 
@@ -1280,7 +1287,7 @@ png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr)
    if (png_ptr != NULL && info_ptr != NULL)
       return png_ptr->num_palette_max;
 
-   return (-1);
+   return -1;
 }
 #  endif
 #endif
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
index e98d49cf0cc..e238ccdb9a4 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
@@ -31,7 +31,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  */
-/* libpng version 1.6.40 */
+/* libpng version 1.6.43 */
 
 /* Copyright (c) 2018-2023 Cosmin Truta */
 /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c
index a98b2013256..816631cae18 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngpread.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -173,10 +173,10 @@ png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr)
        num_to_check);
    png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check);
 
-   if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+   if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0)
    {
       if (num_checked < 4 &&
-          png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+          png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4) != 0)
          png_error(png_ptr, "Not a PNG file");
 
       else
@@ -322,6 +322,14 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
       png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length);
    }
 
+#endif
+#ifdef PNG_READ_eXIf_SUPPORTED
+   else if (png_ptr->chunk_name == png_eXIf)
+   {
+      PNG_PUSH_SAVE_BUFFER_IF_FULL
+      png_handle_eXIf(png_ptr, info_ptr, png_ptr->push_length);
+   }
+
 #endif
 #ifdef PNG_READ_sRGB_SUPPORTED
    else if (chunk_name == png_sRGB)
@@ -1117,7 +1125,7 @@ png_voidp PNGAPI
 png_get_progressive_ptr(png_const_structrp png_ptr)
 {
    if (png_ptr == NULL)
-      return (NULL);
+      return NULL;
 
    return png_ptr->io_ptr;
 }
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
index 914d0b97b1d..18424542b00 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2023 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -64,7 +64,7 @@
  * still required (as of 2011-05-02.)
  */
 #ifndef _POSIX_SOURCE
-# define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */
+#  define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */
 #endif
 
 #ifndef PNG_VERSION_INFO_ONLY
@@ -218,13 +218,27 @@
 #endif /* PNG_ARM_NEON_OPT > 0 */
 
 #ifndef PNG_MIPS_MSA_OPT
-#  if defined(__mips_msa) && (__mips_isa_rev >= 5) && defined(PNG_ALIGNED_MEMORY_SUPPORTED)
+#  if defined(__mips_msa) && (__mips_isa_rev >= 5) && \
+   defined(PNG_ALIGNED_MEMORY_SUPPORTED)
 #     define PNG_MIPS_MSA_OPT 2
 #  else
 #     define PNG_MIPS_MSA_OPT 0
 #  endif
 #endif
 
+#ifndef PNG_MIPS_MMI_OPT
+#  ifdef PNG_MIPS_MMI
+#    if defined(__mips_loongson_mmi) && (_MIPS_SIM == _ABI64) && \
+     defined(PNG_ALIGNED_MEMORY_SUPPORTED)
+#       define PNG_MIPS_MMI_OPT 1
+#    else
+#       define PNG_MIPS_MMI_OPT 0
+#    endif
+#  else
+#    define PNG_MIPS_MMI_OPT 0
+#  endif
+#endif
+
 #ifndef PNG_POWERPC_VSX_OPT
 #  if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__)
 #     define PNG_POWERPC_VSX_OPT 2
@@ -233,13 +247,21 @@
 #  endif
 #endif
 
+#ifndef PNG_LOONGARCH_LSX_OPT
+#  if defined(__loongarch_sx)
+#     define PNG_LOONGARCH_LSX_OPT 1
+#  else
+#     define PNG_LOONGARCH_LSX_OPT 0
+#  endif
+#endif
+
 #ifndef PNG_INTEL_SSE_OPT
 #   ifdef PNG_INTEL_SSE
       /* Only check for SSE if the build configuration has been modified to
        * enable SSE optimizations.  This means that these optimizations will
        * be off by default.  See contrib/intel for more details.
        */
-#     if defined(__SSE4_1__) || defined(__AVX__) || defined(__SSSE3__) || \
+#      if defined(__SSE4_1__) || defined(__AVX__) || defined(__SSSE3__) || \
        defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \
        (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
 #         define PNG_INTEL_SSE_OPT 1
@@ -276,7 +298,6 @@
 #endif
 
 #if PNG_MIPS_MSA_OPT > 0
-#  define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_msa
 #  ifndef PNG_MIPS_MSA_IMPLEMENTATION
 #     if defined(__mips_msa)
 #        if defined(__clang__)
@@ -292,11 +313,28 @@
 
 #  ifndef PNG_MIPS_MSA_IMPLEMENTATION
 #     define PNG_MIPS_MSA_IMPLEMENTATION 1
+#     define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_mips
 #  endif
 #else
 #  define PNG_MIPS_MSA_IMPLEMENTATION 0
 #endif /* PNG_MIPS_MSA_OPT > 0 */
 
+#if PNG_MIPS_MMI_OPT > 0
+#  ifndef PNG_MIPS_MMI_IMPLEMENTATION
+#     if defined(__mips_loongson_mmi) && (_MIPS_SIM == _ABI64)
+#        define PNG_MIPS_MMI_IMPLEMENTATION 2
+#     else /* !defined __mips_loongson_mmi  || _MIPS_SIM != _ABI64 */
+#        define PNG_MIPS_MMI_IMPLEMENTATION 0
+#     endif /* __mips_loongson_mmi  && _MIPS_SIM == _ABI64 */
+#  endif /* !PNG_MIPS_MMI_IMPLEMENTATION */
+
+#   if PNG_MIPS_MMI_IMPLEMENTATION > 0
+#      define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_mips
+#   endif
+#else
+#   define PNG_MIPS_MMI_IMPLEMENTATION 0
+#endif /* PNG_MIPS_MMI_OPT > 0 */
+
 #if PNG_POWERPC_VSX_OPT > 0
 #  define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_vsx
 #  define PNG_POWERPC_VSX_IMPLEMENTATION 1
@@ -304,6 +342,12 @@
 #  define PNG_POWERPC_VSX_IMPLEMENTATION 0
 #endif
 
+#if PNG_LOONGARCH_LSX_OPT > 0
+#   define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_lsx
+#   define PNG_LOONGARCH_LSX_IMPLEMENTATION 1
+#else
+#   define PNG_LOONGARCH_LSX_IMPLEMENTATION 0
+#endif
 
 /* Is this a build of a DLL where compilation of the object modules requires
  * different preprocessor settings to those required for a simple library?  If
@@ -542,18 +586,8 @@
     */
 #  include 
 
-#  if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \
-    defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC)
-   /* We need to check that  hasn't already been included earlier
-    * as it seems it doesn't agree with , yet we should really use
-    *  if possible.
-    */
-#    if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__)
-#      include 
-#    endif
-#  else
-#    include 
-#  endif
+#  include 
+
 #  if defined(_AMIGA) && defined(__SASC) && defined(_M68881)
    /* Amiga SAS/C: We must include builtin FPU functions when compiling using
     * MATH=68881
@@ -1334,7 +1368,7 @@ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop
     row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
 #endif
 
-#if PNG_MIPS_MSA_OPT > 0
+#if PNG_MIPS_MSA_IMPLEMENTATION == 1
 PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_msa,(png_row_infop row_info,
     png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
 PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_msa,(png_row_infop
@@ -1351,6 +1385,23 @@ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_msa,(png_row_infop
     row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
 #endif
 
+#if PNG_MIPS_MMI_IMPLEMENTATION > 0
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_mmi,(png_row_infop row_info,
+    png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_mmi,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_mmi,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_mmi,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_mmi,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_mmi,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_mmi,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+#endif
+
 #if PNG_POWERPC_VSX_OPT > 0
 PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_vsx,(png_row_infop row_info,
     png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
@@ -1383,6 +1434,23 @@ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_sse2,(png_row_infop
     row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
 #endif
 
+#if PNG_LOONGARCH_LSX_IMPLEMENTATION == 1
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_lsx,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_lsx,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_lsx,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_lsx,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_lsx,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_lsx,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_lsx,(png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+#endif
+
 /* Choose the best filter to use and filter the row data */
 PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr,
     png_row_infop row_info),PNG_EMPTY);
@@ -2122,17 +2190,27 @@ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon,
    (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
 #endif
 
-#if PNG_MIPS_MSA_OPT > 0
-PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_msa,
+#if PNG_MIPS_MSA_IMPLEMENTATION == 1
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_mips,
    (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
 #endif
 
+#  if PNG_MIPS_MMI_IMPLEMENTATION > 0
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_mips,
+   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+#  endif
+
 #  if PNG_INTEL_SSE_IMPLEMENTATION > 0
 PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_sse2,
    (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
 #  endif
 #endif
 
+#if PNG_LOONGARCH_LSX_OPT > 0
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_lsx,
+    (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+#endif
+
 PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr,
    png_const_charp key, png_bytep new_key), PNG_EMPTY);
 
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
index 3631e60f36b..e9e94477545 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2019 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -596,7 +596,11 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row)
 #endif
 
 #ifdef PNG_READ_TRANSFORMS_SUPPORTED
-   if (png_ptr->transformations)
+   if (png_ptr->transformations
+#     ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+         || png_ptr->num_palette_max >= 0
+#     endif
+      )
       png_do_read_transformations(png_ptr, &row_info);
 #endif
 
@@ -813,7 +817,7 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
    /* Report invalid palette index; added at libng-1.5.10 */
    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
-       png_ptr->num_palette_max > png_ptr->num_palette)
+       png_ptr->num_palette_max >= png_ptr->num_palette)
       png_benign_error(png_ptr, "Read palette index exceeding num_palette");
 #endif
 
@@ -1077,6 +1081,8 @@ void PNGAPI
 png_read_png(png_structrp png_ptr, png_inforp info_ptr,
     int transforms, voidp params)
 {
+   png_debug(1, "in png_read_png");
+
    if (png_ptr == NULL || info_ptr == NULL)
       return;
 
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
index 843eb5fff2a..a393de4b79d 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2019 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -318,21 +318,20 @@ png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
    int compose = 0;
    png_fixed_point file_gamma;
 
-   png_debug(1, "in png_set_alpha_mode");
+   png_debug(1, "in png_set_alpha_mode_fixed");
 
    if (png_rtran_ok(png_ptr, 0) == 0)
       return;
 
    output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/);
 
-   /* Validate the value to ensure it is in a reasonable range. The value
+   /* Validate the value to ensure it is in a reasonable range.  The value
     * is expected to be 1 or greater, but this range test allows for some
-    * viewing correction values.  The intent is to weed out users of this API
-    * who use the inverse of the gamma value accidentally!  Since some of these
-    * values are reasonable this may have to be changed:
+    * viewing correction values.  The intent is to weed out the API users
+    * who might use the inverse of the gamma value accidentally!
     *
-    * 1.6.x: changed from 0.07..3 to 0.01..100 (to accommodate the optimal 16-bit
-    * gamma of 36, and its reciprocal.)
+    * In libpng 1.6.0, we changed from 0.07..3 to 0.01..100, to accommodate
+    * the optimal 16-bit gamma of 36 and its reciprocal.
     */
    if (output_gamma < 1000 || output_gamma > 10000000)
       png_error(png_ptr, "output gamma out of expected range");
@@ -469,7 +468,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
       int i;
 
       png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
-          (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));
+          (png_alloc_size_t)num_palette);
       for (i = 0; i < num_palette; i++)
          png_ptr->quantize_index[i] = (png_byte)i;
    }
@@ -486,7 +485,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
 
          /* Initialize an array to sort colors */
          png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
-             (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));
+             (png_alloc_size_t)num_palette);
 
          /* Initialize the quantize_sort array */
          for (i = 0; i < num_palette; i++)
@@ -620,11 +619,9 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
 
          /* Initialize palette index arrays */
          png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
-             (png_alloc_size_t)((png_uint_32)num_palette *
-             (sizeof (png_byte))));
+             (png_alloc_size_t)num_palette);
          png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
-             (png_alloc_size_t)((png_uint_32)num_palette *
-             (sizeof (png_byte))));
+             (png_alloc_size_t)num_palette);
 
          /* Initialize the sort array */
          for (i = 0; i < num_palette; i++)
@@ -789,12 +786,11 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
       size_t num_entries = ((size_t)1 << total_bits);
 
       png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr,
-          (png_alloc_size_t)(num_entries * (sizeof (png_byte))));
+          (png_alloc_size_t)(num_entries));
 
-      distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)(num_entries *
-          (sizeof (png_byte))));
+      distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)num_entries);
 
-      memset(distance, 0xff, num_entries * (sizeof (png_byte)));
+      memset(distance, 0xff, num_entries);
 
       for (i = 0; i < num_palette; i++)
       {
@@ -998,7 +994,7 @@ void PNGFAPI
 png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action,
     png_fixed_point red, png_fixed_point green)
 {
-   png_debug(1, "in png_set_rgb_to_gray");
+   png_debug(1, "in png_set_rgb_to_gray_fixed");
 
    /* Need the IHDR here because of the check on color_type below. */
    /* TODO: fix this */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
index 524297c5a10..5280140d12b 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -54,7 +54,7 @@ png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf)
    if (uval > PNG_UINT_31_MAX)
       png_error(png_ptr, "PNG unsigned integer out of range");
 
-   return (uval);
+   return uval;
 }
 
 #if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED)
@@ -168,7 +168,7 @@ png_read_sig(png_structrp png_ptr, png_inforp info_ptr)
    if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0)
    {
       if (num_checked < 4 &&
-          png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+          png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4) != 0)
          png_error(png_ptr, "Not a PNG file");
       else
          png_error(png_ptr, "PNG file corrupted by ASCII conversion");
@@ -199,7 +199,7 @@ png_read_chunk_header(png_structrp png_ptr)
    /* Put the chunk name into png_ptr->chunk_name. */
    png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4);
 
-   png_debug2(0, "Reading %lx chunk, length = %lu",
+   png_debug2(0, "Reading chunk typeid = 0x%lx, length = %lu",
        (unsigned long)png_ptr->chunk_name, (unsigned long)length);
 
    /* Reset the crc and run it over the chunk name. */
@@ -266,10 +266,10 @@ png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
       else
          png_chunk_error(png_ptr, "CRC error");
 
-      return (1);
+      return 1;
    }
 
-   return (0);
+   return 0;
 }
 
 /* Compare the CRC stored in the PNG file with that calculated by libpng from
@@ -305,11 +305,11 @@ png_crc_error(png_structrp png_ptr)
    if (need_crc != 0)
    {
       crc = png_get_uint_32(crc_bytes);
-      return ((int)(crc != png_ptr->crc));
+      return crc != png_ptr->crc;
    }
 
    else
-      return (0);
+      return 0;
 }
 
 #if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\
@@ -449,8 +449,7 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner)
             png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
       }
 
-#if ZLIB_VERNUM >= 0x1290 && \
-   defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_IGNORE_ADLER32)
+#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
       if (((png_ptr->options >> PNG_IGNORE_ADLER32) & 3) == PNG_OPTION_ON)
          /* Turn off validation of the ADLER32 checksum in IDAT chunks */
          ret = inflateValidate(&png_ptr->zstream, 0);
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
index 62612a02278..f53ab6fa1d1 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2023 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
  * Copyright (c) 1998-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -791,11 +791,11 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
 {
    int i;
 
-   png_debug1(1, "in %lx storage function", png_ptr == NULL ? 0xabadca11U :
-      (unsigned long)png_ptr->chunk_name);
+   png_debug1(1, "in text storage function, chunk typeid = 0x%lx",
+      png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name);
 
    if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL)
-      return(0);
+      return 0;
 
    /* Make sure we have enough space in the "text" array in info_struct
     * to hold all of the incoming text_ptr objects.  This compare can't overflow
@@ -975,7 +975,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
       png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
    }
 
-   return(0);
+   return 0;
 }
 #endif
 
@@ -1091,6 +1091,8 @@ png_set_sPLT(png_const_structrp png_ptr,
 {
    png_sPLT_tp np;
 
+   png_debug1(1, "in %s storage function", "sPLT");
+
    if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL)
       return;
 
@@ -1565,7 +1567,7 @@ void PNGAPI
 png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
     png_bytepp row_pointers)
 {
-   png_debug1(1, "in %s storage function", "rows");
+   png_debug(1, "in png_set_rows");
 
    if (png_ptr == NULL || info_ptr == NULL)
       return;
@@ -1584,6 +1586,8 @@ png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
 void PNGAPI
 png_set_compression_buffer_size(png_structrp png_ptr, size_t size)
 {
+   png_debug(1, "in png_set_compression_buffer_size");
+
    if (png_ptr == NULL)
       return;
 
@@ -1655,6 +1659,8 @@ void PNGAPI
 png_set_user_limits(png_structrp png_ptr, png_uint_32 user_width_max,
     png_uint_32 user_height_max)
 {
+   png_debug(1, "in png_set_user_limits");
+
    /* Images with dimensions larger than these limits will be
     * rejected by png_set_IHDR().  To accept any PNG datastream
     * regardless of dimensions, set both limits to 0x7fffffff.
@@ -1670,6 +1676,8 @@ png_set_user_limits(png_structrp png_ptr, png_uint_32 user_width_max,
 void PNGAPI
 png_set_chunk_cache_max(png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
 {
+   png_debug(1, "in png_set_chunk_cache_max");
+
    if (png_ptr != NULL)
       png_ptr->user_chunk_cache_max = user_chunk_cache_max;
 }
@@ -1679,6 +1687,8 @@ void PNGAPI
 png_set_chunk_malloc_max(png_structrp png_ptr,
     png_alloc_size_t user_chunk_malloc_max)
 {
+   png_debug(1, "in png_set_chunk_malloc_max");
+
    if (png_ptr != NULL)
       png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
 }
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c
index 89a62191b6f..2350057e70e 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -131,10 +131,10 @@ png_set_interlace_handling(png_structrp png_ptr)
    if (png_ptr != 0 && png_ptr->interlaced != 0)
    {
       png_ptr->transformations |= PNG_INTERLACE;
-      return (7);
+      return 7;
    }
 
-   return (1);
+   return 1;
 }
 #endif
 
@@ -526,6 +526,8 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
    png_bytep dp = row; /* destination pointer */
    png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */
 
+   png_debug(1, "in png_do_strip_channel");
+
    /* At the start sp will point to the first byte to copy and dp to where
     * it is copied to.  ep always points just beyond the end of the row, so
     * the loop simply copies (channels-1) channels until sp reaches ep.
@@ -726,6 +728,8 @@ png_do_bgr(png_row_infop row_info, png_bytep row)
 void /* PRIVATE */
 png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info)
 {
+   png_debug(1, "in png_do_check_palette_indexes");
+
    if (png_ptr->num_palette < (1 << row_info->bit_depth) &&
       png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */
    {
@@ -736,7 +740,7 @@ png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info)
        * forms produced on either GCC or MSVC.
        */
       int padding = PNG_PADBITS(row_info->pixel_depth, row_info->width);
-      png_bytep rp = png_ptr->row_buf + row_info->rowbytes - 1;
+      png_bytep rp = png_ptr->row_buf + row_info->rowbytes;
 
       switch (row_info->bit_depth)
       {
@@ -861,7 +865,7 @@ png_voidp PNGAPI
 png_get_user_transform_ptr(png_const_structrp png_ptr)
 {
    if (png_ptr == NULL)
-      return (NULL);
+      return NULL;
 
    return png_ptr->user_transform_ptr;
 }
diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java
index ebf4950c49a..edb82719788 100644
--- a/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java
@@ -341,7 +341,8 @@ public void handlePropertyNotify(XEvent xev) {
             || ev.get_atom() == XWM.XA_NET_FRAME_EXTENTS.getAtom())
         {
             if (XWM.getWMID() != XWM.UNITY_COMPIZ_WM) {
-                if (getMWMDecorTitleProperty().isPresent()) {
+                if ((XWM.getWMID() == XWM.MUTTER_WM && !isTargetUndecorated() && isVisible())
+                    || getMWMDecorTitleProperty().isPresent()) {
                     // Insets might have changed "in-flight" if that property
                     // is present, so we need to get the actual values of
                     // insets from the WM and propagate them through all the
diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XWM.java b/src/java.desktop/unix/classes/sun/awt/X11/XWM.java
index 43c6a2c4832..dbd9c42bb0c 100644
--- a/src/java.desktop/unix/classes/sun/awt/X11/XWM.java
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XWM.java
@@ -1369,6 +1369,9 @@ Insets guessInsets(XDecoratedPeer window) {
               case UNITY_COMPIZ_WM:
                   res = new Insets(28, 1, 1, 1);
                   break;
+              case MUTTER_WM:
+                  res = new Insets(37, 0, 0, 0);
+                  break;
               case MOTIF_WM:
               case OPENLOOK_WM:
               default:
@@ -1380,6 +1383,7 @@ Insets guessInsets(XDecoratedPeer window) {
         }
         return res;
     }
+
     /*
      * Some buggy WMs ignore window gravity when processing
      * ConfigureRequest and position window as if the gravity is Static.
diff --git a/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java b/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java
index e61fd1a90e6..78661587554 100644
--- a/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java
+++ b/src/java.desktop/unix/classes/sun/awt/screencast/ScreencastHelper.java
@@ -26,15 +26,20 @@
 package sun.awt.screencast;
 
 import sun.awt.UNIXToolkit;
+import sun.java2d.pipe.Region;
 import sun.security.action.GetPropertyAction;
 
+import java.awt.GraphicsConfiguration;
 import java.awt.GraphicsEnvironment;
 import java.awt.Rectangle;
 import java.awt.Toolkit;
+import java.awt.geom.AffineTransform;
 import java.security.AccessController;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.stream.IntStream;
 
 /**
@@ -54,6 +59,13 @@ public class ScreencastHelper {
     private static final int DENIED = -11;
     private static final int OUT_OF_BOUNDS = -12;
 
+    private static final int DELAY_BEFORE_SESSION_CLOSE = 2000;
+
+    private static volatile TimerTask timerTask = null;
+    private static final Timer timerCloseSession
+            = new Timer("auto-close screencast session", true);
+
+
     private ScreencastHelper() {
     }
 
@@ -100,9 +112,37 @@ private static List getSystemScreensBounds() {
                 .stream(GraphicsEnvironment
                         .getLocalGraphicsEnvironment()
                         .getScreenDevices())
-                .map(graphicsDevice ->
-                        graphicsDevice.getDefaultConfiguration().getBounds()
-                ).toList();
+                .map(graphicsDevice -> {
+                    GraphicsConfiguration gc =
+                            graphicsDevice.getDefaultConfiguration();
+                    Rectangle screen = gc.getBounds();
+                    AffineTransform tx = gc.getDefaultTransform();
+
+                    return new Rectangle(
+                            Region.clipRound(screen.x * tx.getScaleX()),
+                            Region.clipRound(screen.y * tx.getScaleY()),
+                            Region.clipRound(screen.width * tx.getScaleX()),
+                            Region.clipRound(screen.height * tx.getScaleY())
+                    );
+                })
+                .toList();
+    }
+
+    private static synchronized native void closeSession();
+
+    private static void timerCloseSessionRestart() {
+        if (timerTask != null) {
+            timerTask.cancel();
+        }
+
+        timerTask = new TimerTask() {
+            @Override
+            public void run() {
+                closeSession();
+            }
+        };
+
+        timerCloseSession.schedule(timerTask, DELAY_BEFORE_SESSION_CLOSE);
     }
 
     public static synchronized void getRGBPixels(
@@ -110,6 +150,8 @@ public static synchronized void getRGBPixels(
     ) {
         if (!IS_NATIVE_LOADED) return;
 
+        timerCloseSessionRestart();
+
         Rectangle captureArea = new Rectangle(x, y, width, height);
 
         List affectedScreenBounds = getSystemScreensBounds()
diff --git a/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java b/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java
index 022ca5e7dbb..3daf9b2a8b8 100644
--- a/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java
+++ b/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,8 @@
 import java.nio.file.WatchKey;
 import java.nio.file.WatchService;
 import java.nio.file.attribute.PosixFilePermission;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
@@ -58,6 +60,7 @@
  * The restore token allows the ScreenCast session to be restored
  * with previously granted screen access permissions.
  */
+@SuppressWarnings("removal")
 final class TokenStorage {
 
     private TokenStorage() {}
@@ -69,8 +72,24 @@ private TokenStorage() {}
     private static final Path PROPS_PATH;
     private static final Path PROP_FILENAME;
 
+    private static void doPrivilegedRunnable(Runnable runnable) {
+        AccessController.doPrivileged(new PrivilegedAction() {
+            @Override
+            public Void run() {
+                runnable.run();
+                return null;
+            }
+        });
+    }
+
     static {
-        PROPS_PATH = setupPath();
+        PROPS_PATH = AccessController.doPrivileged(new PrivilegedAction() {
+            @Override
+            public Path run() {
+                return setupPath();
+            }
+        });
+
         if (PROPS_PATH != null) {
             PROP_FILENAME = PROPS_PATH.getFileName();
             if (SCREENCAST_DEBUG) {
@@ -192,9 +211,9 @@ public void run() {
                     }
 
                     if (kind == ENTRY_CREATE) {
-                        setFilePermission(PROPS_PATH);
+                        doPrivilegedRunnable(() -> setFilePermission(PROPS_PATH));
                     } else if (kind == ENTRY_MODIFY) {
-                        readTokens(PROPS_PATH);
+                        doPrivilegedRunnable(() -> readTokens(PROPS_PATH));
                     } else if (kind == ENTRY_DELETE) {
                         synchronized (PROPS) {
                             PROPS.clear();
@@ -207,24 +226,31 @@ public void run() {
         }
     }
 
+    private static WatchService watchService;
+
     private static void setupWatch() {
-        try {
-            WatchService watchService =
-                    FileSystems.getDefault().newWatchService();
+        doPrivilegedRunnable(() -> {
+            try {
+                watchService =
+                        FileSystems.getDefault().newWatchService();
 
-            PROPS_PATH
-                    .getParent()
-                    .register(watchService,
-                            ENTRY_CREATE,
-                            ENTRY_DELETE,
-                            ENTRY_MODIFY);
+                PROPS_PATH
+                        .getParent()
+                        .register(watchService,
+                                ENTRY_CREATE,
+                                ENTRY_DELETE,
+                                ENTRY_MODIFY);
 
-            new WatcherThread(watchService).start();
-        } catch (Exception e) {
-            if (SCREENCAST_DEBUG) {
-                System.err.printf("Token storage: failed to setup " +
-                        "file watch %s\n", e);
+            } catch (Exception e) {
+                if (SCREENCAST_DEBUG) {
+                    System.err.printf("Token storage: failed to setup " +
+                            "file watch %s\n", e);
+                }
             }
+        });
+
+        if (watchService != null) {
+            new WatcherThread(watchService).start();
         }
     }
 
@@ -276,7 +302,7 @@ private static void storeTokenFromNative(String oldToken,
             }
 
             if (changed) {
-                store("save tokens");
+                doPrivilegedRunnable(() -> store("save tokens"));
             }
         }
     }
@@ -324,10 +350,14 @@ static Set getTokens(List affectedScreenBounds) {
                         return tokenItem;
                     })
                     .filter(Objects::nonNull)
+                    .sorted((t1, t2) -> //Token with more screens preferred
+                            t2.allowedScreensBounds.size()
+                            - t1.allowedScreensBounds.size()
+                    )
                     .toList();
         }
 
-        removeMalformedRecords(malformed);
+        doPrivilegedRunnable(() -> removeMalformedRecords(malformed));
 
         // 1. Try to find exact matches
         for (TokenItem tokenItem : allTokenItems) {
@@ -365,6 +395,17 @@ static Set getTokens(List affectedScreenBounds) {
             System.out.println("// getTokens same sizes 2. " + result);
         }
 
+        // 3. add tokens with the same or greater number of screens
+        // This is useful if we once received a token with one screen resolution
+        // and the same screen was later scaled in the system.
+        // In that case, the token is still valid.
+
+        allTokenItems
+                .stream()
+                .filter(t ->
+                        t.allowedScreensBounds.size() >= affectedScreenBounds.size())
+                .forEach(result::add);
+
         return result;
     }
 
diff --git a/src/java.desktop/unix/native/common/awt/awt_GraphicsEnv.h b/src/java.desktop/unix/native/common/awt/awt_GraphicsEnv.h
index b7e2a71d41c..da6ae0c8117 100644
--- a/src/java.desktop/unix/native/common/awt/awt_GraphicsEnv.h
+++ b/src/java.desktop/unix/native/common/awt/awt_GraphicsEnv.h
@@ -50,8 +50,6 @@
 #define MITSHM_PERM_COMMON (0666)
 #define MITSHM_PERM_OWNER  (0600)
 
-extern int XShmQueryExtension();
-
 void TryInitMITShm(JNIEnv *env, jint *shmExt, jint *shmPixmaps);
 void resetXShmAttachFailed();
 jboolean isXShmAttachFailed();
diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/fp_pipewire.h b/src/java.desktop/unix/native/libawt_xawt/awt/fp_pipewire.h
index 6cfbe41592b..e5985af5eee 100644
--- a/src/java.desktop/unix/native/libawt_xawt/awt/fp_pipewire.h
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/fp_pipewire.h
@@ -58,7 +58,7 @@ void (*fp_pw_stream_destroy)(struct pw_stream *stream);
 
 
 void (*fp_pw_init)(int *argc, char **argv[]);
-
+void (*fp_pw_deinit)(void);
 
 struct pw_core *
 (*fp_pw_context_connect_fd)(struct pw_context *context,
diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c b/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c
index 9f6621ea97d..7dba83e9024 100644
--- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1092,8 +1092,8 @@ static void init_toggle_widget(WidgetType widget_type, gint synth_state)
         ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_FOCUS;
     }
 
-    if ((synth_state & MOUSE_OVER) != 0 && (synth_state & PRESSED) == 0 ||
-           (synth_state & FOCUSED) != 0 && (synth_state & PRESSED) != 0) {
+    if ((((synth_state & MOUSE_OVER) != 0) && ((synth_state & PRESSED) == 0)) ||
+           (((synth_state & FOCUSED) != 0) && ((synth_state & PRESSED) != 0))) {
         gtk2_widget->state = GTK_STATE_PRELIGHT;
     } else if ((synth_state & DISABLED) != 0) {
         gtk2_widget->state = GTK_STATE_INSENSITIVE;
@@ -1465,7 +1465,7 @@ static GtkWidget *gtk2_get_widget(WidgetType widget_type)
             if (init_result = (NULL == gtk2_widgets[_GTK_NOTEBOOK_TYPE]))
             {
                 gtk2_widgets[_GTK_NOTEBOOK_TYPE] =
-                    (*fp_gtk_notebook_new)(NULL);
+                    (*fp_gtk_notebook_new)();
             }
             result = gtk2_widgets[_GTK_NOTEBOOK_TYPE];
             break;
@@ -1473,7 +1473,7 @@ static GtkWidget *gtk2_get_widget(WidgetType widget_type)
             if (init_result = (NULL == gtk2_widgets[_GTK_TOGGLE_BUTTON_TYPE]))
             {
                 gtk2_widgets[_GTK_TOGGLE_BUTTON_TYPE] =
-                    (*fp_gtk_toggle_button_new)(NULL);
+                    (*fp_gtk_toggle_button_new)();
             }
             result = gtk2_widgets[_GTK_TOGGLE_BUTTON_TYPE];
             break;
@@ -1482,7 +1482,7 @@ static GtkWidget *gtk2_get_widget(WidgetType widget_type)
             if (init_result = (NULL == gtk2_widgets[_GTK_TOOLBAR_TYPE]))
             {
                 gtk2_widgets[_GTK_TOOLBAR_TYPE] =
-                    (*fp_gtk_toolbar_new)(NULL);
+                    (*fp_gtk_toolbar_new)();
             }
             result = gtk2_widgets[_GTK_TOOLBAR_TYPE];
             break;
diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c
index 206a91132bc..96abe6aef56 100644
--- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c
@@ -319,6 +319,10 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name)
 
         /* Pixbuf */
         fp_gdk_pixbuf_new = dl_symbol("gdk_pixbuf_new");
+        fp_gdk_pixbuf_new_from_data = dl_symbol("gdk_pixbuf_new_from_data");
+        fp_gdk_pixbuf_scale_simple = dl_symbol("gdk_pixbuf_scale_simple");
+        fp_gdk_pixbuf_copy_area = dl_symbol("gdk_pixbuf_copy_area");
+
         fp_gdk_pixbuf_new_from_file =
                 dl_symbol("gdk_pixbuf_new_from_file");
         fp_gdk_pixbuf_get_from_drawable =
@@ -604,6 +608,7 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name)
 
         fp_g_string_new = dl_symbol("g_string_new");
         fp_g_string_erase = dl_symbol("g_string_erase");
+        fp_g_string_set_size = dl_symbol("g_string_set_size");
         fp_g_string_free = dl_symbol("g_string_free");
 
         glib_version_2_68 = !fp_glib_check_version(2, 68, 0);
@@ -1251,7 +1256,7 @@ static GtkWidget *gtk3_get_widget(WidgetType widget_type)
             if (init_result = (NULL == gtk3_widgets[_GTK_NOTEBOOK_TYPE]))
             {
                 gtk3_widgets[_GTK_NOTEBOOK_TYPE] =
-                    (*fp_gtk_notebook_new)(NULL);
+                    (*fp_gtk_notebook_new)();
             }
             result = gtk3_widgets[_GTK_NOTEBOOK_TYPE];
             break;
@@ -1259,7 +1264,7 @@ static GtkWidget *gtk3_get_widget(WidgetType widget_type)
             if (init_result = (NULL == gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE]))
             {
                 gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE] =
-                    (*fp_gtk_toggle_button_new)(NULL);
+                    (*fp_gtk_toggle_button_new)();
             }
             result = gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE];
             break;
@@ -1268,7 +1273,7 @@ static GtkWidget *gtk3_get_widget(WidgetType widget_type)
             if (init_result = (NULL == gtk3_widgets[_GTK_TOOLBAR_TYPE]))
             {
                 gtk3_widgets[_GTK_TOOLBAR_TYPE] =
-                    (*fp_gtk_toolbar_new)(NULL);
+                    (*fp_gtk_toolbar_new)();
             }
             result = gtk3_widgets[_GTK_TOOLBAR_TYPE];
             break;
@@ -3110,6 +3115,7 @@ static void gtk3_init(GtkApi* gtk) {
 
     gtk->g_string_new = fp_g_string_new;
     gtk->g_string_erase = fp_g_string_erase;
+    gtk->g_string_set_size = fp_g_string_set_size;
     gtk->g_string_free = fp_g_string_free;
     gtk->g_string_replace = fp_g_string_replace;
     gtk->g_string_printf = fp_g_string_printf;
@@ -3118,4 +3124,10 @@ static void gtk3_init(GtkApi* gtk) {
     gtk->g_main_context_iteration = fp_g_main_context_iteration;
     gtk->g_error_free = fp_g_error_free;
     gtk->g_unix_fd_list_get = fp_g_unix_fd_list_get;
+
+    gtk->gdk_pixbuf_new = fp_gdk_pixbuf_new;
+    gtk->gdk_pixbuf_new_from_data = fp_gdk_pixbuf_new_from_data;
+    gtk->gdk_pixbuf_scale_simple = fp_gdk_pixbuf_scale_simple;
+    gtk->gdk_pixbuf_get_pixels = fp_gdk_pixbuf_get_pixels;
+    gtk->gdk_pixbuf_copy_area = fp_gdk_pixbuf_copy_area;
 }
diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h
index 0a3c8364e79..ed5997cb0cd 100644
--- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h
@@ -528,6 +528,30 @@ static void (*fp_gdk_draw_rectangle)(GdkDrawable*, GdkGC*, gboolean,
         gint, gint, gint, gint);
 static GdkPixbuf *(*fp_gdk_pixbuf_new)(GdkColorspace colorspace,
         gboolean has_alpha, int bits_per_sample, int width, int height);
+
+static GdkPixbuf *(*fp_gdk_pixbuf_new_from_data)(
+        const guchar *data,
+        GdkColorspace colorspace,
+        gboolean has_alpha,
+        int bits_per_sample,
+        int width,
+        int height,
+        int rowstride,
+        GdkPixbufDestroyNotify destroy_fn,
+        gpointer destroy_fn_data
+);
+
+static void (*fp_gdk_pixbuf_copy_area) (
+        const GdkPixbuf* src_pixbuf,
+        int src_x,
+        int src_y,
+        int width,
+        int height,
+        GdkPixbuf* dest_pixbuf,
+        int dest_x,
+        int dest_y
+);
+
 static void (*fp_gdk_drawable_get_size)(GdkDrawable *drawable,
         gint* width, gint* height);
 static gboolean (*fp_gtk_init_check)(int* argc, char** argv);
@@ -758,6 +782,9 @@ static GString *(*fp_g_string_erase)(GString *string,
                                      gssize pos,
                                      gssize len);
 
+static GString *(*fp_g_string_set_size)(GString* string,
+                                        gsize len);
+
 static gchar *(*fp_g_string_free)(GString *string,
                                   gboolean free_segment);
 
diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h b/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h
index 9c8c5743f7a..33bd4a6cee8 100644
--- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.h
@@ -532,6 +532,8 @@ typedef void (*GClosureNotify)(gpointer data, GClosure *closure);
 typedef void (*GDestroyNotify)(gpointer data);
 typedef void (*GCallback)(void);
 
+typedef void GdkPixbuf;
+typedef void (* GdkPixbufDestroyNotify) (guchar *pixels, gpointer data);
 
 typedef struct GtkApi {
     int version;
@@ -716,6 +718,10 @@ typedef struct GtkApi {
                                gssize pos,
                                gssize len);
 
+    GString *(*g_string_set_size)(GString* string,
+                                  gsize len);
+
+
     gchar *(*g_string_free)(GString *string,
                             gboolean free_segment);
 
@@ -793,6 +799,46 @@ typedef struct GtkApi {
                                gint index_,
                                GError **error);
 
+    GdkPixbuf *(*gdk_pixbuf_new)(GdkColorspace colorspace,
+                                 gboolean has_alpha,
+                                 int bits_per_sample,
+                                 int width,
+                                 int height);
+
+
+    GdkPixbuf *(*gdk_pixbuf_new_from_data)(
+            const guchar *data,
+            GdkColorspace colorspace,
+            gboolean has_alpha,
+            int bits_per_sample,
+            int width,
+            int height,
+            int rowstride,
+            GdkPixbufDestroyNotify destroy_fn,
+            gpointer destroy_fn_data
+    );
+
+
+    GdkPixbuf *(*gdk_pixbuf_scale_simple)(GdkPixbuf *src,
+                                          int dest_width,
+                                          int dest_heigh,
+                                          GdkInterpType interp_type
+    );
+
+    guchar* (*gdk_pixbuf_get_pixels) (const GdkPixbuf* pixbuf);
+
+
+    void (*gdk_pixbuf_copy_area) (
+            const GdkPixbuf* src_pixbuf,
+            int src_x,
+            int src_y,
+            int width,
+            int height,
+            GdkPixbuf* dest_pixbuf,
+            int dest_x,
+            int dest_y
+    );
+
     /*   */
 } GtkApi;
 
diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c b/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c
index a5443784e00..e2f4ea31d2e 100644
--- a/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c
@@ -43,6 +43,10 @@ int DEBUG_SCREENCAST_ENABLED = FALSE;
                                       (*env)->ExceptionDescribe(env); \
                                    }
 
+static gboolean hasPipewireFailed = FALSE;
+static gboolean sessionClosed = TRUE;
+static GString *activeSessionToken;
+
 struct ScreenSpace screenSpace = {0};
 static struct PwLoopData pw = {0};
 
@@ -85,6 +89,11 @@ static gboolean initScreenSpace() {
 }
 
 static void doCleanup() {
+    if (pw.loop) {
+        DEBUG_SCREENCAST("STOPPING loop\n", NULL);
+        fp_pw_thread_loop_stop(pw.loop);
+    }
+
     for (int i = 0; i < screenSpace.screenCount; ++i) {
         struct ScreenProps *screenProps = &screenSpace.screens[i];
         if (screenProps->data) {
@@ -112,10 +121,7 @@ static void doCleanup() {
         pw.core = NULL;
     }
 
-    DEBUG_SCREENCAST("STOPPING loop\n", NULL)
-
     if (pw.loop) {
-        fp_pw_thread_loop_stop(pw.loop);
         fp_pw_thread_loop_destroy(pw.loop);
         pw.loop = NULL;
     }
@@ -123,7 +129,15 @@ static void doCleanup() {
     if (screenSpace.screens) {
         free(screenSpace.screens);
         screenSpace.screens = NULL;
+        screenSpace.screenCount = 0;
+    }
+
+    if (!sessionClosed) {
+        fp_pw_deinit();
     }
+
+    gtk->g_string_set_size(activeSessionToken, 0);
+    sessionClosed = TRUE;
 }
 
 /**
@@ -132,6 +146,24 @@ static void doCleanup() {
 static gboolean initScreencast(const gchar *token,
                                GdkRectangle *affectedBounds,
                                gint affectedBoundsLength) {
+    gboolean isSameToken = !token
+            ? FALSE
+            : strcmp(token, activeSessionToken->str) == 0;
+
+    if (!sessionClosed) {
+        if (isSameToken) {
+            DEBUG_SCREENCAST("Reusing active session.\n", NULL);
+            return TRUE;
+        } else {
+            DEBUG_SCREENCAST(
+                    "Active session has a different token |%s| -> |%s|,"
+                    " closing current session.\n",
+                    activeSessionToken->str, token
+            );
+            doCleanup();
+        }
+    }
+
     fp_pw_init(NULL, NULL);
 
     pw.pwFd = RESULT_ERROR;
@@ -145,52 +177,12 @@ static gboolean initScreencast(const gchar *token,
         return FALSE;
     }
 
+    gtk->g_string_printf(activeSessionToken, "%s", token);
+    hasPipewireFailed = FALSE;
+    sessionClosed = FALSE;
     return TRUE;
 }
 
-static inline void convertRGBxToBGRx(int* in) {
-    char* o = (char*) in;
-    char tmp = o[0];
-    o[0] = o[2];
-    o[2] = tmp;
-}
-
-static gchar * cropTo(
-        struct spa_data data,
-        struct spa_video_info_raw raw,
-        guint32 x,
-        guint32 y,
-        guint32 width,
-        guint32 height
-) {
-    int srcW = raw.size.width;
-    if (data.chunk->stride / 4 != srcW) {
-        fprintf(stderr, "%s:%i Unexpected stride / 4: %i srcW: %i\n",
-                __func__, __LINE__, data.chunk->stride / 4, srcW);
-    }
-
-    int* d = data.data;
-
-    int *outData = calloc(width * height, sizeof(int));
-    if (!outData) {
-        ERR("failed to allocate memory\n");
-        return NULL;
-    }
-
-    gboolean needConversion = raw.format != SPA_VIDEO_FORMAT_BGRx;
-    for (guint32 j = y; j < y + height; ++j) {
-        for (guint32 i = x; i < x + width; ++i) {
-            int color = *(d + (j * srcW) + i);
-            if (needConversion) {
-                convertRGBxToBGRx(&color);
-            }
-            *(outData + ((j - y) * width) + (i - x)) = color;
-        }
-    }
-
-    return (gchar*) outData;
-}
-
 static void onStreamParamChanged(
         void *userdata,
         uint32_t id,
@@ -274,29 +266,88 @@ static void onStreamProcess(void *userdata) {
 
     struct spa_data spaData = spaBuffer->datas[0];
 
+    gint streamWidth = data->rawFormat.size.width;
+    gint streamHeight = data->rawFormat.size.height;
+
     DEBUG_SCREEN(screen);
     DEBUG_SCREEN_PREFIX(screen,
                         "got a frame of size %d offset %d stride %d "
-                        "flags %d FD %li captureDataReady %i\n",
+                        "flags %d FD %li captureDataReady %i of stream %dx%d\n",
                         spaBuffer->datas[0].chunk->size,
                         spaData.chunk->offset,
                         spaData.chunk->stride,
                         spaData.chunk->flags,
                         spaData.fd,
-                        screen->captureDataReady
+                        screen->captureDataReady,
+                        streamWidth,
+                        streamHeight
     );
 
-    data->screenProps->captureData = cropTo(
-            spaData,
-            data->rawFormat,
-            screen->captureArea.x, screen->captureArea.y,
-            screen->captureArea.width, screen->captureArea.height
-    );
+    GdkRectangle captureArea = screen->captureArea;
+    GdkRectangle screenBounds = screen->bounds;
+
+    GdkPixbuf *pixbuf = gtk->gdk_pixbuf_new_from_data(spaData.data,
+                                                      GDK_COLORSPACE_RGB,
+                                                      TRUE,
+                                                      8,
+                                                      streamWidth,
+                                                      streamHeight,
+                                                      spaData.chunk->stride,
+                                                      NULL,
+                                                      NULL);
+
+    if (screen->bounds.width != streamWidth
+        || screen->bounds.height != streamHeight) {
+
+        DEBUG_SCREEN_PREFIX(screen, "scaling stream data %dx%d -> %dx%d\n",
+                         streamWidth, streamHeight,
+                         screen->bounds.width, screen->bounds.height
+        );
+
+        GdkPixbuf *scaled = gtk->gdk_pixbuf_scale_simple(pixbuf,
+                                                         screen->bounds.width,
+                                                         screen->bounds.height,
+                                                         GDK_INTERP_BILINEAR);
+
+        gtk->g_object_unref(pixbuf);
+        pixbuf = scaled;
+    }
+
+    GdkPixbuf *cropped = NULL;
+    if (captureArea.width != screenBounds.width
+        || captureArea.height != screenBounds.height) {
+
+        cropped = gtk->gdk_pixbuf_new(GDK_COLORSPACE_RGB,
+                                      TRUE,
+                                      8,
+                                      captureArea.width,
+                                      captureArea.height);
+        if (cropped) {
+            gtk->gdk_pixbuf_copy_area(pixbuf,
+                                      captureArea.x,
+                                      captureArea.y,
+                                      captureArea.width,
+                                      captureArea.height,
+                                      cropped,
+                                      0, 0);
+        } else {
+            ERR("Cannot create a new pixbuf.\n");
+        }
+
+        gtk->g_object_unref(pixbuf);
+        pixbuf = NULL;
+
+        data->screenProps->captureDataPixbuf = cropped;
+    } else {
+        data->screenProps->captureDataPixbuf = pixbuf;
+    }
 
     screen->captureDataReady = TRUE;
 
     DEBUG_SCREEN_PREFIX(screen, "data ready\n", NULL);
     fp_pw_stream_queue_buffer(data->stream, pwBuffer);
+
+    fp_pw_thread_loop_signal(pw.loop, FALSE);
 }
 
 static void onStreamStateChanged(
@@ -310,6 +361,12 @@ static void onStreamStateChanged(
                      old, fp_pw_stream_state_as_string(old),
                      state, fp_pw_stream_state_as_string(state),
                      error);
+    if (state == PW_STREAM_STATE_ERROR
+        || state == PW_STREAM_STATE_UNCONNECTED) {
+
+        hasPipewireFailed = TRUE;
+        fp_pw_thread_loop_signal(pw.loop, FALSE);
+    }
 }
 
 static const struct pw_stream_events streamEvents = {
@@ -339,11 +396,7 @@ static bool startStream(
             SPA_FORMAT_mediaSubtype,
             SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
             SPA_FORMAT_VIDEO_format,
-            SPA_POD_CHOICE_ENUM_Id(
-                    2,
-                    SPA_VIDEO_FORMAT_RGBx,
-                    SPA_VIDEO_FORMAT_BGRx
-            ),
+            SPA_POD_Id(SPA_VIDEO_FORMAT_BGRx),
             SPA_FORMAT_VIDEO_size,
             SPA_POD_CHOICE_RANGE_Rectangle(
                     &SPA_RECTANGLE(320, 240),
@@ -386,8 +439,19 @@ static gboolean connectStream(int index) {
 
     data->screenProps = &screenSpace.screens[index];
 
-    data->hasFormat = FALSE;
+    if (!sessionClosed && data->stream) {
+        fp_pw_thread_loop_lock(pw.loop);
+        int result = fp_pw_stream_set_active(data->stream, TRUE);
+        fp_pw_thread_loop_unlock(pw.loop);
+
+        DEBUG_SCREEN_PREFIX(data->screenProps,
+                            "stream %p: activate result |%i|\n",
+                            data->stream, result);
 
+        return result == 0; // 0 - success
+    };
+
+    data->hasFormat = FALSE;
 
     data->stream = fp_pw_stream_new(
             pw.core,
@@ -425,6 +489,11 @@ static gboolean connectStream(int index) {
 
     while (!data->hasFormat) {
         fp_pw_thread_loop_wait(pw.loop);
+        fp_pw_thread_loop_accept(pw.loop);
+        if (hasPipewireFailed) {
+            fp_pw_thread_loop_unlock(pw.loop);
+            return FALSE;
+        }
     }
 
     DEBUG_SCREEN_PREFIX(data->screenProps,
@@ -432,8 +501,6 @@ static gboolean connectStream(int index) {
             data->rawFormat.size.width, data->rawFormat.size.height
     );
 
-    fp_pw_thread_loop_accept(pw.loop);
-
     return TRUE;
 }
 
@@ -491,7 +558,12 @@ static void onCoreError(
             "!!! pipewire error: id %u, seq: %d, res: %d (%s): %s\n",
             id, seq, res, strerror(res), message
     );
-    fp_pw_thread_loop_unlock(pw.loop);
+    if (id == PW_ID_CORE) {
+        fp_pw_thread_loop_lock(pw.loop);
+        hasPipewireFailed = TRUE;
+        fp_pw_thread_loop_signal(pw.loop, FALSE);
+        fp_pw_thread_loop_unlock(pw.loop);
+    }
 }
 
 static const struct pw_core_events coreEvents = {
@@ -505,60 +577,66 @@ static const struct pw_core_events coreEvents = {
  * @return TRUE on success
  */
 static gboolean doLoop(GdkRectangle requestedArea) {
-    pw.loop = fp_pw_thread_loop_new("AWT Pipewire Thread", NULL);
+    gboolean isLoopLockTaken = FALSE;
+    if (!pw.loop && !sessionClosed) {
+        pw.loop = fp_pw_thread_loop_new("AWT Pipewire Thread", NULL);
 
-    if (!pw.loop) {
-        DEBUG_SCREENCAST("!!! Could not create a loop\n", NULL);
-        doCleanup();
-        return FALSE;
-    }
-
-    pw.context = fp_pw_context_new(
-            fp_pw_thread_loop_get_loop(pw.loop),
-            NULL,
-            0
-    );
-
-    if (!pw.context) {
-        DEBUG_SCREENCAST("!!! Could not create a pipewire context\n", NULL);
-        doCleanup();
-        return FALSE;
-    }
+        if (!pw.loop) {
+            DEBUG_SCREENCAST("!!! Could not create a loop\n", NULL);
+            doCleanup();
+            return FALSE;
+        }
 
-    if (fp_pw_thread_loop_start(pw.loop) != 0) {
-        DEBUG_SCREENCAST("!!! Could not start pipewire thread loop\n", NULL);
-        doCleanup();
-        return FALSE;
-    }
+        pw.context = fp_pw_context_new(
+                fp_pw_thread_loop_get_loop(pw.loop),
+                NULL,
+                0
+        );
 
-    fp_pw_thread_loop_lock(pw.loop);
+        if (!pw.context) {
+            DEBUG_SCREENCAST("!!! Could not create a pipewire context\n", NULL);
+            doCleanup();
+            return FALSE;
+        }
 
-    pw.core = fp_pw_context_connect_fd(
-            pw.context,
-            pw.pwFd,
-            NULL,
-            0
-    );
+        if (fp_pw_thread_loop_start(pw.loop) != 0) {
+            DEBUG_SCREENCAST("!!! Could not start pipewire thread loop\n", NULL);
+            doCleanup();
+            return FALSE;
+        }
 
-    if (!pw.core) {
-        DEBUG_SCREENCAST("!!! Could not create pipewire core\n", NULL);
-        goto fail;
-    }
+        fp_pw_thread_loop_lock(pw.loop);
+        isLoopLockTaken = TRUE;
 
-    pw_core_add_listener(pw.core, &pw.coreListener, &coreEvents, NULL);
+        pw.core = fp_pw_context_connect_fd(
+                pw.context,
+                pw.pwFd,
+                NULL,
+                0
+        );
 
-    for (int i = 0; i < screenSpace.screenCount; ++i) {
-        struct PwStreamData *data =
-                (struct PwStreamData*) malloc(sizeof (struct PwStreamData));
-        if (!data) {
-            ERR("failed to allocate memory\n");
+        if (!pw.core) {
+            DEBUG_SCREENCAST("!!! Could not create pipewire core\n", NULL);
             goto fail;
         }
 
-        memset(data, 0, sizeof (struct PwStreamData));
+        pw_core_add_listener(pw.core, &pw.coreListener, &coreEvents, NULL);
+    }
 
+    for (int i = 0; i < screenSpace.screenCount; ++i) {
         struct ScreenProps *screen = &screenSpace.screens[i];
-        screen->data = data;
+        if (!screen->data && !sessionClosed) {
+            struct PwStreamData *data =
+                    (struct PwStreamData*) malloc(sizeof (struct PwStreamData));
+            if (!data) {
+                ERR("failed to allocate memory\n");
+                goto fail;
+            }
+
+            memset(data, 0, sizeof (struct PwStreamData));
+
+            screen->data = data;
+        }
 
         DEBUG_SCREEN_PREFIX(screen, "@@@ adding screen %i\n", i);
         if (checkScreen(i, requestedArea)) {
@@ -569,12 +647,16 @@ static gboolean doLoop(GdkRectangle requestedArea) {
         DEBUG_SCREEN_PREFIX(screen, "@@@ screen processed %i\n", i);
     }
 
-    fp_pw_thread_loop_unlock(pw.loop);
+    if (isLoopLockTaken) {
+        fp_pw_thread_loop_unlock(pw.loop);
+    }
 
     return TRUE;
 
     fail:
-        fp_pw_thread_loop_unlock(pw.loop);
+        if (isLoopLockTaken) {
+            fp_pw_thread_loop_unlock(pw.loop);
+        }
         doCleanup();
         return FALSE;
 }
@@ -630,6 +712,7 @@ static gboolean loadSymbols() {
     LOAD_SYMBOL(fp_pw_stream_disconnect, "pw_stream_disconnect");
     LOAD_SYMBOL(fp_pw_stream_destroy, "pw_stream_destroy");
     LOAD_SYMBOL(fp_pw_init, "pw_init");
+    LOAD_SYMBOL(fp_pw_deinit, "pw_deinit");
     LOAD_SYMBOL(fp_pw_context_connect_fd, "pw_context_connect_fd");
     LOAD_SYMBOL(fp_pw_core_disconnect, "pw_core_disconnect");
     LOAD_SYMBOL(fp_pw_context_new, "pw_context_new");
@@ -746,6 +829,8 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_screencast_ScreencastHelper_loadPipewire
         return JNI_FALSE;
     }
 
+    activeSessionToken = gtk->g_string_new("");
+
     gboolean usable = initXdgDesktopPortal();
     portalScreenCastCleanup();
     return usable;
@@ -783,6 +868,44 @@ static void arrayToRectangles(JNIEnv *env,
     (*env)->ReleaseIntArrayElements(env, boundsArray, body, 0);
 }
 
+static int makeScreencast(
+        const gchar *token,
+        GdkRectangle *requestedArea,
+        GdkRectangle *affectedScreenBounds,
+        gint affectedBoundsLength
+) {
+    if (!initScreencast(token, affectedScreenBounds, affectedBoundsLength)) {
+        return pw.pwFd;
+    }
+
+    if (!doLoop(*requestedArea)) {
+        return RESULT_ERROR;
+    }
+
+    while (!isAllDataReady()) {
+        fp_pw_thread_loop_lock(pw.loop);
+        fp_pw_thread_loop_wait(pw.loop);
+        fp_pw_thread_loop_unlock(pw.loop);
+        if (hasPipewireFailed) {
+            doCleanup();
+            return RESULT_ERROR;
+        }
+    }
+
+    return RESULT_OK;
+}
+
+/*
+ * Class:     sun_awt_screencast_ScreencastHelper
+ * Method:    closeSession
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_sun_awt_screencast_ScreencastHelper_closeSession(JNIEnv *env, jclass cls) {
+    DEBUG_SCREENCAST("closing screencast session\n\n", NULL);
+    doCleanup();
+}
+
 /*
  * Class:     sun_awt_screencast_ScreencastHelper
  * Method:    getRGBPixelsImpl
@@ -805,7 +928,7 @@ JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl
         boundsLen = (*env)->GetArrayLength(env, affectedScreensBoundsArray);
         EXCEPTION_CHECK_DESCRIBE();
         if (boundsLen % 4 != 0) {
-            DEBUG_SCREENCAST("%s:%i incorrect array length\n", __FUNCTION__, __LINE__);
+            DEBUG_SCREENCAST("incorrect array length\n", NULL);
             return RESULT_ERROR;
         }
         affectedBoundsLength = boundsLen / 4;
@@ -828,18 +951,22 @@ JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl
             jx, jy, jwidth, jheight, token
     );
 
-    if (!initScreencast(token, affectedScreenBounds, affectedBoundsLength)) {
-        releaseToken(env, jtoken, token);
-        return pw.pwFd;
-    }
-
-    if (!doLoop(requestedArea)) {
-        releaseToken(env, jtoken, token);
-        return RESULT_ERROR;
-    }
+    int attemptResult = makeScreencast(
+        token, &requestedArea, affectedScreenBounds, affectedBoundsLength);
 
-    while (!isAllDataReady()) {
-        fp_pw_thread_loop_wait(pw.loop);
+    if (attemptResult) {
+        if (attemptResult == RESULT_DENIED) {
+            releaseToken(env, jtoken, token);
+            return attemptResult;
+        }
+        DEBUG_SCREENCAST("Screencast attempt failed with %i, re-trying...\n",
+                         attemptResult);
+        attemptResult = makeScreencast(
+            token, &requestedArea, affectedScreenBounds, affectedBoundsLength);
+        if (attemptResult) {
+            releaseToken(env, jtoken, token);
+            return attemptResult;
+        }
     }
 
     DEBUG_SCREENCAST("\nall data ready\n", NULL);
@@ -855,7 +982,7 @@ JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl
                                 "\t||\tx %5i y %5i w %5i h %5i %s\n"
                                 "\t||\tx %5i y %5i w %5i h %5i %s\n"
                                 "\t||\tx %5i y %5i w %5i h %5i %s\n\n",
-                                i, screenProps->captureData,
+                                i, screenProps->captureDataPixbuf,
                                 requestedArea.x, requestedArea.y,
                                 requestedArea.width, requestedArea.height,
                                 "requested area",
@@ -869,7 +996,7 @@ JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl
                                 "in-screen coords capture area"
             );
 
-            if (screenProps->captureData) {
+            if (screenProps->captureDataPixbuf) {
                 for (int y = 0; y < captureArea.height; y++) {
                     jsize preY = (requestedArea.y > screenProps->bounds.y)
                             ? 0
@@ -884,23 +1011,28 @@ JNIEXPORT jint JNICALL Java_sun_awt_screencast_ScreencastHelper_getRGBPixelsImpl
                     (*env)->SetIntArrayRegion(
                             env, pixelArray,
                             start, len,
-                            ((jint *) screenProps->captureData)
-                                + (captureArea.width * y)
+                            ((jint *) gtk->gdk_pixbuf_get_pixels(
+                                    screenProps->captureDataPixbuf
+                            ))
+                            + (captureArea.width * y)
                     );
                 }
             }
 
-            free(screenProps->captureData);
-            screenProps->captureData = NULL;
+            if (screenProps->captureDataPixbuf) {
+                gtk->g_object_unref(screenProps->captureDataPixbuf);
+                screenProps->captureDataPixbuf = NULL;
+            }
             screenProps->shouldCapture = FALSE;
 
             fp_pw_thread_loop_lock(pw.loop);
             fp_pw_stream_set_active(screenProps->data->stream, FALSE);
-            fp_pw_stream_disconnect(screenProps->data->stream);
             fp_pw_thread_loop_unlock(pw.loop);
+
+            screenProps->captureDataReady = FALSE;
         }
     }
-    doCleanup();
+
     releaseToken(env, jtoken, token);
     return 0;
 }
diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.h b/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.h
index 29b6fa00d15..07a7e91304c 100644
--- a/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.h
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.h
@@ -48,7 +48,7 @@ struct ScreenProps {
     GdkRectangle captureArea;
     struct PwStreamData *data;
 
-    gchar *captureData;
+    GdkPixbuf *captureDataPixbuf;
     volatile gboolean shouldCapture;
     volatile gboolean captureDataReady;
 };
diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.c b/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.c
index e314359a325..8590cf27da2 100644
--- a/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.c
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/screencast_portal.c
@@ -777,6 +777,10 @@ int portalScreenCastOpenPipewireRemote() {
 }
 
 void portalScreenCastCleanup() {
+    if (!portal) {
+        return;
+    }
+
     if (portal->screenCastSessionHandle) {
         gtk->g_dbus_connection_call_sync(
                 portal->connection,
@@ -796,9 +800,6 @@ void portalScreenCastCleanup() {
         portal->screenCastSessionHandle = NULL;
     }
 
-    if (!portal) {
-        return;
-    }
     if (portal->connection) {
         gtk->g_object_unref(portal->connection);
         portal->connection = NULL;
diff --git a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java
index c75d7738144..20df99eb7d6 100644
--- a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java
+++ b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -522,7 +522,7 @@ static int compareShellFolders(Win32ShellFolder2 sf1, Win32ShellFolder2 sf2) {
         boolean special1 = sf1.isSpecial();
         boolean special2 = sf2.isSpecial();
 
-        if (special1 || special2) {
+        if (special1 && special2) {
             if (topFolderList == null) {
                 ArrayList tmpTopFolderList = new ArrayList<>();
                 tmpTopFolderList.add(Win32ShellFolderManager2.getPersonal());
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/dv/SchemaDVFactory.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/dv/SchemaDVFactory.java
index f81b7cf41ee..85d4ac0a50c 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/dv/SchemaDVFactory.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/dv/SchemaDVFactory.java
@@ -53,7 +53,7 @@ public abstract class SchemaDVFactory {
      * @exception DVFactoryException  cannot create an instance of the specified
      *                                class name or the default class name
      */
-    public static synchronized final SchemaDVFactory getInstance() throws DVFactoryException {
+    public static final SchemaDVFactory getInstance() throws DVFactoryException {
         return getInstance(DEFAULT_FACTORY_CLASS);
     } //getInstance():  SchemaDVFactory
 
@@ -66,7 +66,7 @@ public static synchronized final SchemaDVFactory getInstance() throws DVFactoryE
      * @exception DVFactoryException  cannot create an instance of the specified
      *                                class name or the default class name
      */
-    public static synchronized final SchemaDVFactory getInstance(String factoryClass) throws DVFactoryException {
+    public static final SchemaDVFactory getInstance(String factoryClass) throws DVFactoryException {
 
         try {
             // if the class name is not specified, use the default one
@@ -78,7 +78,7 @@ public static synchronized final SchemaDVFactory getInstance(String factoryClass
     }
 
     // can't create a new object of this class
-    protected SchemaDVFactory(){}
+    protected SchemaDVFactory() {}
 
     /**
      * Get a built-in simple type of the given name
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
index 5f2a5820e03..9d7bd1f068e 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
@@ -1569,8 +1569,15 @@ public void visitSelect(JCFieldAccess tree) {
         public void visitVarDef(JCVariableDecl tree) {
             TranslationContext context = context();
             if (context != null && context instanceof LambdaTranslationContext lambdaContext) {
-                if (frameStack.head.tree.hasTag(LAMBDA)) {
-                    lambdaContext.addSymbol(tree.sym, LOCAL_VAR);
+                for (Frame frame : frameStack) {
+                    if (frame.tree.hasTag(VARDEF)) {
+                        //skip variable frames inside a lambda:
+                        continue;
+                    } else if (frame.tree.hasTag(LAMBDA)) {
+                        lambdaContext.addSymbol(tree.sym, LOCAL_VAR);
+                    } else {
+                        break;
+                    }
                 }
                 // Check for type variables (including as type arguments).
                 // If they occur within class nested in a lambda, mark for erasure
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java
index 59568aef605..2cced809afd 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java
@@ -908,6 +908,7 @@ public void resolve(VarSymbol commonBinding,
             } else if (currentBinding != null &&
                        commonBinding.type.tsym == currentBinding.type.tsym &&
                        !previousNullable &&
+                       !currentNullable &&
                        new TreeDiffer(List.of(commonBinding), List.of(currentBinding))
                                .scan(commonNestedExpression, currentNestedExpression)) {
                 accummulator.add(c.head);
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java
index d8477217947..d04776a0384 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -454,12 +454,26 @@ private void initialize() throws PKCS11Exception {
             if (session == null) {
                 session = token.getOpSession();
             }
-            if (encrypt) {
-                token.p11.C_EncryptInit(session.id(), mechWithParams,
-                    p11KeyID);
+
+            if (type == Transformation.AES_GCM) {
+                CK_VERSION cryptokiVersion = token.p11.getVersion();
+                boolean useNormativeMechFirst = cryptokiVersion.major > 2 ||
+                    (cryptokiVersion.major == 2  && cryptokiVersion.minor >= 40);
+                if (encrypt) {
+                    token.p11.C_GCMEncryptInitWithRetry(session.id(), mechWithParams,
+                        p11KeyID, useNormativeMechFirst);
+                } else {
+                    token.p11.C_GCMDecryptInitWithRetry(session.id(), mechWithParams,
+                        p11KeyID, useNormativeMechFirst);
+                }
             } else {
-                token.p11.C_DecryptInit(session.id(), mechWithParams,
-                    p11KeyID);
+                if (encrypt) {
+                    token.p11.C_EncryptInit(session.id(), mechWithParams,
+                        p11KeyID);
+                } else {
+                    token.p11.C_DecryptInit(session.id(), mechWithParams,
+                        p11KeyID);
+                }
             }
         } catch (PKCS11Exception e) {
             p11Key.releaseKeyID();
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java
index 4b06daaf264..0fd13fd6fa6 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java
@@ -799,6 +799,24 @@ public native long[] C_FindObjects(long hSession, long ulMaxObjectCount)
     public native void C_EncryptInit(long hSession, CK_MECHANISM pMechanism,
             long hKey) throws PKCS11Exception;
 
+    /**
+     * C_GCMEncryptInitWithRetry initializes a GCM encryption operation and retry
+     * with alternative param structure for max compatibility.
+     * (Encryption and decryption)
+     *
+     * @param hSession the session's handle
+     *         (PKCS#11 param: CK_SESSION_HANDLE hSession)
+     * @param pMechanism the encryption mechanism
+     *         (PKCS#11 param: CK_MECHANISM_PTR pMechanism)
+     * @param hKey the handle of the encryption key
+     *         (PKCS#11 param: CK_OBJECT_HANDLE hKey)
+     * @param useNormativeVerFirst whether to use normative version of GCM parameter first
+     * @exception PKCS11Exception If function returns other value than CKR_OK.
+     * @preconditions
+     * @postconditions
+     */
+    public native void C_GCMEncryptInitWithRetry(long hSession, CK_MECHANISM pMechanism,
+            long hKey, boolean useNormativeVerFirst) throws PKCS11Exception;
 
     /**
      * C_Encrypt encrypts single-part data.
@@ -893,6 +911,24 @@ public native int C_EncryptFinal(long hSession, long directOut, byte[] out,
     public native void C_DecryptInit(long hSession, CK_MECHANISM pMechanism,
             long hKey) throws PKCS11Exception;
 
+    /**
+     * C_GCMDecryptInitWithRetry initializes a GCM decryption operation
+     * with alternative param structure for max compatibility.
+     * (Encryption and decryption)
+     *
+     * @param hSession the session's handle
+     *         (PKCS#11 param: CK_SESSION_HANDLE hSession)
+     * @param pMechanism the decryption mechanism
+     *         (PKCS#11 param: CK_MECHANISM_PTR pMechanism)
+     * @param hKey the handle of the decryption key
+     *         (PKCS#11 param: CK_OBJECT_HANDLE hKey)
+     * @param useNormativeVerFirst whether to use normative version of GCM parameter first
+     * @exception PKCS11Exception If function returns other value than CKR_OK.
+     * @preconditions
+     * @postconditions
+     */
+    public native void C_GCMDecryptInitWithRetry(long hSession, CK_MECHANISM pMechanism,
+            long hKey, boolean useNormativeVerFirst) throws PKCS11Exception;
 
     /**
      * C_Decrypt decrypts encrypted data in a single part.
diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c
index 53ee635a24c..986ef9799c4 100644
--- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c
+++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
  */
 
 /* Copyright  (c) 2002 Graz University of Technology. All rights reserved.
@@ -1014,18 +1014,19 @@ jAesCtrParamsToCKAesCtrParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
 }
 
 /*
- * converts the Java CK_GCM_PARAMS object to a CK_GCM_PARAMS_NO_IVBITS pointer
- * Note: Need to try NSS definition first to avoid SIGSEGV.
+ * converts the Java CK_GCM_PARAMS object to a CK_GCM_PARAMS pointer
+ * Note: Early NSS versions crash w/ CK_GCM_PARAMS and need to use
+ * CK_GCM_PARAMS_NO_IVBITS to avoid SIGSEGV.
  *
  * @param env - used to call JNI funktions to get the Java classes and objects
  * @param jParam - the Java CK_GCM_PARAMS object to convert
  * @param pLength - length of the allocated memory of the returned pointer
- * @return pointer to the new CK_GCM_PARAMS_NO_IVBITS structure
+ * @return pointer to the new CK_GCM_PARAMS structure
  */
-CK_GCM_PARAMS_NO_IVBITS_PTR
+CK_GCM_PARAMS_PTR
 jGCMParamsToCKGCMParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
 {
-    CK_GCM_PARAMS_NO_IVBITS_PTR ckParamPtr;
+    CK_GCM_PARAMS_PTR ckParamPtr;
     jclass jGcmParamsClass;
     jfieldID fieldID;
     jobject jIv, jAad;
@@ -1053,8 +1054,8 @@ jGCMParamsToCKGCMParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
     if (fieldID == NULL) { return NULL; }
     jTagLen = (*env)->GetLongField(env, jParam, fieldID);
 
-    // allocate memory for CK_GCM_PARAMS_NO_IVBITS pointer
-    ckParamPtr = calloc(1, sizeof(CK_GCM_PARAMS_NO_IVBITS));
+    // allocate memory for CK_GCM_PARAMS pointer
+    ckParamPtr = calloc(1, sizeof(CK_GCM_PARAMS));
     if (ckParamPtr == NULL) {
         p11ThrowOutOfMemoryError(env, 0);
         return NULL;
@@ -1065,6 +1066,8 @@ jGCMParamsToCKGCMParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
     if ((*env)->ExceptionCheck(env)) {
         goto cleanup;
     }
+    // adjust since the value is in bits
+    ckParamPtr->ulIvBits = ckParamPtr->ulIvLen << 3;
 
     jByteArrayToCKByteArray(env, jAad, &(ckParamPtr->pAAD), &(ckParamPtr->ulAADLen));
     if ((*env)->ExceptionCheck(env)) {
@@ -1074,9 +1077,9 @@ jGCMParamsToCKGCMParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
     ckParamPtr->ulTagBits = jLongToCKULong(jTagLen);
 
     if (pLength != NULL) {
-        *pLength = sizeof(CK_GCM_PARAMS_NO_IVBITS);
+        *pLength = sizeof(CK_GCM_PARAMS);
     }
-    TRACE1("Created inner GCM_PARAMS PTR w/o ulIvBits %p\n", ckParamPtr);
+    TRACE1("Created inner GCM_PARAMS PTR %p\n", ckParamPtr);
     return ckParamPtr;
 cleanup:
     free(ckParamPtr->pIv);
diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_crypt.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_crypt.c
index 6d8cca4da83..d969fabffd0 100644
--- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_crypt.c
+++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_crypt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
  */
 
 /* Copyright  (c) 2002 Graz University of Technology. All rights reserved.
@@ -72,7 +72,6 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptInit
 {
     CK_SESSION_HANDLE ckSessionHandle;
     CK_MECHANISM_PTR ckpMechanism = NULL;
-    CK_MECHANISM_PTR ckpTemp;
     CK_OBJECT_HANDLE ckKeyHandle;
     CK_RV rv;
 
@@ -90,20 +89,60 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptInit
     rv = (*ckpFunctions->C_EncryptInit)(ckSessionHandle, ckpMechanism,
                                         ckKeyHandle);
 
-    if (ckpMechanism->mechanism == CKM_AES_GCM) {
-        if (rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_PARAM_INVALID) {
-            // retry with CKM_GCM_PARAMS structure in pkcs11t.h
-            TRACE0("DEBUG C_EncryptInit: retry with CK_GCM_PARAMS\n");
-            ckpTemp = updateGCMParams(env, ckpMechanism);
-            if (ckpTemp != NULL) { // only re-call if conversion succeeds
-                ckpMechanism = ckpTemp;
-                rv = (*ckpFunctions->C_EncryptInit)(ckSessionHandle, ckpMechanism,
-                        ckKeyHandle);
-            }
+    TRACE1("DEBUG C_EncryptInit: freed pMech = %p\n", ckpMechanism);
+    freeCKMechanismPtr(ckpMechanism);
+    if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
+
+    TRACE0("FINISHED\n");
+}
+
+/*
+ * Class:     sun_security_pkcs11_wrapper_PKCS11
+ * Method:    C_GCMEncryptInitWithRetry
+ * Signature: (JLsun/security/pkcs11/wrapper/CK_MECHANISM;JZ)V
+ * Parametermapping:                    *PKCS11*
+ * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
+ * @param   jobject jMechanism          CK_MECHANISM_PTR pMechanism
+ * @param   jlong jKeyHandle            CK_OBJECT_HANDLE hKey
+ * @param   jboolean useNormVerFirst    CK_BBOOL retry (only retry if the first
+ *                                      init uses the non-normative version)
+ */
+JNIEXPORT void JNICALL
+Java_sun_security_pkcs11_wrapper_PKCS11_C_1GCMEncryptInitWithRetry
+(JNIEnv *env, jobject obj, jlong jSessionHandle,
+ jobject jMechanism, jlong jKeyHandle, jboolean useNormVerFirst)
+{
+    CK_SESSION_HANDLE ckSessionHandle;
+    CK_MECHANISM_PTR ckpMechanism = NULL;
+    CK_OBJECT_HANDLE ckKeyHandle;
+    CK_BBOOL retry = FALSE;
+    CK_RV rv = 1;
+
+    CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
+    if (ckpFunctions == NULL) { return; }
+
+    ckSessionHandle = jLongToCKULong(jSessionHandle);
+    ckKeyHandle = jLongToCKULong(jKeyHandle);
+    ckpMechanism = jMechanismToCKMechanismPtr(env, jMechanism);
+
+    if ((*env)->ExceptionCheck(env)) { return; }
+
+    // if !useNormVerFirst, then update 'ckpMechanism' in place w/
+    // non-normative GCM params.
+    retry = (!useNormVerFirst && updateGCMParams(env, ckpMechanism) != NULL);
+
+    rv = (*ckpFunctions->C_EncryptInit)(ckSessionHandle, ckpMechanism, ckKeyHandle);
+
+    if (rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_PARAM_INVALID) {
+        // retry and update 'ckpMechanism' in place w/ normative GCM params.
+        if (retry && updateGCMParams(env, ckpMechanism) != NULL) {
+            TRACE0("DEBUG retry C_EncryptInit\n");
+            rv = (*ckpFunctions->C_EncryptInit)(ckSessionHandle,
+                ckpMechanism, ckKeyHandle);
         }
     }
 
-    TRACE1("DEBUG C_EncryptInit: freed pMech = %p\n", ckpMechanism);
+    TRACE1("DEBUG C_GCMEncryptInitWithRetry: freed pMech = %p\n", ckpMechanism);
     freeCKMechanismPtr(ckpMechanism);
     if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
 
@@ -312,7 +351,6 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptInit
 {
     CK_SESSION_HANDLE ckSessionHandle;
     CK_MECHANISM_PTR ckpMechanism = NULL;
-    CK_MECHANISM_PTR ckpTemp;
     CK_OBJECT_HANDLE ckKeyHandle;
     CK_RV rv;
 
@@ -330,20 +368,61 @@ Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptInit
     rv = (*ckpFunctions->C_DecryptInit)(ckSessionHandle, ckpMechanism,
                                         ckKeyHandle);
 
-    if (ckpMechanism->mechanism == CKM_AES_GCM) {
-        if (rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_PARAM_INVALID) {
-            // retry with CKM_GCM_PARAMS structure in pkcs11t.h
-            TRACE0("DEBUG C_DecryptInit: retry with CK_GCM_PARAMS\n");
-            ckpTemp = updateGCMParams(env, ckpMechanism);
-            if (ckpTemp != NULL) { // only re-call if conversion succeeds
-                ckpMechanism = ckpTemp;
-                rv = (*ckpFunctions->C_DecryptInit)(ckSessionHandle, ckpMechanism,
-                        ckKeyHandle);
-            }
+    TRACE1("DEBUG C_DecryptInit: freed pMech = %p\n", ckpMechanism);
+    freeCKMechanismPtr(ckpMechanism);
+    if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
+
+    TRACE0("FINISHED\n");
+}
+
+/*
+ * Class:     sun_security_pkcs11_wrapper_PKCS11
+ * Method:    C_GCMDecryptInitWithRetry
+ * Signature: (JLsun/security/pkcs11/wrapper/CK_MECHANISM;JZ)V
+ * Parametermapping:                    *PKCS11*
+ * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
+ * @param   jobject jMechanism          CK_MECHANISM_PTR pMechanism
+ * @param   jlong jKeyHandle            CK_OBJECT_HANDLE hKey
+ * @param   jboolean useNormVerFirst    CK_BBOOL retry (only retry if the first
+ *                                      init uses the non-normative version)
+ */
+JNIEXPORT void JNICALL
+Java_sun_security_pkcs11_wrapper_PKCS11_C_1GCMDecryptInitWithRetry
+(JNIEnv *env, jobject obj, jlong jSessionHandle,
+ jobject jMechanism, jlong jKeyHandle, jboolean useNormVerFirst)
+{
+    CK_SESSION_HANDLE ckSessionHandle;
+    CK_MECHANISM_PTR ckpMechanism = NULL;
+    CK_OBJECT_HANDLE ckKeyHandle;
+    CK_BBOOL retry = FALSE;
+    CK_RV rv = 1;
+
+    CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
+    if (ckpFunctions == NULL) { return; }
+
+    ckSessionHandle = jLongToCKULong(jSessionHandle);
+    ckKeyHandle = jLongToCKULong(jKeyHandle);
+    ckpMechanism = jMechanismToCKMechanismPtr(env, jMechanism);
+
+    if ((*env)->ExceptionCheck(env)) { return; }
+
+    // if !useNormVerFirst, then update 'ckpMechanism' in place w/
+    // non-normative GCM params.
+    retry = (!useNormVerFirst && updateGCMParams(env, ckpMechanism) != NULL);
+
+    rv = (*ckpFunctions->C_DecryptInit)(ckSessionHandle, ckpMechanism,
+        ckKeyHandle);
+
+    if (rv == CKR_ARGUMENTS_BAD || rv == CKR_MECHANISM_PARAM_INVALID) {
+        // retry and update 'ckpMechanism' in place w/ normative GCM params.
+        if (retry && updateGCMParams(env, ckpMechanism) != NULL) {
+            TRACE0("DEBUG retry C_DecryptInit with normative CK_GCM_PARAMS\n");
+            rv = (*ckpFunctions->C_DecryptInit)(ckSessionHandle, ckpMechanism,
+                ckKeyHandle);
         }
     }
 
-    TRACE1("DEBUG C_DecryptInit: freed pMech = %p\n", ckpMechanism);
+    TRACE1("DEBUG C_GCMDecryptInitWithRetry: freed pMech = %p\n", ckpMechanism);
     freeCKMechanismPtr(ckpMechanism);
     if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
 
diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c
index abc39a0ce08..4edf9c94ce2 100644
--- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c
+++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
  */
 
 /* Copyright  (c) 2002 Graz University of Technology. All rights reserved.
@@ -327,14 +327,14 @@ void freeCKMechanismPtr(CK_MECHANISM_PTR mechPtr) {
              tmp = mechPtr->pParameter;
              switch (mechPtr->mechanism) {
                  case CKM_AES_GCM:
-                     if (mechPtr->ulParameterLen == sizeof(CK_GCM_PARAMS_NO_IVBITS)) {
-                         TRACE0("[ GCM_PARAMS w/o ulIvBits ]\n");
-                         free(((CK_GCM_PARAMS_NO_IVBITS*)tmp)->pIv);
-                         free(((CK_GCM_PARAMS_NO_IVBITS*)tmp)->pAAD);
-                     } else if (mechPtr->ulParameterLen == sizeof(CK_GCM_PARAMS)) {
+                     if (mechPtr->ulParameterLen == sizeof(CK_GCM_PARAMS)) {
                          TRACE0("[ GCM_PARAMS ]\n");
                          free(((CK_GCM_PARAMS*)tmp)->pIv);
                          free(((CK_GCM_PARAMS*)tmp)->pAAD);
+                     } else if (mechPtr->ulParameterLen == sizeof(CK_GCM_PARAMS_NO_IVBITS)) {
+                         TRACE0("[ GCM_PARAMS w/o ulIvBits ]\n");
+                         free(((CK_GCM_PARAMS_NO_IVBITS*)tmp)->pIv);
+                         free(((CK_GCM_PARAMS_NO_IVBITS*)tmp)->pAAD);
                      }
                      break;
                  case CKM_AES_CCM:
@@ -451,43 +451,54 @@ void freeCKMechanismPtr(CK_MECHANISM_PTR mechPtr) {
      }
 }
 
-/* This function replaces the CK_GCM_PARAMS_NO_IVBITS structure associated
- * with the specified CK_MECHANISM structure with CK_GCM_PARAMS
- * structure.
+/* This function updates the specified CK_MECHANISM structure
+ * and its GCM parameter structure switching between CK_GCM_PARAMS and
+ * CK_GCM_PARAMS_NO_IVBITS.
  *
  * @param mechPtr pointer to the CK_MECHANISM structure containing
- * the to-be-converted CK_GCM_PARAMS_NO_IVBITS structure.
+ * the to-be-converted CK_GCM_PARAMS / CK_GCM_PARAMS_NO_IVBITS structure.
  * @return pointer to the CK_MECHANISM structure containing the
- * converted CK_GCM_PARAMS structure or NULL if no conversion took place.
+ * converted structure or NULL if no conversion is done.
  */
 CK_MECHANISM_PTR updateGCMParams(JNIEnv *env, CK_MECHANISM_PTR mechPtr) {
-    CK_GCM_PARAMS* pGcmParams2 = NULL;
-    CK_GCM_PARAMS_NO_IVBITS* pParams = NULL;
-    if ((mechPtr->mechanism == CKM_AES_GCM) &&
-            (mechPtr->pParameter != NULL_PTR) &&
-            (mechPtr->ulParameterLen == sizeof(CK_GCM_PARAMS_NO_IVBITS))) {
-        pGcmParams2 = calloc(1, sizeof(CK_GCM_PARAMS));
-        if (pGcmParams2 == NULL) {
-            p11ThrowOutOfMemoryError(env, 0);
-            return NULL;
+    CK_GCM_PARAMS_PTR pParams;
+    CK_GCM_PARAMS_NO_IVBITS_PTR pParamsNoIvBits;
+    CK_ULONG paramLen;
+
+    if (mechPtr != NULL) {
+        paramLen = mechPtr->ulParameterLen;
+        if (paramLen == sizeof(CK_GCM_PARAMS)) {
+            // CK_GCM_PARAMS => CK_GCM_PARAMS_NO_IVBITS
+            pParams = (CK_GCM_PARAMS*) mechPtr->pParameter;
+            pParamsNoIvBits = calloc(1, sizeof(CK_GCM_PARAMS_NO_IVBITS));
+            pParamsNoIvBits->pIv = pParams->pIv;
+            pParamsNoIvBits->ulIvLen = pParams->ulIvLen;
+            pParamsNoIvBits->pAAD = pParams->pAAD;
+            pParamsNoIvBits->ulAADLen = pParams->ulAADLen;
+            pParamsNoIvBits->ulTagBits = pParams->ulTagBits;
+            mechPtr->pParameter = pParamsNoIvBits;
+            mechPtr->ulParameterLen = sizeof(CK_GCM_PARAMS_NO_IVBITS);
+            free(pParams);
+            TRACE0("DEBUG update CK_GCM_PARAMS to CK_GCM_PARAMS_NO_IVBITS\n");
+            return mechPtr;
+        } else if (paramLen == sizeof(CK_GCM_PARAMS_NO_IVBITS)) {
+            // CK_GCM_PARAMS_NO_IVBITS => CK_GCM_PARAMS
+            pParamsNoIvBits = (CK_GCM_PARAMS_NO_IVBITS*) mechPtr->pParameter;
+            pParams = calloc(1, sizeof(CK_GCM_PARAMS));
+            pParams->pIv = pParamsNoIvBits->pIv;
+            pParams->ulIvLen = pParamsNoIvBits->ulIvLen;
+            pParams->ulIvBits = pParamsNoIvBits->ulIvLen << 3;
+            pParams->pAAD = pParamsNoIvBits->pAAD;
+            pParams->ulAADLen = pParamsNoIvBits->ulAADLen;
+            pParams->ulTagBits = pParamsNoIvBits->ulTagBits;
+            mechPtr->pParameter = pParams;
+            mechPtr->ulParameterLen = sizeof(CK_GCM_PARAMS);
+            free(pParamsNoIvBits);
+            TRACE0("DEBUG update CK_GCM_PARAMS_NO_IVBITS to CK_GCM_PARAMS\n");
+            return mechPtr;
         }
-        pParams = (CK_GCM_PARAMS_NO_IVBITS*) mechPtr->pParameter;
-        pGcmParams2->pIv = pParams->pIv;
-        pGcmParams2->ulIvLen = pParams->ulIvLen;
-        pGcmParams2->ulIvBits = (pGcmParams2->ulIvLen << 3);
-        pGcmParams2->pAAD = pParams->pAAD;
-        pGcmParams2->ulAADLen = pParams->ulAADLen;
-        pGcmParams2->ulTagBits = pParams->ulTagBits;
-        TRACE1("DEBUG updateGCMParams: pMech %p\n", mechPtr);
-        TRACE2("\t=> GCM param w/o ulIvBits %p => GCM param %p\n", pParams,
-                pGcmParams2);
-        free(pParams);
-        mechPtr->pParameter = pGcmParams2;
-        mechPtr->ulParameterLen = sizeof(CK_GCM_PARAMS);
-        return mechPtr;
-    } else {
-        TRACE0("DEBUG updateGCMParams: no conversion done\n");
     }
+    TRACE0("DEBUG updateGCMParams: no conversion done\n");
     return NULL;
 }
 
diff --git a/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c b/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c
index 85b9cad03a7..62895895123 100644
--- a/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c
+++ b/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
  */
 
 /* Copyright  (c) 2002 Graz University of Technology. All rights reserved.
@@ -103,7 +103,6 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect
     /*
      * Load the PKCS #11 DLL
      */
-    dlerror(); /* clear any old error message not fetched */
 #ifdef DEBUG
     hModule = dlopen(libraryNameStr, RTLD_NOW);
 #else
@@ -124,9 +123,6 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect
         goto cleanup;
     }
 
-    // clear any old error message not fetched
-    dlerror();
-
 #ifdef DEBUG
     C_GetInterfaceList = (CK_C_GetInterfaceList) dlsym(hModule,
             "C_GetInterfaceList");
@@ -158,47 +154,42 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect
     }
 #endif
 
-    if (jGetFunctionList != NULL) {
+    // if none specified, then we try 3.0 API first before trying 2.40
+    if (jGetFunctionList == NULL) {
+        C_GetInterface = (CK_C_GetInterface) dlsym(hModule, "C_GetInterface");
+        if (C_GetInterface != NULL) {
+            TRACE0("Connect: Found C_GetInterface func\n");
+            rv = (C_GetInterface)(NULL, NULL, &interface, 0L);
+            // don't use ckAssertReturnValueOK as we want to continue trying
+            // C_GetFunctionList() or method named by "getFunctionListStr"
+            if (rv == CKR_OK && interface != NULL) {
+                goto setModuleData;
+            }
+        }
+        getFunctionListStr = "C_GetFunctionList";
+    } else {
         getFunctionListStr = (*env)->GetStringUTFChars(env,
             jGetFunctionList, 0);
         if (getFunctionListStr == NULL) {
             goto cleanup;
         }
-        C_GetFunctionList = (CK_C_GetFunctionList) dlsym(hModule,
+    }
+
+    dlerror(); // clear any old error message not fetched
+    C_GetFunctionList = (CK_C_GetFunctionList) dlsym(hModule,
             getFunctionListStr);
+    if (C_GetFunctionList == NULL) {
         if ((systemErrorMessage = dlerror()) != NULL){
+            TRACE2("Connect: error finding %s func: %s\n", getFunctionListStr,
+                systemErrorMessage);
             p11ThrowIOException(env, systemErrorMessage);
-            goto cleanup;
-        }
-        if (C_GetFunctionList == NULL) {
+        } else {
             TRACE1("Connect: No %s func\n", getFunctionListStr);
             p11ThrowIOException(env, "ERROR: C_GetFunctionList == NULL");
-            goto cleanup;
-        }
-        TRACE1("Connect: Found %s func\n", getFunctionListStr);
-    } else {
-        // if none specified, then we try 3.0 API first before trying 2.40
-        C_GetInterface = (CK_C_GetInterface) dlsym(hModule, "C_GetInterface");
-        if ((C_GetInterface != NULL) && (dlerror() == NULL)) {
-            TRACE0("Connect: Found C_GetInterface func\n");
-            rv = (C_GetInterface)(NULL, NULL, &interface, 0L);
-            if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) {
-                goto setModuleData;
-            }
-        }
-        C_GetFunctionList = (CK_C_GetFunctionList) dlsym(hModule,
-                "C_GetFunctionList");
-        if ((systemErrorMessage = dlerror()) != NULL){
-            p11ThrowIOException(env, systemErrorMessage);
-            goto cleanup;
-        }
-        if (C_GetFunctionList == NULL) {
-            TRACE0("Connect: No C_GetFunctionList func\n");
-            p11ThrowIOException(env, "ERROR: C_GetFunctionList == NULL");
-            goto cleanup;
         }
-        TRACE0("Connect: Found C_GetFunctionList func\n");
+        goto cleanup;
     }
+    TRACE1("Connect: Found %s func\n", getFunctionListStr);
 
 setModuleData:
     /*
@@ -219,15 +210,13 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect
         }
     } else if (interface != NULL) {
         moduleData->ckFunctionListPtr = interface->pFunctionList;
-        if (((CK_VERSION *)moduleData->ckFunctionListPtr)->major == 3) {
-            moduleData->ckFunctionList30Ptr = interface->pFunctionList;
-        }
     } else {
         // should never happen
         p11ThrowIOException(env, "ERROR: No function list ptr found");
         goto cleanup;
     }
-    if (((CK_VERSION *)moduleData->ckFunctionListPtr)->major == 3) {
+    if (((CK_VERSION *)moduleData->ckFunctionListPtr)->major == 3 &&
+            interface != NULL) {
         moduleData->ckFunctionList30Ptr = interface->pFunctionList;
     } else {
         moduleData->ckFunctionList30Ptr = NULL;
diff --git a/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c b/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c
index d05a341377f..ca0fd317230 100644
--- a/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c
+++ b/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/p11_md.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
  */
 
 /* Copyright  (c) 2002 Graz University of Technology. All rights reserved.
@@ -186,7 +186,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect
         if (C_GetInterface != NULL) {
             TRACE0("Connect: Found C_GetInterface func\n");
             rv = (C_GetInterface)(NULL, NULL, &interface, 0);
-            if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) {
+            if (rv == CKR_OK && interface != NULL) {
                 goto setModuleData;
             }
         }
@@ -234,7 +234,8 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect
         p11ThrowIOException(env, "ERROR: No function list ptr found");
         goto cleanup;
     }
-    if (((CK_VERSION *)moduleData->ckFunctionListPtr)->major == 3) {
+    if (((CK_VERSION *)moduleData->ckFunctionListPtr)->major == 3 &&
+            interface != NULL) {
         moduleData->ckFunctionList30Ptr = interface->pFunctionList;
     } else {
         moduleData->ckFunctionList30Ptr = NULL;
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java
index 976af5bac20..8add1862542 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java
@@ -120,7 +120,6 @@ public String getName() {
   }
 
   /** OopMap for frame; can return null if none available */
-
   public ImmutableOopMapSet getOopMaps() {
     Address value = oopMapsField.getValue(addr);
     if (value == null) {
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
index 2c3f2d2a698..cec603be2d5 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
@@ -57,7 +57,6 @@ public void update(Observable o, Object data) {
   // ClassState constants
   private static int CLASS_STATE_ALLOCATED;
   private static int CLASS_STATE_LOADED;
-  private static int CLASS_STATE_BEING_LINKED;
   private static int CLASS_STATE_LINKED;
   private static int CLASS_STATE_BEING_INITIALIZED;
   private static int CLASS_STATE_FULLY_INITIALIZED;
@@ -98,7 +97,6 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc
     // read ClassState constants
     CLASS_STATE_ALLOCATED = db.lookupIntConstant("InstanceKlass::allocated").intValue();
     CLASS_STATE_LOADED = db.lookupIntConstant("InstanceKlass::loaded").intValue();
-    CLASS_STATE_BEING_LINKED = db.lookupIntConstant("InstanceKlass::being_linked").intValue();
     CLASS_STATE_LINKED = db.lookupIntConstant("InstanceKlass::linked").intValue();
     CLASS_STATE_BEING_INITIALIZED = db.lookupIntConstant("InstanceKlass::being_initialized").intValue();
     CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("InstanceKlass::fully_initialized").intValue();
@@ -152,7 +150,6 @@ public InstanceKlass(Address addr) {
   public static class ClassState {
      public static final ClassState ALLOCATED    = new ClassState("allocated");
      public static final ClassState LOADED       = new ClassState("loaded");
-     public static final ClassState BEING_LINKED = new ClassState("beingLinked");
      public static final ClassState LINKED       = new ClassState("linked");
      public static final ClassState BEING_INITIALIZED      = new ClassState("beingInitialized");
      public static final ClassState FULLY_INITIALIZED    = new ClassState("fullyInitialized");
@@ -176,8 +173,6 @@ public ClassState getInitState() {
         return ClassState.ALLOCATED;
      } else if (state == CLASS_STATE_LOADED) {
         return ClassState.LOADED;
-     } else if (state == CLASS_STATE_BEING_LINKED) {
-        return ClassState.BEING_LINKED;
      } else if (state == CLASS_STATE_LINKED) {
         return ClassState.LINKED;
      } else if (state == CLASS_STATE_BEING_INITIALIZED) {
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java
index 7a360942572..60bcb7bb86d 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -100,7 +100,7 @@ public void printLockInfo(PrintStream tty, int frameCount) {
     // then print out the receiver. Locals are not always available,
     // e.g., compiled native frames have no scope so there are no locals.
     if (frameCount == 0) {
-      if (getMethod().getName().asString().equals("wait") &&
+      if (getMethod().getName().asString().equals("wait0") &&
           getMethod().getMethodHolder().getName().asString().equals("java/lang/Object")) {
         String waitState = "waiting on"; // assume we are waiting
         // If earlier in the output we reported java.lang.Thread.State ==
diff --git a/src/jdk.hotspot.agent/test/libproc/Makefile b/src/jdk.hotspot.agent/test/libproc/Makefile
index 81fadaeb552..c7b171bc633 100644
--- a/src/jdk.hotspot.agent/test/libproc/Makefile
+++ b/src/jdk.hotspot.agent/test/libproc/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -19,7 +19,7 @@
 # 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:
diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java
index ee0439f7542..add50920336 100644
--- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java
+++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java
@@ -57,7 +57,6 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import java.util.Timer;
@@ -522,14 +521,15 @@ public void run() {
 
                                     key.cancel();
                                     chan.configureBlocking (true);
+                                    // check if connection is being closed
                                     if (newlyAcceptedConnections.remove(conn)
                                             || idleConnections.remove(conn)) {
                                         // was either a newly accepted connection or an idle
                                         // connection. In either case, we mark that the request
                                         // has now started on this connection.
                                         requestStarted(conn);
+                                        handle (chan, conn);
                                     }
-                                    handle (chan, conn);
                                 } else {
                                     assert false : "Unexpected non-readable key:" + key;
                                 }
@@ -1019,35 +1019,30 @@ void responseCompleted (HttpConnection c) {
      */
     class IdleTimeoutTask extends TimerTask {
         public void run () {
-            ArrayList toClose = new ArrayList<>();
-            final long currentTime = System.currentTimeMillis();
-            synchronized (idleConnections) {
-                final Iterator it = idleConnections.iterator();
-                while (it.hasNext()) {
-                    final HttpConnection c = it.next();
-                    if (currentTime - c.idleStartTime >= IDLE_INTERVAL) {
-                        toClose.add(c);
-                        it.remove();
-                    }
-                }
-            }
+            closeConnections(idleConnections, IDLE_INTERVAL);
             // if any newly accepted connection has been idle (i.e. no byte has been sent on that
             // connection during the configured idle timeout period) then close it as well
-            synchronized (newlyAcceptedConnections) {
-                final Iterator it = newlyAcceptedConnections.iterator();
-                while (it.hasNext()) {
-                    final HttpConnection c = it.next();
-                    if (currentTime - c.idleStartTime >= NEWLY_ACCEPTED_CONN_IDLE_INTERVAL) {
-                        toClose.add(c);
-                        it.remove();
-                    }
+            closeConnections(newlyAcceptedConnections, NEWLY_ACCEPTED_CONN_IDLE_INTERVAL);
+        }
+
+        private void closeConnections(Set connections, long idleInterval) {
+            long currentTime = System.currentTimeMillis();
+            ArrayList toClose = new ArrayList<>();
+
+            connections.forEach(c -> {
+                if (currentTime - c.idleStartTime >= idleInterval) {
+                    toClose.add(c);
                 }
-            }
+            });
             for (HttpConnection c : toClose) {
-                allConnections.remove(c);
-                c.close();
-                if (logger.isLoggable(Level.TRACE)) {
-                    logger.log(Level.TRACE, "Closed idle connection " + c);
+                // check if connection still idle
+                if (currentTime - c.idleStartTime >= idleInterval &&
+                        connections.remove(c)) {
+                    allConnections.remove(c);
+                    c.close();
+                    if (logger.isLoggable(Level.TRACE)) {
+                        logger.log(Level.TRACE, "Closed idle connection " + c);
+                    }
                 }
             }
         }
diff --git a/src/jdk.jartool/share/man/jar.1 b/src/jdk.jartool/share/man/jar.1
index 934b14984f4..e9e30388175 100644
--- a/src/jdk.jartool/share/man/jar.1
+++ b/src/jdk.jartool/share/man/jar.1
@@ -186,7 +186,8 @@ created or a non-modular JAR file being updated.
 Specifies the location of module dependence for generating the hash.
 .TP
 \f[V]\[at]\f[R]\f[I]file\f[R]
-Reads \f[V]jar\f[R] options and file names from a text file.
+Reads \f[V]jar\f[R] options and file names from a text file as if they
+were supplied on the command line
 .SH OPERATION MODIFIERS VALID ONLY IN CREATE, UPDATE, AND GENERATE-INDEX MODES
 .PP
 You can use the following options to customize the actions of the create
@@ -330,11 +331,14 @@ class files from the file \f[V]classes.list\f[R].
 .PP
 \f[B]Note:\f[R]
 .PP
-To shorten or simplify the \f[V]jar\f[R] command, you can specify
-arguments in a separate text file and pass it to the \f[V]jar\f[R]
-command with the at sign (\f[V]\[at]\f[R]) as a prefix.
+To shorten or simplify the \f[V]jar\f[R] command, you can provide an arg
+file that lists the files to include in the JAR file and pass it to the
+\f[V]jar\f[R] command with the at sign (\f[V]\[at]\f[R]) as a prefix.
 .RS
 .PP
 \f[V]jar --create --file my.jar \[at]classes.list\f[R]
 .RE
+.PP
+If one or more entries in the arg file cannot be found then the jar
+command fails without creating the JAR file.
 .RE
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
index cf382def3f5..0c595d780b0 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
@@ -117,6 +117,7 @@
 import static com.sun.source.doctree.DocTree.Kind.LINK;
 import static com.sun.source.doctree.DocTree.Kind.LINK_PLAIN;
 import static com.sun.source.doctree.DocTree.Kind.SEE;
+import static com.sun.source.doctree.DocTree.Kind.START_ELEMENT;
 import static com.sun.source.doctree.DocTree.Kind.TEXT;
 
 
@@ -1133,21 +1134,37 @@ private void addCommentTags(Element element, List tags, boole
         }
     }
 
-    boolean ignoreNonInlineTag(DocTree dtree) {
+    // helper methods because jdk21 functionality is not allowed
+    private static Name getLastHelper(List l) {
+        return l.get(l.size() - 1);
+    }
+
+    private static Name removeLastHelper(List l) {
+        return l.remove(l.size() - 1);
+    }
+
+    boolean ignoreNonInlineTag(DocTree dtree, List openTags) {
         Name name = null;
-        if (dtree.getKind() == Kind.START_ELEMENT) {
-            StartElementTree setree = (StartElementTree)dtree;
-            name = setree.getName();
-        } else if (dtree.getKind() == Kind.END_ELEMENT) {
-            EndElementTree eetree = (EndElementTree)dtree;
-            name = eetree.getName();
+        Kind kind = dtree.getKind();
+        if (kind == Kind.START_ELEMENT) {
+            name = ((StartElementTree)dtree).getName();
+        } else if (kind == Kind.END_ELEMENT) {
+            name = ((EndElementTree)dtree).getName();
         }
 
         if (name != null) {
             HtmlTag htmlTag = HtmlTag.get(name);
-            if (htmlTag != null &&
-                    htmlTag.blockType != jdk.javadoc.internal.doclint.HtmlTag.BlockType.INLINE) {
-                return true;
+            if (htmlTag != null) {
+                if (htmlTag.blockType != HtmlTag.BlockType.INLINE) {
+                    return true;
+                }
+                // Keep track of open inline tags that need to be closed, see 8326332
+                if (kind == START_ELEMENT && htmlTag.endKind == HtmlTag.EndKind.REQUIRED) {
+                    openTags.add(name);
+                } else if (kind == Kind.END_ELEMENT && !openTags.isEmpty()
+                        && getLastHelper(openTags).equals(name)) {
+                    removeLastHelper(openTags);
+                }
             }
         }
         return false;
@@ -1219,6 +1236,7 @@ public ContentBuilder add(CharSequence text) {
         CommentHelper ch = utils.getCommentHelper(element);
         configuration.tagletManager.checkTags(element, trees);
         commentRemoved = false;
+        List openTags = new ArrayList<>();
 
         for (ListIterator iterator = trees.listIterator(); iterator.hasNext();) {
             boolean isFirstNode = !iterator.hasPrevious();
@@ -1227,14 +1245,16 @@ public ContentBuilder add(CharSequence text) {
 
             if (context.isFirstSentence) {
                 // Ignore block tags
-                if (ignoreNonInlineTag(tag))
+                if (ignoreNonInlineTag(tag, openTags)) {
                     continue;
+                }
 
                 // Ignore any trailing whitespace OR whitespace after removed html comment
                 if ((isLastNode || commentRemoved)
                         && tag.getKind() == TEXT
-                        && ((tag instanceof TextTree tt) && tt.getBody().isBlank()))
+                        && ((tag instanceof TextTree tt) && tt.getBody().isBlank())) {
                     continue;
+                }
 
                 // Ignore any leading html comments
                 if ((isFirstNode || commentRemoved) && tag.getKind() == COMMENT) {
@@ -1485,6 +1505,10 @@ protected Boolean defaultAction(DocTree node, Content content) {
             if (allDone)
                 break;
         }
+        // Close any open inline tags
+        while (!openTags.isEmpty()) {
+            result.add(RawHtml.endElement(removeLastHelper(openTags)));
+        }
         return result;
     }
 
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.6.1.min.js b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.6.1.min.js
deleted file mode 100644
index 2c69bc908b1..00000000000
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.6.1.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! jQuery v3.6.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */
-!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),v={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&v(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!y||!y.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ve(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ye(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ve(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],y=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||y.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||y.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||y.push(".#.+[+~]"),e.querySelectorAll("\\\f"),y.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),y=y.length&&new RegExp(y.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),v=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&v(p,e)?-1:t==C||t.ownerDocument==p&&v(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!y||!y.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),v.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",v.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",v.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),v.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(v.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return B(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=_e(v.pixelPosition,function(e,t){if(t)return t=Be(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return B(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 0 && ( length - 1 ) in obj; } -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.3.6 - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://js.foundation/ - * - * Date: 2021-02-16 - */ -( function( window ) { + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var pop = arr.pop; + + +var sort = arr.sort; + + +var splice = arr.splice; + + +var whitespace = "[\\x20\\t\\r\\n\\f]"; + + +var rtrimCSS = new RegExp( + "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", + "g" +); + + + + +// Note: an element does not contain itself +jQuery.contains = function( a, b ) { + var bup = b && b.parentNode; + + return a === bup || !!( bup && bup.nodeType === 1 && ( + + // Support: IE 9 - 11+ + // IE doesn't have `contains` on SVG. + a.contains ? + a.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); +}; + + + + +// CSS string/identifier serialization +// https://drafts.csswg.org/cssom/#common-serializing-idioms +var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g; + +function fcssescape( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; +} + +jQuery.escapeSelector = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + + + + +var preferredDoc = document, + pushNative = push; + +( function() { + var i, - support, Expr, - getText, - isXML, - tokenize, - compile, - select, outermostContext, sortInput, hasDuplicate, + push = pushNative, // Local document vars - setDocument, document, - docElem, + documentElement, documentIsHTML, rbuggyQSA, - rbuggyMatches, matches, - contains, // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, + expando = jQuery.expando, dirruns = 0, done = 0, classCache = createCache(), @@ -570,47 +664,22 @@ var i, return 0; }, - // Instance methods - hasOwn = ( {} ).hasOwnProperty, - arr = [], - pop = arr.pop, - pushNative = arr.push, - push = arr.push, - slice = arr.slice, - - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[ i ] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + - "ismap|loop|multiple|open|readonly|required|scoped", + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|" + + "loop|multiple|open|readonly|required|scoped", // Regular expressions - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + // Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + // Operator (capture 2) "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] - // or strings [capture 3 or capture 4]" + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]", @@ -629,101 +698,88 @@ var i, // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + - whitespace + "+$", "g" ), rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + - "*" ), + rleadingCombinator = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + + whitespace + "*" ), rdescend = new RegExp( whitespace + "|>" ), rpseudo = new RegExp( pseudos ), ridentifier = new RegExp( "^" + identifier + "$" ), matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + - whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + - whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + ID: new RegExp( "^#(" + identifier + ")" ), + CLASS: new RegExp( "^\\.(" + identifier + ")" ), + TAG: new RegExp( "^(" + identifier + "|[*])" ), + ATTR: new RegExp( "^" + attributes ), + PSEUDO: new RegExp( "^" + pseudos ), + CHILD: new RegExp( + "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + bool: new RegExp( "^(?:" + booleans + ")$", "i" ), // For use in libraries implementing .is() // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + + needsContext: new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) }, - rhtml = /HTML$/i, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, - rnative = /^[^{]+\{\s*\[native \w/, - // Easily-parseable/retrievable ID or TAG or CLASS selectors rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, rsibling = /[+~]/, // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + // https://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\([^\\r\\n\\f])", "g" ), funescape = function( escape, nonHex ) { var high = "0x" + escape.slice( 1 ) - 0x10000; - return nonHex ? + if ( nonHex ) { // Strip the backslash prefix from a non-hex escape sequence - nonHex : - - // Replace a hexadecimal escape sequence with the encoded Unicode code point - // Support: IE <=11+ - // For values outside the Basic Multilingual Plane (BMP), manually construct a - // surrogate pair - high < 0 ? - String.fromCharCode( high + 0x10000 ) : - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + - ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + return nonHex; } - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + return high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); }, - // Used for iframes - // See setDocument() + // Used for iframes; see `setDocument`. + // Support: IE 9 - 11+, Edge 12 - 18+ // Removing the function wrapper causes a "Permission Denied" - // error in IE + // error in IE/Edge. unloadHandler = function() { setDocument(); }, inDisabledFieldset = addCombinator( function( elem ) { - return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + return elem.disabled === true && nodeName( elem, "fieldset" ); }, { dir: "parentNode", next: "legend" } ); +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + // Optimize for push.apply( _, NodeList ) try { push.apply( @@ -731,32 +787,22 @@ try { preferredDoc.childNodes ); - // Support: Android<4.0 + // Support: Android <=4.0 // Detect silently failing push.apply // eslint-disable-next-line no-unused-expressions arr[ preferredDoc.childNodes.length ].nodeType; } catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { + push = { + apply: function( target, els ) { pushNative.apply( target, slice.call( els ) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - - // Can't trust NodeList.length - while ( ( target[ j++ ] = els[ i++ ] ) ) {} - target.length = j - 1; + }, + call: function( target ) { + pushNative.apply( target, slice.call( arguments, 1 ) ); } }; } -function Sizzle( selector, context, results, seed ) { +function find( selector, context, results, seed ) { var m, i, elem, nid, match, groups, newSelector, newContext = context && context.ownerDocument, @@ -790,11 +836,10 @@ function Sizzle( selector, context, results, seed ) { if ( nodeType === 9 ) { if ( ( elem = context.getElementById( m ) ) ) { - // Support: IE, Opera, Webkit - // TODO: identify versions + // Support: IE 9 only // getElementById can match elements by name instead of ID if ( elem.id === m ) { - results.push( elem ); + push.call( results, elem ); return results; } } else { @@ -804,14 +849,13 @@ function Sizzle( selector, context, results, seed ) { // Element context } else { - // Support: IE, Opera, Webkit - // TODO: identify versions + // Support: IE 9 only // getElementById can match elements by name instead of ID if ( newContext && ( elem = newContext.getElementById( m ) ) && - contains( context, elem ) && + find.contains( context, elem ) && elem.id === m ) { - results.push( elem ); + push.call( results, elem ); return results; } } @@ -822,22 +866,15 @@ function Sizzle( selector, context, results, seed ) { return results; // Class selector - } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && - context.getElementsByClassName ) { - + } else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) { push.apply( results, context.getElementsByClassName( m ) ); return results; } } // Take advantage of querySelectorAll - if ( support.qsa && - !nonnativeSelectorCache[ selector + " " ] && - ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && - - // Support: IE 8 only - // Exclude object elements - ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + if ( !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) { newSelector = selector; newContext = context; @@ -850,7 +887,7 @@ function Sizzle( selector, context, results, seed ) { // as such selectors are not recognized by querySelectorAll. // Thanks to Andrew Dupont for this technique. if ( nodeType === 1 && - ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + ( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) { // Expand context for sibling selectors newContext = rsibling.test( selector ) && testContext( context.parentNode ) || @@ -858,11 +895,15 @@ function Sizzle( selector, context, results, seed ) { // We can use :scope instead of the ID hack if the browser // supports it & if we're not changing the context. - if ( newContext !== context || !support.scope ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when + // strict-comparing two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( newContext != context || !support.scope ) { // Capture the context ID, setting it first if necessary if ( ( nid = context.getAttribute( "id" ) ) ) { - nid = nid.replace( rcssescape, fcssescape ); + nid = jQuery.escapeSelector( nid ); } else { context.setAttribute( "id", ( nid = expando ) ); } @@ -895,7 +936,7 @@ function Sizzle( selector, context, results, seed ) { } // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); + return select( selector.replace( rtrimCSS, "$1" ), context, results, seed ); } /** @@ -909,7 +950,8 @@ function createCache() { function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + // Use (key + " ") to avoid collision with native prototype properties + // (see https://github.com/jquery/sizzle/issues/157) if ( keys.push( key + " " ) > Expr.cacheLength ) { // Only keep the most recent entries @@ -921,7 +963,7 @@ function createCache() { } /** - * Mark a function for special use by Sizzle + * Mark a function for special use by jQuery selector module * @param {Function} fn The function to mark */ function markFunction( fn ) { @@ -952,56 +994,13 @@ function assert( fn ) { } } -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split( "|" ), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[ i ] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( ( cur = cur.nextSibling ) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - /** * Returns a function to use in pseudos for input types * @param {String} type */ function createInputPseudo( type ) { return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; + return nodeName( elem, "input" ) && elem.type === type; }; } @@ -1011,8 +1010,8 @@ function createInputPseudo( type ) { */ function createButtonPseudo( type ) { return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return ( name === "input" || name === "button" ) && elem.type === type; + return ( nodeName( elem, "input" ) || nodeName( elem, "button" ) ) && + elem.type === type; }; } @@ -1048,14 +1047,13 @@ function createDisabledPseudo( disabled ) { } } - // Support: IE 6 - 11 + // Support: IE 6 - 11+ // Use the isDisabled shortcut property to check for disabled fieldset ancestors return elem.isDisabled === disabled || // Where there is no isDisabled, check manually - /* jshint -W018 */ elem.isDisabled !== !disabled && - inDisabledFieldset( elem ) === disabled; + inDisabledFieldset( elem ) === disabled; } return elem.disabled === disabled; @@ -1095,7 +1093,7 @@ function createPositionalPseudo( fn ) { } /** - * Checks a node for validity as a Sizzle context + * Checks a node for validity as a jQuery selector context * @param {Element|Object=} context * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value */ @@ -1103,31 +1101,13 @@ function testContext( context ) { return context && typeof context.getElementsByTagName !== "undefined" && context; } -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - var namespace = elem && elem.namespaceURI, - docElem = elem && ( elem.ownerDocument || elem ).documentElement; - - // Support: IE <=8 - // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes - // https://bugs.jquery.com/ticket/4833 - return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); -}; - /** * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document + * @param {Element|Object} [node] An element or document object to use to set the document * @returns {Object} Returns the current document */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, subWindow, +function setDocument( node ) { + var subWindow, doc = node ? node.ownerDocument || node : preferredDoc; // Return early if doc is invalid or already selected @@ -1141,87 +1121,90 @@ setDocument = Sizzle.setDocument = function( node ) { // Update global variables document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); + documentElement = document.documentElement; + documentIsHTML = !jQuery.isXMLDoc( document ); + + // Support: iOS 7 only, IE 9 - 11+ + // Older browsers didn't support unprefixed `matches`. + matches = documentElement.matches || + documentElement.webkitMatchesSelector || + documentElement.msMatchesSelector; // Support: IE 9 - 11+, Edge 12 - 18+ - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( preferredDoc != document && - ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + // Accessing iframe documents after unload throws "permission denied" errors + // (see trac-13936). + // Limit the fix to IE & Edge Legacy; despite Edge 15+ implementing `matches`, + // all IE 9+ and Edge Legacy versions implement `msMatchesSelector` as well. + if ( documentElement.msMatchesSelector && - // Support: IE 11, Edge - if ( subWindow.addEventListener ) { - subWindow.addEventListener( "unload", unloadHandler, false ); + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { - // Support: IE 9 - 10 only - } else if ( subWindow.attachEvent ) { - subWindow.attachEvent( "onunload", unloadHandler ); - } + // Support: IE 9 - 11+, Edge 12 - 18+ + subWindow.addEventListener( "unload", unloadHandler ); } - // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, - // Safari 4 - 5 only, Opera <=11.6 - 12.x only - // IE/Edge & older browsers don't support the :scope pseudo-class. - // Support: Safari 6.0 only - // Safari 6.0 supports :scope but it's an alias of :root there. - support.scope = assert( function( el ) { - docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); - return typeof el.querySelectorAll !== "undefined" && - !el.querySelectorAll( ":scope fieldset div" ).length; + // Support: IE <10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + documentElement.appendChild( el ).id = jQuery.expando; + return !document.getElementsByName || + !document.getElementsByName( jQuery.expando ).length; } ); - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert( function( el ) { - el.className = "i"; - return !el.getAttribute( "className" ); + // Support: IE 9 only + // Check to see if it's possible to do matchesSelector + // on a disconnected node. + support.disconnectedMatch = assert( function( el ) { + return matches.call( el, "*" ); } ); - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert( function( el ) { - el.appendChild( document.createComment( "" ) ); - return !el.getElementsByTagName( "*" ).length; + // Support: IE 9 - 11+, Edge 12 - 18+ + // IE/Edge don't support the :scope pseudo-class. + support.scope = assert( function() { + return document.querySelectorAll( ":scope" ); } ); - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert( function( el ) { - docElem.appendChild( el ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; + // Support: Chrome 105 - 111 only, Safari 15.4 - 16.3 only + // Make sure the `:has()` argument is parsed unforgivingly. + // We include `*` in the test to detect buggy implementations that are + // _selectively_ forgiving (specifically when the list includes at least + // one valid selector). + // Note that we treat complete lack of support for `:has()` as if it were + // spec-compliant support, which is fine because use of `:has()` in such + // environments will fail in the qSA path and fall back to jQuery traversal + // anyway. + support.cssHas = assert( function() { + try { + document.querySelector( ":has(*,:jqfake)" ); + return false; + } catch ( e ) { + return true; + } } ); // ID filter and find if ( support.getById ) { - Expr.filter[ "ID" ] = function( id ) { + Expr.filter.ID = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { return elem.getAttribute( "id" ) === attrId; }; }; - Expr.find[ "ID" ] = function( id, context ) { + Expr.find.ID = function( id, context ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { var elem = context.getElementById( id ); return elem ? [ elem ] : []; } }; } else { - Expr.filter[ "ID" ] = function( id ) { + Expr.filter.ID = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { var node = typeof elem.getAttributeNode !== "undefined" && @@ -1232,7 +1215,7 @@ setDocument = Sizzle.setDocument = function( node ) { // Support: IE 6 - 7 only // getElementById is not reliable as a find shortcut - Expr.find[ "ID" ] = function( id, context ) { + Expr.find.ID = function( id, context ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { var node, i, elems, elem = context.getElementById( id ); @@ -1262,40 +1245,18 @@ setDocument = Sizzle.setDocument = function( node ) { } // Tag - Expr.find[ "TAG" ] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); + Expr.find.TAG = function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); - // Filter out possible comments - if ( tag === "*" ) { - while ( ( elem = results[ i++ ] ) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; + // DocumentFragment nodes don't have gEBTN + } else { + return context.querySelectorAll( tag ); + } + }; // Class - Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + Expr.find.CLASS = function( className, context ) { if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { return context.getElementsByClassName( className ); } @@ -1306,177 +1267,94 @@ setDocument = Sizzle.setDocument = function( node ) { // QSA and matchesSelector support - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See https://bugs.jquery.com/ticket/13378 rbuggyQSA = []; - if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert( function( el ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { - var input; + var input; - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // https://bugs.jquery.com/ticket/12359 - docElem.appendChild( el ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } + documentElement.appendChild( el ).innerHTML = + "" + + ""; - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll( "[selected]" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push( "~=" ); - } - - // Support: IE 11+, Edge 15 - 18+ - // IE 11/Edge don't find elements on a `[name='']` query in some cases. - // Adding a temporary attribute to the document before the selection works - // around the issue. - // Interestingly, IE 10 & older don't seem to have the issue. - input = document.createElement( "input" ); - input.setAttribute( "name", "" ); - el.appendChild( input ); - if ( !el.querySelectorAll( "[name='']" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + - whitespace + "*(?:''|\"\")" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll( ":checked" ).length ) { - rbuggyQSA.push( ":checked" ); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push( ".#.+[+~]" ); - } - - // Support: Firefox <=3.6 - 5 only - // Old Firefox doesn't throw on a badly-escaped identifier. - el.querySelectorAll( "\\\f" ); - rbuggyQSA.push( "[\\r\\n\\f]" ); - } ); - - assert( function( el ) { - el.innerHTML = "" + - ""; - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement( "input" ); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll( "[name=d]" ).length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } + // Support: iOS <=7 - 8 only + // Boolean attributes and "value" are not treated correctly in some XML documents + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } - // Support: IE9-11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } + // Support: iOS <=7 - 8 only + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } - // Support: Opera 10 - 11 only - // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll( "*,:x" ); - rbuggyQSA.push( ",.*:" ); - } ); - } + // Support: iOS 8 only + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } - if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector ) ) ) ) { + // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ + // In some of the document kinds, these selectors wouldn't work natively. + // This is probably OK but for backwards compatibility we want to maintain + // handling them through jQuery traversal in jQuery 3.x. + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } - assert( function( el ) { + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE 9 - 11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ + // In some of the document kinds, these selectors wouldn't work natively. + // This is probably OK but for backwards compatibility we want to maintain + // handling them through jQuery traversal in jQuery 3.x. + documentElement.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + } ); - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( el, "*" ); + if ( !support.cssHas ) { - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( el, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - } ); + // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ + // Our regular `try-catch` mechanism fails to detect natively-unsupported + // pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`) + // in browsers that parse the `:has()` argument as a forgiving selector list. + // https://drafts.csswg.org/selectors/#relational now requires the argument + // to be parsed unforgivingly, but browsers have not yet fully adjusted. + rbuggyQSA.push( ":has" ); } rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - ) ); - } : - function( a, b ) { - if ( b ) { - while ( ( b = b.parentNode ) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; /* Sorting ---------------------------------------------------------------------- */ // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { + sortOrder = function( a, b ) { // Flag for duplicate removal if ( a === b ) { @@ -1510,8 +1388,8 @@ setDocument = Sizzle.setDocument = function( node ) { // IE/Edge sometimes throw a "Permission denied" error when strict-comparing // two documents; shallow comparisons work. // eslint-disable-next-line eqeqeq - if ( a == document || a.ownerDocument == preferredDoc && - contains( preferredDoc, a ) ) { + if ( a === document || a.ownerDocument == preferredDoc && + find.contains( preferredDoc, a ) ) { return -1; } @@ -1519,100 +1397,33 @@ setDocument = Sizzle.setDocument = function( node ) { // IE/Edge sometimes throw a "Permission denied" error when strict-comparing // two documents; shallow comparisons work. // eslint-disable-next-line eqeqeq - if ( b == document || b.ownerDocument == preferredDoc && - contains( preferredDoc, b ) ) { + if ( b === document || b.ownerDocument == preferredDoc && + find.contains( preferredDoc, b ) ) { return 1; } // Maintain original order return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : 0; } return compare & 4 ? -1 : 1; - } : - function( a, b ) { - - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - /* eslint-disable eqeqeq */ - return a == document ? -1 : - b == document ? 1 : - /* eslint-enable eqeqeq */ - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( ( cur = cur.parentNode ) ) { - ap.unshift( cur ); - } - cur = b; - while ( ( cur = cur.parentNode ) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[ i ] === bp[ i ] ) { - i++; - } - - return i ? - - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[ i ], bp[ i ] ) : - - // Otherwise nodes in our document sort first - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - /* eslint-disable eqeqeq */ - ap[ i ] == preferredDoc ? -1 : - bp[ i ] == preferredDoc ? 1 : - /* eslint-enable eqeqeq */ - 0; }; return document; -}; +} -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); +find.matches = function( expr, elements ) { + return find( expr, null, null, elements ); }; -Sizzle.matchesSelector = function( elem, expr ) { +find.matchesSelector = function( elem, expr ) { setDocument( elem ); - if ( support.matchesSelector && documentIsHTML && + if ( documentIsHTML && !nonnativeSelectorCache[ expr + " " ] && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { try { var ret = matches.call( elem, expr ); @@ -1620,9 +1431,9 @@ Sizzle.matchesSelector = function( elem, expr ) { // IE 9's matchesSelector returns false on disconnected nodes if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { return ret; } } catch ( e ) { @@ -1630,10 +1441,10 @@ Sizzle.matchesSelector = function( elem, expr ) { } } - return Sizzle( expr, document, null, [ elem ] ).length > 0; + return find( expr, document, null, [ elem ] ).length > 0; }; -Sizzle.contains = function( context, elem ) { +find.contains = function( context, elem ) { // Set document vars if needed // Support: IE 11+, Edge 17 - 18+ @@ -1643,10 +1454,11 @@ Sizzle.contains = function( context, elem ) { if ( ( context.ownerDocument || context ) != document ) { setDocument( context ); } - return contains( context, elem ); + return jQuery.contains( context, elem ); }; -Sizzle.attr = function( elem, name ) { + +find.attr = function( elem, name ) { // Set document vars if needed // Support: IE 11+, Edge 17 - 18+ @@ -1659,25 +1471,19 @@ Sizzle.attr = function( elem, name ) { var fn = Expr.attrHandle[ name.toLowerCase() ], - // Don't get fooled by Object.prototype properties (jQuery #13807) + // Don't get fooled by Object.prototype properties (see trac-13807) val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? fn( elem, name, !documentIsHTML ) : undefined; - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - ( val = elem.getAttributeNode( name ) ) && val.specified ? - val.value : - null; -}; + if ( val !== undefined ) { + return val; + } -Sizzle.escape = function( sel ) { - return ( sel + "" ).replace( rcssescape, fcssescape ); + return elem.getAttribute( name ); }; -Sizzle.error = function( msg ) { +find.error = function( msg ) { throw new Error( "Syntax error, unrecognized expression: " + msg ); }; @@ -1685,16 +1491,20 @@ Sizzle.error = function( msg ) { * Document sorting and removing duplicates * @param {ArrayLike} results */ -Sizzle.uniqueSort = function( results ) { +jQuery.uniqueSort = function( results ) { var elem, duplicates = [], j = 0, i = 0; // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); + // + // Support: Android <=4.0+ + // Testing for detecting duplicates is unpredictable so instead assume we can't + // depend on duplicate detection in all browsers without a stable sort. + hasDuplicate = !support.sortStable; + sortInput = !support.sortStable && slice.call( results, 0 ); + sort.call( results, sortOrder ); if ( hasDuplicate ) { while ( ( elem = results[ i++ ] ) ) { @@ -1703,7 +1513,7 @@ Sizzle.uniqueSort = function( results ) { } } while ( j-- ) { - results.splice( duplicates[ j ], 1 ); + splice.call( results, duplicates[ j ], 1 ); } } @@ -1714,47 +1524,11 @@ Sizzle.uniqueSort = function( results ) { return results; }; -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - - // If no nodeType, this is expected to be an array - while ( ( node = elem[ i++ ] ) ) { - - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - - // Do not include comment or processing instruction nodes - - return ret; +jQuery.fn.uniqueSort = function() { + return this.pushStack( jQuery.uniqueSort( slice.apply( this ) ) ); }; -Expr = Sizzle.selectors = { +Expr = jQuery.expr = { // Can be adjusted by the user cacheLength: 50, @@ -1775,12 +1549,12 @@ Expr = Sizzle.selectors = { }, preFilter: { - "ATTR": function( match ) { + ATTR: function( match ) { match[ 1 ] = match[ 1 ].replace( runescape, funescape ); // Move the given value to match[3] whether quoted or unquoted - match[ 3 ] = ( match[ 3 ] || match[ 4 ] || - match[ 5 ] || "" ).replace( runescape, funescape ); + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || match[ 5 ] || "" ) + .replace( runescape, funescape ); if ( match[ 2 ] === "~=" ) { match[ 3 ] = " " + match[ 3 ] + " "; @@ -1789,7 +1563,7 @@ Expr = Sizzle.selectors = { return match.slice( 0, 4 ); }, - "CHILD": function( match ) { + CHILD: function( match ) { /* matches from matchExpr["CHILD"] 1 type (only|nth|...) @@ -1807,29 +1581,30 @@ Expr = Sizzle.selectors = { // nth-* requires argument if ( !match[ 3 ] ) { - Sizzle.error( match[ 0 ] ); + find.error( match[ 0 ] ); } // numeric x and y parameters for Expr.filter.CHILD // remember that false/true cast respectively to 0/1 match[ 4 ] = +( match[ 4 ] ? match[ 5 ] + ( match[ 6 ] || 1 ) : - 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) + ); match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); - // other types prohibit arguments + // other types prohibit arguments } else if ( match[ 3 ] ) { - Sizzle.error( match[ 0 ] ); + find.error( match[ 0 ] ); } return match; }, - "PSEUDO": function( match ) { + PSEUDO: function( match ) { var excess, unquoted = !match[ 6 ] && match[ 2 ]; - if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + if ( matchExpr.CHILD.test( match[ 0 ] ) ) { return null; } @@ -1858,36 +1633,36 @@ Expr = Sizzle.selectors = { filter: { - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + TAG: function( nodeNameSelector ) { + var expectedNodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); return nodeNameSelector === "*" ? function() { return true; } : function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + return nodeName( elem, expectedNodeName ); }; }, - "CLASS": function( className ) { + CLASS: function( className ) { var pattern = classCache[ className + " " ]; return pattern || - ( pattern = new RegExp( "(^|" + whitespace + - ")" + className + "(" + whitespace + "|$)" ) ) && classCache( - className, function( elem ) { - return pattern.test( - typeof elem.className === "string" && elem.className || - typeof elem.getAttribute !== "undefined" && - elem.getAttribute( "class" ) || - "" - ); + ( pattern = new RegExp( "(^|" + whitespace + ")" + className + + "(" + whitespace + "|$)" ) ) && + classCache( className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); } ); }, - "ATTR": function( name, operator, check ) { + ATTR: function( name, operator, check ) { return function( elem ) { - var result = Sizzle.attr( elem, name ); + var result = find.attr( elem, name ); if ( result == null ) { return operator === "!="; @@ -1898,22 +1673,34 @@ Expr = Sizzle.selectors = { result += ""; - /* eslint-disable max-len */ - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - /* eslint-enable max-len */ + if ( operator === "=" ) { + return result === check; + } + if ( operator === "!=" ) { + return result !== check; + } + if ( operator === "^=" ) { + return check && result.indexOf( check ) === 0; + } + if ( operator === "*=" ) { + return check && result.indexOf( check ) > -1; + } + if ( operator === "$=" ) { + return check && result.slice( -check.length ) === check; + } + if ( operator === "~=" ) { + return ( " " + result.replace( rwhitespace, " " ) + " " ) + .indexOf( check ) > -1; + } + if ( operator === "|=" ) { + return result === check || result.slice( 0, check.length + 1 ) === check + "-"; + } + return false; }; }, - "CHILD": function( type, what, _argument, first, last ) { + CHILD: function( type, what, _argument, first, last ) { var simple = type.slice( 0, 3 ) !== "nth", forward = type.slice( -4 ) !== "last", ofType = what === "of-type"; @@ -1926,7 +1713,7 @@ Expr = Sizzle.selectors = { } : function( elem, _context, xml ) { - var cache, uniqueCache, outerCache, node, nodeIndex, start, + var cache, outerCache, node, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), @@ -1941,7 +1728,7 @@ Expr = Sizzle.selectors = { node = elem; while ( ( node = node[ dir ] ) ) { if ( ofType ? - node.nodeName.toLowerCase() === name : + nodeName( node, name ) : node.nodeType === 1 ) { return false; @@ -1960,17 +1747,8 @@ Expr = Sizzle.selectors = { if ( forward && useCache ) { // Seek `elem` from a previously-cached index - - // ...in a gzip-friendly way - node = parent; - outerCache = node[ expando ] || ( node[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - ( outerCache[ node.uniqueID ] = {} ); - - cache = uniqueCache[ type ] || []; + outerCache = parent[ expando ] || ( parent[ expando ] = {} ); + cache = outerCache[ type ] || []; nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; diff = nodeIndex && cache[ 2 ]; node = nodeIndex && parent.childNodes[ nodeIndex ]; @@ -1982,7 +1760,7 @@ Expr = Sizzle.selectors = { // When found, cache indexes on `parent` and break if ( node.nodeType === 1 && ++diff && node === elem ) { - uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; break; } } @@ -1991,17 +1769,8 @@ Expr = Sizzle.selectors = { // Use previously-cached element index if available if ( useCache ) { - - // ...in a gzip-friendly way - node = elem; - outerCache = node[ expando ] || ( node[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - ( outerCache[ node.uniqueID ] = {} ); - - cache = uniqueCache[ type ] || []; + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + cache = outerCache[ type ] || []; nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; diff = nodeIndex; } @@ -2015,7 +1784,7 @@ Expr = Sizzle.selectors = { ( diff = nodeIndex = 0 ) || start.pop() ) ) { if ( ( ofType ? - node.nodeName.toLowerCase() === name : + nodeName( node, name ) : node.nodeType === 1 ) && ++diff ) { @@ -2023,13 +1792,7 @@ Expr = Sizzle.selectors = { if ( useCache ) { outerCache = node[ expando ] || ( node[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - ( outerCache[ node.uniqueID ] = {} ); - - uniqueCache[ type ] = [ dirruns, diff ]; + outerCache[ type ] = [ dirruns, diff ]; } if ( node === elem ) { @@ -2047,19 +1810,19 @@ Expr = Sizzle.selectors = { }; }, - "PSEUDO": function( pseudo, argument ) { + PSEUDO: function( pseudo, argument ) { // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes + // https://www.w3.org/TR/selectors/#pseudo-classes // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters // Remember that setFilters inherits from pseudos var args, fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); + find.error( "unsupported pseudo: " + pseudo ); // The user may use createPseudo to indicate that // arguments are needed to create the filter function - // just as Sizzle does + // just as jQuery does if ( fn[ expando ] ) { return fn( argument ); } @@ -2073,7 +1836,7 @@ Expr = Sizzle.selectors = { matched = fn( seed, argument ), i = matched.length; while ( i-- ) { - idx = indexOf( seed, matched[ i ] ); + idx = indexOf.call( seed, matched[ i ] ); seed[ idx ] = !( matches[ idx ] = matched[ i ] ); } } ) : @@ -2089,14 +1852,14 @@ Expr = Sizzle.selectors = { pseudos: { // Potentially complex pseudos - "not": markFunction( function( selector ) { + not: markFunction( function( selector ) { // Trim the selector passed to compile // to avoid treating leading and trailing // spaces as combinators var input = [], results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); + matcher = compile( selector.replace( rtrimCSS, "$1" ) ); return matcher[ expando ] ? markFunction( function( seed, matches, _context, xml ) { @@ -2115,22 +1878,23 @@ Expr = Sizzle.selectors = { input[ 0 ] = elem; matcher( input, null, xml, results ); - // Don't keep the element (issue #299) + // Don't keep the element + // (see https://github.com/jquery/sizzle/issues/299) input[ 0 ] = null; return !results.pop(); }; } ), - "has": markFunction( function( selector ) { + has: markFunction( function( selector ) { return function( elem ) { - return Sizzle( selector, elem ).length > 0; + return find( selector, elem ).length > 0; }; } ), - "contains": markFunction( function( text ) { + contains: markFunction( function( text ) { text = text.replace( runescape, funescape ); return function( elem ) { - return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + return ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1; }; } ), @@ -2140,12 +1904,12 @@ Expr = Sizzle.selectors = { // or beginning with the identifier C immediately followed by "-". // The matching of C against the element's language value is performed case-insensitively. // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { + // https://www.w3.org/TR/selectors/#lang-pseudo + lang: markFunction( function( lang ) { // lang value must be a valid identifier if ( !ridentifier.test( lang || "" ) ) { - Sizzle.error( "unsupported lang: " + lang ); + find.error( "unsupported lang: " + lang ); } lang = lang.replace( runescape, funescape ).toLowerCase(); return function( elem ) { @@ -2164,38 +1928,39 @@ Expr = Sizzle.selectors = { } ), // Miscellaneous - "target": function( elem ) { + target: function( elem ) { var hash = window.location && window.location.hash; return hash && hash.slice( 1 ) === elem.id; }, - "root": function( elem ) { - return elem === docElem; + root: function( elem ) { + return elem === documentElement; }, - "focus": function( elem ) { - return elem === document.activeElement && - ( !document.hasFocus || document.hasFocus() ) && + focus: function( elem ) { + return elem === safeActiveElement() && + document.hasFocus() && !!( elem.type || elem.href || ~elem.tabIndex ); }, // Boolean properties - "enabled": createDisabledPseudo( false ), - "disabled": createDisabledPseudo( true ), + enabled: createDisabledPseudo( false ), + disabled: createDisabledPseudo( true ), - "checked": function( elem ) { + checked: function( elem ) { // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return ( nodeName === "input" && !!elem.checked ) || - ( nodeName === "option" && !!elem.selected ); + // https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + return ( nodeName( elem, "input" ) && !!elem.checked ) || + ( nodeName( elem, "option" ) && !!elem.selected ); }, - "selected": function( elem ) { + selected: function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly + // Support: IE <=11+ + // Accessing the selectedIndex property + // forces the browser to treat the default option as + // selected when in an optgroup. if ( elem.parentNode ) { // eslint-disable-next-line no-unused-expressions elem.parentNode.selectedIndex; @@ -2205,9 +1970,9 @@ Expr = Sizzle.selectors = { }, // Contents - "empty": function( elem ) { + empty: function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo + // https://www.w3.org/TR/selectors/#empty-pseudo // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), // but not by others (comment: 8; processing instruction: 7; etc.) // nodeType < 6 works because attributes (2) do not appear as children @@ -2219,49 +1984,49 @@ Expr = Sizzle.selectors = { return true; }, - "parent": function( elem ) { - return !Expr.pseudos[ "empty" ]( elem ); + parent: function( elem ) { + return !Expr.pseudos.empty( elem ); }, // Element/input types - "header": function( elem ) { + header: function( elem ) { return rheader.test( elem.nodeName ); }, - "input": function( elem ) { + input: function( elem ) { return rinputs.test( elem.nodeName ); }, - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; + button: function( elem ) { + return nodeName( elem, "input" ) && elem.type === "button" || + nodeName( elem, "button" ); }, - "text": function( elem ) { + text: function( elem ) { var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && + return nodeName( elem, "input" ) && elem.type === "text" && - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + // Support: IE <10 only + // New HTML5 attribute values (e.g., "search") appear + // with elem.type === "text" ( ( attr = elem.getAttribute( "type" ) ) == null || attr.toLowerCase() === "text" ); }, // Position-in-collection - "first": createPositionalPseudo( function() { + first: createPositionalPseudo( function() { return [ 0 ]; } ), - "last": createPositionalPseudo( function( _matchIndexes, length ) { + last: createPositionalPseudo( function( _matchIndexes, length ) { return [ length - 1 ]; } ), - "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + eq: createPositionalPseudo( function( _matchIndexes, length, argument ) { return [ argument < 0 ? argument + length : argument ]; } ), - "even": createPositionalPseudo( function( matchIndexes, length ) { + even: createPositionalPseudo( function( matchIndexes, length ) { var i = 0; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); @@ -2269,7 +2034,7 @@ Expr = Sizzle.selectors = { return matchIndexes; } ), - "odd": createPositionalPseudo( function( matchIndexes, length ) { + odd: createPositionalPseudo( function( matchIndexes, length ) { var i = 1; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); @@ -2277,19 +2042,24 @@ Expr = Sizzle.selectors = { return matchIndexes; } ), - "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { - var i = argument < 0 ? - argument + length : - argument > length ? - length : - argument; + lt: createPositionalPseudo( function( matchIndexes, length, argument ) { + var i; + + if ( argument < 0 ) { + i = argument + length; + } else if ( argument > length ) { + i = length; + } else { + i = argument; + } + for ( ; --i >= 0; ) { matchIndexes.push( i ); } return matchIndexes; } ), - "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + gt: createPositionalPseudo( function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; ++i < length; ) { matchIndexes.push( i ); @@ -2299,7 +2069,7 @@ Expr = Sizzle.selectors = { } }; -Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; +Expr.pseudos.nth = Expr.pseudos.eq; // Add button/input type pseudos for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { @@ -2314,7 +2084,7 @@ function setFilters() {} setFilters.prototype = Expr.filters = Expr.pseudos; Expr.setFilters = new setFilters(); -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { +function tokenize( selector, parseOnly ) { var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[ selector + " " ]; @@ -2342,13 +2112,13 @@ tokenize = Sizzle.tokenize = function( selector, parseOnly ) { matched = false; // Combinators - if ( ( match = rcombinators.exec( soFar ) ) ) { + if ( ( match = rleadingCombinator.exec( soFar ) ) ) { matched = match.shift(); tokens.push( { value: matched, // Cast descendant combinators to space - type: match[ 0 ].replace( rtrim, " " ) + type: match[ 0 ].replace( rtrimCSS, " " ) } ); soFar = soFar.slice( matched.length ); } @@ -2375,14 +2145,16 @@ tokenize = Sizzle.tokenize = function( selector, parseOnly ) { // Return the length of the invalid excess // if we're just parsing // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : + if ( parseOnly ) { + return soFar.length; + } - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; + return soFar ? + find.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} function toSelector( tokens ) { var i = 0, @@ -2415,7 +2187,7 @@ function addCombinator( matcher, combinator, base ) { // Check against all ancestor/preceding elements function( elem, context, xml ) { - var oldCache, uniqueCache, outerCache, + var oldCache, outerCache, newCache = [ dirruns, doneName ]; // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching @@ -2432,14 +2204,9 @@ function addCombinator( matcher, combinator, base ) { if ( elem.nodeType === 1 || checkNonElements ) { outerCache = elem[ expando ] || ( elem[ expando ] = {} ); - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || - ( outerCache[ elem.uniqueID ] = {} ); - - if ( skip && skip === elem.nodeName.toLowerCase() ) { + if ( skip && nodeName( elem, skip ) ) { elem = elem[ dir ] || elem; - } else if ( ( oldCache = uniqueCache[ key ] ) && + } else if ( ( oldCache = outerCache[ key ] ) && oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { // Assign to newCache so results back-propagate to previous elements @@ -2447,7 +2214,7 @@ function addCombinator( matcher, combinator, base ) { } else { // Reuse newcache so results back-propagate to previous elements - uniqueCache[ key ] = newCache; + outerCache[ key ] = newCache; // A match means we're done; a fail means we have to keep checking if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { @@ -2479,7 +2246,7 @@ function multipleContexts( selector, contexts, results ) { var i = 0, len = contexts.length; for ( ; i < len; i++ ) { - Sizzle( selector, contexts[ i ], results ); + find( selector, contexts[ i ], results ); } return results; } @@ -2513,38 +2280,37 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS postFinder = setMatcher( postFinder, postSelector ); } return markFunction( function( seed, results, context, xml ) { - var temp, i, elem, + var temp, i, elem, matcherOut, preMap = [], postMap = [], preexisting = results.length, // Get initial elements from seed or context - elems = seed || multipleContexts( - selector || "*", - context.nodeType ? [ context ] : context, - [] - ), + elems = seed || + multipleContexts( selector || "*", + context.nodeType ? [ context ] : context, [] ), // Prefilter to get matcher input, preserving a map for seed-results synchronization matcherIn = preFilter && ( seed || !selector ) ? condense( elems, preMap, preFilter, context, xml ) : - elems, + elems; - matcherOut = matcher ? + if ( matcher ) { - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + // If we have a postFinder, or filtered seed, or non-seed postFilter + // or preexisting results, + matcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - // ...intermediate processing is necessary - [] : + // ...intermediate processing is necessary + [] : - // ...otherwise use results directly - results : - matcherIn; + // ...otherwise use results directly + results; - // Find primary matches - if ( matcher ) { + // Find primary matches matcher( matcherIn, matcherOut, context, xml ); + } else { + matcherOut = matcherIn; } // Apply postFilter @@ -2582,7 +2348,7 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS i = matcherOut.length; while ( i-- ) { if ( ( elem = matcherOut[ i ] ) && - ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + ( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) { seed[ temp ] = !( results[ temp ] = elem ); } @@ -2617,15 +2383,21 @@ function matcherFromTokens( tokens ) { return elem === checkContext; }, implicitRelative, true ), matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; + return indexOf.call( checkContext, elem ) > -1; }, implicitRelative, true ), matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + var ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || ( ( checkContext = context ).nodeType ? matchContext( elem, context, xml ) : matchAnyContext( elem, context, xml ) ); - // Avoid hanging onto element (issue #299) + // Avoid hanging onto element + // (see https://github.com/jquery/sizzle/issues/299) checkContext = null; return ret; } ]; @@ -2650,11 +2422,10 @@ function matcherFromTokens( tokens ) { i > 1 && elementMatcher( matchers ), i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens - .slice( 0, i - 1 ) - .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) - ).replace( rtrim, "$1" ), + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrimCSS, "$1" ), matcher, i < j && matcherFromTokens( tokens.slice( i, j ) ), j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), @@ -2680,7 +2451,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { contextBackup = outermostContext, // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + elems = seed || byElement && Expr.find.TAG( "*", outermost ), // Use integer dirruns iff this is the outermost matcher dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), @@ -2696,8 +2467,9 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { } // Add elements passing elementMatchers directly to results - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + // Support: iOS <=7 - 9 only + // Tolerate NodeList properties (IE: "length"; Safari: ) matching + // elements by id. (see trac-14142) for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { if ( byElement && elem ) { j = 0; @@ -2712,7 +2484,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { } while ( ( matcher = elementMatchers[ j++ ] ) ) { if ( matcher( elem, context || document, xml ) ) { - results.push( elem ); + push.call( results, elem ); break; } } @@ -2775,7 +2547,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { if ( outermost && !seed && setMatched.length > 0 && ( matchedCount + setMatchers.length ) > 1 ) { - Sizzle.uniqueSort( results ); + jQuery.uniqueSort( results ); } } @@ -2793,7 +2565,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { superMatcher; } -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { +function compile( selector, match /* Internal Use Only */ ) { var i, setMatchers = [], elementMatchers = [], @@ -2816,27 +2588,25 @@ compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { } // Cache the compiled function - cached = compilerCache( - selector, - matcherFromGroupMatchers( elementMatchers, setMatchers ) - ); + cached = compilerCache( selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) ); // Save selector and tokenization cached.selector = selector; } return cached; -}; +} /** - * A low-level selection function that works with Sizzle's compiled + * A low-level selection function that works with jQuery's compiled * selector functions * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile + * selector function built with jQuery selector compile * @param {Element} context * @param {Array} [results] * @param {Array} [seed] A set of elements to match against */ -select = Sizzle.select = function( selector, context, results, seed ) { +function select( selector, context, results, seed ) { var i, tokens, token, type, find, compiled = typeof selector === "function" && selector, match = !seed && tokenize( ( selector = compiled.selector || selector ) ); @@ -2850,10 +2620,12 @@ select = Sizzle.select = function( selector, context, results, seed ) { // Reduce context if the leading compound selector is an ID tokens = match[ 0 ] = match[ 0 ].slice( 0 ); if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { - context = ( Expr.find[ "ID" ]( token.matches[ 0 ] - .replace( runescape, funescape ), context ) || [] )[ 0 ]; + context = ( Expr.find.ID( + token.matches[ 0 ].replace( runescape, funescape ), + context + ) || [] )[ 0 ]; if ( !context ) { return results; @@ -2866,7 +2638,7 @@ select = Sizzle.select = function( selector, context, results, seed ) { } // Fetch a seed set for right-to-left matching - i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + i = matchExpr.needsContext.test( selector ) ? 0 : tokens.length; while ( i-- ) { token = tokens[ i ]; @@ -2879,8 +2651,8 @@ select = Sizzle.select = function( selector, context, results, seed ) { // Search, expanding context for leading sibling combinators if ( ( seed = find( token.matches[ 0 ].replace( runescape, funescape ), - rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || - context + rsibling.test( tokens[ 0 ].type ) && + testContext( context.parentNode ) || context ) ) ) { // If seed is empty or no tokens remain, we can return early @@ -2907,21 +2679,18 @@ select = Sizzle.select = function( selector, context, results, seed ) { !context || rsibling.test( selector ) && testContext( context.parentNode ) || context ); return results; -}; +} // One-time assignments +// Support: Android <=4.0 - 4.1+ // Sort stability support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - // Initialize against the default document setDocument(); -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Support: Android <=4.0 - 4.1+ // Detached nodes confoundingly follow *each other* support.sortDetached = assert( function( el ) { @@ -2929,68 +2698,29 @@ support.sortDetached = assert( function( el ) { return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; } ); -// Support: IE<8 -// Prevent attribute/property "interpolation" -// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert( function( el ) { - el.innerHTML = ""; - return el.firstChild.getAttribute( "href" ) === "#"; -} ) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - } ); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert( function( el ) { - el.innerHTML = ""; - el.firstChild.setAttribute( "value", "" ); - return el.firstChild.getAttribute( "value" ) === ""; -} ) ) { - addHandle( "value", function( elem, _name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - } ); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert( function( el ) { - return el.getAttribute( "disabled" ) == null; -} ) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - ( val = elem.getAttributeNode( name ) ) && val.specified ? - val.value : - null; - } - } ); -} - -return Sizzle; - -} )( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; +jQuery.find = find; // Deprecated jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; -jQuery.escapeSelector = Sizzle.escape; +jQuery.unique = jQuery.uniqueSort; +// These have always been private, but they used to be documented as part of +// Sizzle so let's maintain them for now for backwards compatibility purposes. +find.compile = compile; +find.select = select; +find.setDocument = setDocument; +find.tokenize = tokenize; +find.escape = jQuery.escapeSelector; +find.getText = jQuery.text; +find.isXML = jQuery.isXMLDoc; +find.selectors = jQuery.expr; +find.support = jQuery.support; +find.uniqueSort = jQuery.uniqueSort; + + /* eslint-enable */ + +} )(); var dir = function( elem, dir, until ) { @@ -3024,13 +2754,6 @@ var siblings = function( n, elem ) { var rneedsContext = jQuery.expr.match.needsContext; - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -} var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); @@ -3281,7 +3004,7 @@ jQuery.fn.extend( { if ( cur.nodeType < 11 && ( targets ? targets.index( cur ) > -1 : - // Don't pass non-elements to Sizzle + // Don't pass non-elements to jQuery#find cur.nodeType === 1 && jQuery.find.matchesSelector( cur, selectors ) ) ) { @@ -3836,7 +3559,7 @@ jQuery.extend( { if ( jQuery.Deferred.exceptionHook ) { jQuery.Deferred.exceptionHook( e, - process.stackTrace ); + process.error ); } // Support: Promises/A+ section 2.3.3.3.4.1 @@ -3864,10 +3587,17 @@ jQuery.extend( { process(); } else { - // Call an optional hook to record the stack, in case of exception + // Call an optional hook to record the error, in case of exception // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getStackHook ) { - process.stackTrace = jQuery.Deferred.getStackHook(); + if ( jQuery.Deferred.getErrorHook ) { + process.error = jQuery.Deferred.getErrorHook(); + + // The deprecated alias of the above. While the name suggests + // returning the stack, not an error instance, jQuery just passes + // it directly to `console.warn` so both will work; an instance + // just better cooperates with source maps. + } else if ( jQuery.Deferred.getStackHook ) { + process.error = jQuery.Deferred.getStackHook(); } window.setTimeout( process ); } @@ -4042,12 +3772,16 @@ jQuery.extend( { // warn about them ASAP rather than swallowing them by default. var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; -jQuery.Deferred.exceptionHook = function( error, stack ) { +// If `jQuery.Deferred.getErrorHook` is defined, `asyncError` is an error +// captured before the async barrier to get the original error cause +// which may otherwise be hidden. +jQuery.Deferred.exceptionHook = function( error, asyncError ) { // Support: IE 8 - 9 only // Console exists when dev tools are open, which can happen at any time if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + window.console.warn( "jQuery.Deferred exception: " + error.message, + error.stack, asyncError ); } }; @@ -5103,25 +4837,6 @@ function returnFalse() { return false; } -// Support: IE <=9 - 11+ -// focus() and blur() are asynchronous, except when they are no-op. -// So expect focus to be synchronous when the element is already active, -// and blur to be synchronous when the element is not already active. -// (focus and blur are always synchronous in other supported browsers, -// this just defines when we can count on it). -function expectSync( elem, type ) { - return ( elem === safeActiveElement() ) === ( type === "focus" ); -} - -// Support: IE <=9 only -// Accessing document.activeElement can throw unexpectedly -// https://bugs.jquery.com/ticket/13393 -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - function on( elem, types, selector, data, fn, one ) { var origFn, type; @@ -5559,7 +5274,7 @@ jQuery.event = { el.click && nodeName( el, "input" ) ) { // dataPriv.set( el, "click", ... ) - leverageNative( el, "click", returnTrue ); + leverageNative( el, "click", true ); } // Return false to allow normal processing in the caller @@ -5610,10 +5325,10 @@ jQuery.event = { // synthetic events by interrupting progress until reinvoked in response to // *native* events that it fires directly, ensuring that state changes have // already occurred before other listeners are invoked. -function leverageNative( el, type, expectSync ) { +function leverageNative( el, type, isSetup ) { - // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add - if ( !expectSync ) { + // Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add + if ( !isSetup ) { if ( dataPriv.get( el, type ) === undefined ) { jQuery.event.add( el, type, returnTrue ); } @@ -5625,15 +5340,13 @@ function leverageNative( el, type, expectSync ) { jQuery.event.add( el, type, { namespace: false, handler: function( event ) { - var notAsync, result, + var result, saved = dataPriv.get( this, type ); if ( ( event.isTrigger & 1 ) && this[ type ] ) { // Interrupt processing of the outer synthetic .trigger()ed event - // Saved data should be false in such cases, but might be a leftover capture object - // from an async native handler (gh-4350) - if ( !saved.length ) { + if ( !saved ) { // Store arguments for use when handling the inner native event // There will always be at least one argument (an event object), so this array @@ -5642,33 +5355,22 @@ function leverageNative( el, type, expectSync ) { dataPriv.set( this, type, saved ); // Trigger the native event and capture its result - // Support: IE <=9 - 11+ - // focus() and blur() are asynchronous - notAsync = expectSync( this, type ); this[ type ](); result = dataPriv.get( this, type ); - if ( saved !== result || notAsync ) { - dataPriv.set( this, type, false ); - } else { - result = {}; - } + dataPriv.set( this, type, false ); + if ( saved !== result ) { // Cancel the outer synthetic event event.stopImmediatePropagation(); event.preventDefault(); - // Support: Chrome 86+ - // In Chrome, if an element having a focusout handler is blurred by - // clicking outside of it, it invokes the handler synchronously. If - // that handler calls `.remove()` on the element, the data is cleared, - // leaving `result` undefined. We need to guard against this. - return result && result.value; + return result; } // If this is an inner synthetic event for an event with a bubbling surrogate - // (focus or blur), assume that the surrogate already propagated from triggering the - // native event and prevent that from happening again here. + // (focus or blur), assume that the surrogate already propagated from triggering + // the native event and prevent that from happening again here. // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the // bubbling surrogate propagates *after* the non-bubbling base), but that seems // less bad than duplication. @@ -5678,22 +5380,25 @@ function leverageNative( el, type, expectSync ) { // If this is a native event triggered above, everything is now in order // Fire an inner synthetic event with the original arguments - } else if ( saved.length ) { + } else if ( saved ) { // ...and capture the result - dataPriv.set( this, type, { - value: jQuery.event.trigger( - - // Support: IE <=9 - 11+ - // Extend with the prototype to reset the above stopImmediatePropagation() - jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), - saved.slice( 1 ), - this - ) - } ); - - // Abort handling of the native event - event.stopImmediatePropagation(); + dataPriv.set( this, type, jQuery.event.trigger( + saved[ 0 ], + saved.slice( 1 ), + this + ) ); + + // Abort handling of the native event by all jQuery handlers while allowing + // native handlers on the same element to run. On target, this is achieved + // by stopping immediate propagation just on the jQuery event. However, + // the native event is re-wrapped by a jQuery one on each level of the + // propagation so the only way to stop it for jQuery is to stop it for + // everyone via native `stopPropagation()`. This is not a problem for + // focus/blur which don't bubble, but it does also stop click on checkboxes + // and radios. We accept this limitation. + event.stopPropagation(); + event.isImmediatePropagationStopped = returnTrue; } } } ); @@ -5832,18 +5537,73 @@ jQuery.each( { }, jQuery.event.addProp ); jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + + function focusMappedHandler( nativeEvent ) { + if ( document.documentMode ) { + + // Support: IE 11+ + // Attach a single focusin/focusout handler on the document while someone wants + // focus/blur. This is because the former are synchronous in IE while the latter + // are async. In other browsers, all those handlers are invoked synchronously. + + // `handle` from private data would already wrap the event, but we need + // to change the `type` here. + var handle = dataPriv.get( this, "handle" ), + event = jQuery.event.fix( nativeEvent ); + event.type = nativeEvent.type === "focusin" ? "focus" : "blur"; + event.isSimulated = true; + + // First, handle focusin/focusout + handle( nativeEvent ); + + // ...then, handle focus/blur + // + // focus/blur don't bubble while focusin/focusout do; simulate the former by only + // invoking the handler at the lower level. + if ( event.target === event.currentTarget ) { + + // The setup part calls `leverageNative`, which, in turn, calls + // `jQuery.event.add`, so event handle will already have been set + // by this point. + handle( event ); + } + } else { + + // For non-IE browsers, attach a single capturing handler on the document + // while someone wants focusin/focusout. + jQuery.event.simulate( delegateType, nativeEvent.target, + jQuery.event.fix( nativeEvent ) ); + } + } + jQuery.event.special[ type ] = { // Utilize native event if possible so blur/focus sequence is correct setup: function() { + var attaches; + // Claim the first handler // dataPriv.set( this, "focus", ... ) // dataPriv.set( this, "blur", ... ) - leverageNative( this, type, expectSync ); + leverageNative( this, type, true ); - // Return false to allow normal processing in the caller - return false; + if ( document.documentMode ) { + + // Support: IE 9 - 11+ + // We use the same native handler for focusin & focus (and focusout & blur) + // so we need to coordinate setup & teardown parts between those events. + // Use `delegateType` as the key as `type` is already used by `leverageNative`. + attaches = dataPriv.get( this, delegateType ); + if ( !attaches ) { + this.addEventListener( delegateType, focusMappedHandler ); + } + dataPriv.set( this, delegateType, ( attaches || 0 ) + 1 ); + } else { + + // Return false to allow normal processing in the caller + return false; + } }, trigger: function() { @@ -5854,6 +5614,24 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp return true; }, + teardown: function() { + var attaches; + + if ( document.documentMode ) { + attaches = dataPriv.get( this, delegateType ) - 1; + if ( !attaches ) { + this.removeEventListener( delegateType, focusMappedHandler ); + dataPriv.remove( this, delegateType ); + } else { + dataPriv.set( this, delegateType, attaches ); + } + } else { + + // Return false to indicate standard teardown should be applied + return false; + } + }, + // Suppress native focus or blur if we're currently inside // a leveraged native-event stack _default: function( event ) { @@ -5862,6 +5640,58 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp delegateType: delegateType }; + + // Support: Firefox <=44 + // Firefox doesn't have focus(in | out) events + // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 + // + // Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 + // focus(in | out) events fire after focus & blur events, + // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order + // Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 + // + // Support: IE 9 - 11+ + // To preserve relative focusin/focus & focusout/blur event order guaranteed on the 3.x branch, + // attach a single handler for both events in IE. + jQuery.event.special[ delegateType ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + dataHolder = document.documentMode ? this : doc, + attaches = dataPriv.get( dataHolder, delegateType ); + + // Support: IE 9 - 11+ + // We use the same native handler for focusin & focus (and focusout & blur) + // so we need to coordinate setup & teardown parts between those events. + // Use `delegateType` as the key as `type` is already used by `leverageNative`. + if ( !attaches ) { + if ( document.documentMode ) { + this.addEventListener( delegateType, focusMappedHandler ); + } else { + doc.addEventListener( type, focusMappedHandler, true ); + } + } + dataPriv.set( dataHolder, delegateType, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + dataHolder = document.documentMode ? this : doc, + attaches = dataPriv.get( dataHolder, delegateType ) - 1; + + if ( !attaches ) { + if ( document.documentMode ) { + this.removeEventListener( delegateType, focusMappedHandler ); + } else { + doc.removeEventListener( type, focusMappedHandler, true ); + } + dataPriv.remove( dataHolder, delegateType ); + } else { + dataPriv.set( dataHolder, delegateType, attaches ); + } + } + }; } ); // Create mouseenter/leave events using mouseover/out and event-time checks @@ -6093,7 +5923,7 @@ function domManip( collection, args, callback, ignored ) { if ( hasScripts ) { doc = scripts[ scripts.length - 1 ].ownerDocument; - // Reenable scripts + // Re-enable scripts jQuery.map( scripts, restoreScript ); // Evaluate executable scripts on first document insertion @@ -6164,7 +5994,8 @@ jQuery.extend( { if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) { - // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + // We eschew jQuery#find here for performance reasons: + // https://jsperf.com/getall-vs-sizzle/2 destElements = getAll( clone ); srcElements = getAll( elem ); @@ -6440,15 +6271,6 @@ var swap = function( elem, options, callback ) { var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); -var whitespace = "[\\x20\\t\\r\\n\\f]"; - - -var rtrimCSS = new RegExp( - "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", - "g" -); - - ( function() { @@ -6558,7 +6380,7 @@ var rtrimCSS = new RegExp( trChild = document.createElement( "div" ); table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; - tr.style.cssText = "border:1px solid"; + tr.style.cssText = "box-sizing:content-box;border:1px solid"; // Support: Chrome 86+ // Height set through cssText does not get applied. @@ -6570,7 +6392,7 @@ var rtrimCSS = new RegExp( // In our bodyBackground.html iframe, // display for all div elements is set to "inline", // which causes a problem only in Android 8 Chrome 86. - // Ensuring the div is display: block + // Ensuring the div is `display: block` // gets around this issue. trChild.style.display = "block"; @@ -6608,17 +6430,37 @@ function curCSS( elem, name, computed ) { // .css('filter') (IE 9 only, trac-12537) // .css('--customProperty) (gh-3144) if ( computed ) { - ret = computed.getPropertyValue( name ) || computed[ name ]; - // trim whitespace for custom property (issue gh-4926) - if ( isCustomProp ) { + // Support: IE <=9 - 11+ + // IE only supports `"float"` in `getPropertyValue`; in computed styles + // it's only available as `"cssFloat"`. We no longer modify properties + // sent to `.css()` apart from camelCasing, so we need to check both. + // Normally, this would create difference in behavior: if + // `getPropertyValue` returns an empty string, the value returned + // by `.css()` would be `undefined`. This is usually the case for + // disconnected elements. However, in IE even disconnected elements + // with no styles return `"none"` for `getPropertyValue( "float" )` + ret = computed.getPropertyValue( name ) || computed[ name ]; - // rtrim treats U+000D CARRIAGE RETURN and U+000C FORM FEED + if ( isCustomProp && ret ) { + + // Support: Firefox 105+, Chrome <=105+ + // Spec requires trimming whitespace for custom properties (gh-4926). + // Firefox only trims leading whitespace. Chrome just collapses + // both leading & trailing whitespace to a single space. + // + // Fall back to `undefined` if empty string returned. + // This collapses a missing definition with property defined + // and set to an empty string but there's no standard API + // allowing us to differentiate them without a performance penalty + // and returning `undefined` aligns with older jQuery. + // + // rtrimCSS treats U+000D CARRIAGE RETURN and U+000C FORM FEED // as whitespace while CSS does not, but this is not a problem // because CSS preprocessing replaces them with U+000A LINE FEED // (which *is* CSS whitespace) // https://www.w3.org/TR/css-syntax-3/#input-preprocessing - ret = ret.replace( rtrimCSS, "$1" ); + ret = ret.replace( rtrimCSS, "$1" ) || undefined; } if ( ret === "" && !isAttached( elem ) ) { @@ -6737,7 +6579,8 @@ function setPositiveNumber( _elem, value, subtract ) { function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { var i = dimension === "width" ? 1 : 0, extra = 0, - delta = 0; + delta = 0, + marginDelta = 0; // Adjustment may not be necessary if ( box === ( isBorderBox ? "border" : "content" ) ) { @@ -6747,8 +6590,10 @@ function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computed for ( ; i < 4; i += 2 ) { // Both box models exclude margin + // Count margin delta separately to only add it after scroll gutter adjustment. + // This is needed to make negative margins work with `outerHeight( true )` (gh-3982). if ( box === "margin" ) { - delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + marginDelta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); } // If we get here with a content-box, we're seeking "padding" or "border" or "margin" @@ -6799,7 +6644,7 @@ function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computed ) ) || 0; } - return delta; + return delta + marginDelta; } function getWidthOrHeight( elem, dimension, extra ) { @@ -6897,26 +6742,35 @@ jQuery.extend( { // Don't automatically add "px" to these possibly-unitless properties cssNumber: { - "animationIterationCount": true, - "columnCount": true, - "fillOpacity": true, - "flexGrow": true, - "flexShrink": true, - "fontWeight": true, - "gridArea": true, - "gridColumn": true, - "gridColumnEnd": true, - "gridColumnStart": true, - "gridRow": true, - "gridRowEnd": true, - "gridRowStart": true, - "lineHeight": true, - "opacity": true, - "order": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true + animationIterationCount: true, + aspectRatio: true, + borderImageSlice: true, + columnCount: true, + flexGrow: true, + flexShrink: true, + fontWeight: true, + gridArea: true, + gridColumn: true, + gridColumnEnd: true, + gridColumnStart: true, + gridRow: true, + gridRowEnd: true, + gridRowStart: true, + lineHeight: true, + opacity: true, + order: true, + orphans: true, + scale: true, + widows: true, + zIndex: true, + zoom: true, + + // SVG-related + fillOpacity: true, + floodOpacity: true, + stopOpacity: true, + strokeMiterlimit: true, + strokeOpacity: true }, // Add in properties whose names you wish to fix before @@ -8642,9 +8496,39 @@ jQuery.each( [ "radio", "checkbox" ], function() { // Return jQuery for attributes-only inclusion +var location = window.location; + +var nonce = { guid: Date.now() }; +var rquery = ( /\?/ ); -support.focusin = "onfocusin" in window; + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml, parserErrorElem; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) {} + + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); + } + return xml; +}; var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, @@ -8832,85 +8716,6 @@ jQuery.fn.extend( { } ); -// Support: Firefox <=44 -// Firefox doesn't have focus(in | out) events -// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 -// -// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 -// focus(in | out) events fire after focus & blur events, -// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order -// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 -if ( !support.focusin ) { - jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - - // Handle: regular nodes (via `this.ownerDocument`), window - // (via `this.document`) & document (via `this`). - var doc = this.ownerDocument || this.document || this, - attaches = dataPriv.access( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this.document || this, - attaches = dataPriv.access( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - dataPriv.remove( doc, fix ); - - } else { - dataPriv.access( doc, fix, attaches ); - } - } - }; - } ); -} -var location = window.location; - -var nonce = { guid: Date.now() }; - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml, parserErrorElem; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) {} - - parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; - if ( !xml || parserErrorElem ) { - jQuery.error( "Invalid XML: " + ( - parserErrorElem ? - jQuery.map( parserErrorElem.childNodes, function( el ) { - return el.textContent; - } ).join( "\n" ) : - data - ) ); - } - return xml; -}; - - var rbracket = /\[\]$/, rCRLF = /\r?\n/g, @@ -10755,7 +10560,9 @@ jQuery.fn.extend( { }, hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + return this + .on( "mouseenter", fnOver ) + .on( "mouseleave", fnOut || fnOver ); } } ); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.7.1.min.js b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.7.1.min.js new file mode 100644 index 00000000000..7f37b5d9912 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.7.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0 +#include #include +#include #include #include #include #include "sys.h" #include "util.h" +#include "error_messages.h" static char *skipWhitespace(char *p) { while ((*p != '\0') && isspace(*p)) { @@ -44,6 +48,106 @@ static char *skipNonWhitespace(char *p) { return p; } +#if defined(_AIX) + /* AIX does not understand '/proc/self' - it requires the real process ID */ + #define FD_DIR aix_fd_dir + #define DIR DIR64 + #define dirent dirent64 + #define opendir opendir64 + #define readdir readdir64 + #define closedir closedir64 +#elif defined(_ALLBSD_SOURCE) + #define FD_DIR "/dev/fd" +#else + #define FD_DIR "/proc/self/fd" +#endif + +// Closes every file descriptor that is listed as a directory +// entry in "/proc/self/fd" (or its equivalent). Standard +// input/output/error file descriptors will not be closed +// by this function. This function returns 0 on failure +// and 1 on success. +int +closeDescriptors(void) +{ + DIR *dp; + struct dirent *dirp; + /* leave out standard input/output/error descriptors */ + int from_fd = STDERR_FILENO + 1; + + /* We're trying to close all file descriptors, but opendir() might + * itself be implemented using a file descriptor, and we certainly + * don't want to close that while it's in use. We assume that if + * opendir() is implemented using a file descriptor, then it uses + * the lowest numbered file descriptor, just like open(). So + * before calling opendir(), we close a couple explicitly, so that + * opendir() can then use these lowest numbered closed file + * descriptors afresh. */ + + close(from_fd); /* for possible use by opendir() */ + close(from_fd + 1); /* another one for good luck */ + from_fd += 2; /* leave out the 2 we just closed, which the opendir() may use */ + +#if defined(_AIX) + /* set FD_DIR for AIX which does not understand '/proc/self' - it + * requires the real process ID */ + char aix_fd_dir[32]; /* the pid has at most 19 digits */ + snprintf(aix_fd_dir, 32, "/proc/%d/fd", getpid()); +#endif + + if ((dp = opendir(FD_DIR)) == NULL) { + ERROR_MESSAGE(("failed to open dir %s while determining" + " file descriptors to close for process %d", + FD_DIR, getpid())); + return 0; // failure + } + + while ((dirp = readdir(dp)) != NULL) { + if (!isdigit(dirp->d_name[0])) { + continue; + } + const long fd = strtol(dirp->d_name, NULL, 10); + if (fd <= INT_MAX && fd >= from_fd) { + (void)close((int)fd); + } + } + + (void)closedir(dp); + + return 1; // success +} + +// Does necessary housekeeping of a forked child process +// (like closing copied file descriptors) before +// execing the child process. This function never returns. +void +forkedChildProcess(const char *file, char *const argv[]) +{ + /* Close all file descriptors that have been copied over + * from the parent process due to fork(). */ + if (closeDescriptors() == 0) { /* failed, close the old way */ + /* Find max allowed file descriptors for a process + * and assume all were opened for the parent process and + * copied over to this child process. We close them all. */ + const rlim_t max_fd = sysconf(_SC_OPEN_MAX); + JDI_ASSERT(max_fd != (rlim_t)-1); // -1 represents error + /* close(), that we subsequently call, takes only int values */ + JDI_ASSERT(max_fd <= INT_MAX); + /* leave out standard input/output/error file descriptors */ + rlim_t i = STDERR_FILENO + 1; + ERROR_MESSAGE(("failed to close file descriptors of" + " child process optimally, falling back to closing" + " %d file descriptors sequentially", (max_fd - i + 1))); + for (; i < max_fd; i++) { + (void)close(i); + } + } + + (void)execvp(file, argv); /* not expected to return */ + + exit(errno); /* errno will have been set by the failed execvp */ +} + int dbgsysExec(char *cmdLine) { @@ -93,21 +197,11 @@ dbgsysExec(char *cmdLine) argv[i] = NULL; /* NULL terminate */ if ((pid = fork()) == 0) { - /* Child process */ - int i; - long max_fd; - - /* close everything */ - max_fd = sysconf(_SC_OPEN_MAX); - /*LINTED*/ - for (i = 3; i < (int)max_fd; i++) { - (void)close(i); - } - - (void)execvp(argv[0], argv); - - exit(-1); + // manage the child process + forkedChildProcess(argv[0], argv); } + // call to forkedChildProcess(...) will never return for a forked process + JDI_ASSERT(pid != 0); jvmtiDeallocate(args); jvmtiDeallocate(argv); if (pid == pid_err) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java index cc9e02fb75b..82fa6da8ec3 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -265,10 +265,11 @@ public T run() { public static List getPredefinedJFCFiles() { List list = new ArrayList<>(); - try (var ds = doPrivilegedIOWithReturn(() -> Files.newDirectoryStream(JFC_DIRECTORY.toPath(), "*.jfc"))) { + try (var ds = doPrivilegedIOWithReturn(() -> Files.newDirectoryStream(JFC_DIRECTORY.toPath()))) { for (Path path : ds) { SafePath s = new SafePath(path); - if (!SecuritySupport.isDirectory(s)) { + String text = s.toString(); + if (text.endsWith(".jfc") && !SecuritySupport.isDirectory(s)) { list.add(s); } } diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index 5743b64285b..34e9d5b9064 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -807,6 +807,7 @@ true + true 0 ms diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index 816408a4baf..bdd148121c1 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -807,6 +807,7 @@ true + true 0 ms diff --git a/src/jdk.management/share/native/libmanagement_ext/GcInfoBuilder.c b/src/jdk.management/share/native/libmanagement_ext/GcInfoBuilder.c index 3d21a896ec3..45a093551c3 100644 --- a/src/jdk.management/share/native/libmanagement_ext/GcInfoBuilder.c +++ b/src/jdk.management/share/native/libmanagement_ext/GcInfoBuilder.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,7 +129,9 @@ static void setLongValueAtObjectArray(JNIEnv *env, jobjectArray array, static const char* class_name = "java/lang/Long"; static const char* signature = "(J)V"; jobject obj = JNU_NewObjectByName(env, class_name, signature, value); - + if ((*env)->ExceptionCheck(env)) { + return; + } (*env)->SetObjectArrayElement(env, array, index, obj); } @@ -138,7 +140,9 @@ static void setBooleanValueAtObjectArray(JNIEnv *env, jobjectArray array, static const char* class_name = "java/lang/Boolean"; static const char* signature = "(Z)V"; jobject obj = JNU_NewObjectByName(env, class_name, signature, value); - + if ((*env)->ExceptionCheck(env)) { + return; + } (*env)->SetObjectArrayElement(env, array, index, obj); } @@ -147,7 +151,9 @@ static void setByteValueAtObjectArray(JNIEnv *env, jobjectArray array, static const char* class_name = "java/lang/Byte"; static const char* signature = "(B)V"; jobject obj = JNU_NewObjectByName(env, class_name, signature, value); - + if ((*env)->ExceptionCheck(env)) { + return; + } (*env)->SetObjectArrayElement(env, array, index, obj); } @@ -156,7 +162,9 @@ static void setIntValueAtObjectArray(JNIEnv *env, jobjectArray array, static const char* class_name = "java/lang/Integer"; static const char* signature = "(I)V"; jobject obj = JNU_NewObjectByName(env, class_name, signature, value); - + if ((*env)->ExceptionCheck(env)) { + return; + } (*env)->SetObjectArrayElement(env, array, index, obj); } @@ -165,7 +173,9 @@ static void setShortValueAtObjectArray(JNIEnv *env, jobjectArray array, static const char* class_name = "java/lang/Short"; static const char* signature = "(S)V"; jobject obj = JNU_NewObjectByName(env, class_name, signature, value); - + if ((*env)->ExceptionCheck(env)) { + return; + } (*env)->SetObjectArrayElement(env, array, index, obj); } @@ -174,7 +184,9 @@ static void setDoubleValueAtObjectArray(JNIEnv *env, jobjectArray array, static const char* class_name = "java/lang/Double"; static const char* signature = "(D)V"; jobject obj = JNU_NewObjectByName(env, class_name, signature, value); - + if ((*env)->ExceptionCheck(env)) { + return; + } (*env)->SetObjectArrayElement(env, array, index, obj); } @@ -183,7 +195,9 @@ static void setFloatValueAtObjectArray(JNIEnv *env, jobjectArray array, static const char* class_name = "java/lang/Float"; static const char* signature = "(D)V"; jobject obj = JNU_NewObjectByName(env, class_name, signature, value); - + if ((*env)->ExceptionCheck(env)) { + return; + } (*env)->SetObjectArrayElement(env, array, index, obj); } @@ -192,7 +206,9 @@ static void setCharValueAtObjectArray(JNIEnv *env, jobjectArray array, static const char* class_name = "java/lang/Character"; static const char* signature = "(C)V"; jobject obj = JNU_NewObjectByName(env, class_name, signature, value); - + if ((*env)->ExceptionCheck(env)) { + return; + } (*env)->SetObjectArrayElement(env, array, index, obj); } @@ -293,6 +309,10 @@ JNIEXPORT jobject JNICALL Java_com_sun_management_internal_GcInfoBuilder_getLast if (nativeTypes != NULL) { free(nativeTypes); } + // Recognise possible Exception from the switch statement above: + if ((*env)->ExceptionCheck(env)) { + return NULL; + } return JNU_NewObjectByName(env, "com/sun/management/GcInfo", diff --git a/src/utils/LogCompilation/Makefile b/src/utils/LogCompilation/Makefile index 5f9ca083842..6ab946abc20 100644 --- a/src/utils/LogCompilation/Makefile +++ b/src/utils/LogCompilation/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -19,7 +19,7 @@ # 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. -# +# # PKGLIST = \ com.sun.hotspot.tools.compiler @@ -49,7 +49,7 @@ SRC_DIR = src BUILD_DIR = build OUTPUT_DIR = $(BUILD_DIR)/classes -# gnumake 3.78.1 does not accept the *s, +# gnumake 3.78.1 does not accept the *s, # so use the shell to expand them ALLFILES := $(patsubst %,$(SRC_DIR)/%,$(FILELIST)) ALLFILES := $(shell /bin/ls $(ALLFILES)) diff --git a/test/failure_handler/README b/test/failure_handler/README index a03136ae3aa..f629a1fbc91 100644 --- a/test/failure_handler/README +++ b/test/failure_handler/README @@ -102,3 +102,15 @@ $ ${JTREG_HOME}/bin/jtreg -jdk:${JAVA_HOME} \ -timeoutHandler:jdk.test.failurehandler.jtreg.GatherProcessInfoTimeoutHandler\ -observer:jdk.test.failurehandler.jtreg.GatherDiagnosticInfoObserver \ ${WS}/hotspot/test/ + +TESTING + +There are a few make targets for testing the failure_handler itself. + - Everything in `test/failure_handler/Makefile` + - The `test-failure-handler` target in `make/RunTests.gmk` + - The `test` target in `make/test/BuildFailureHandler.gmk` +All of these targets are written for manual testing only. They rely on +manual inspection of generated artifacts and cannot be run as part of a CI. +They are tests which timeout, crash, fail in various ways and you can check +the failure_handler output yourself. They might also leave processes running +on your machine so be extra careful about cleaning up. diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java index 2f26654927d..76d4e8c1c71 100644 --- a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java @@ -164,7 +164,7 @@ private ExitCode run(HtmlSection section, PrintWriter log, Writer out, ProcessBu Stopwatch stopwatch = new Stopwatch(); stopwatch.start(); - log.printf("%s%n[%tF % tmp4 = std::regex_replace(tmp3, std::regex("\\s+:\\s+unimp"), ""); // Padding: x64 - std::basic_string red = std::regex_replace(tmp4, std::regex("\\s+:\\s+hlt[ \\t]+(?!\\n\\s+;;)"), ""); + std::basic_string tmp5 = std::regex_replace(tmp4, std::regex("\\s+:\\s+hlt[ \\t]+(?!\\n\\s+;;)"), ""); + std::basic_string red = std::regex_replace(tmp5, std::regex("(\\s+:\\s+nop)[ \\t]*"), "$1"); return os::strdup(red.c_str()); } diff --git a/test/hotspot/gtest/logging/test_asynclog.cpp b/test/hotspot/gtest/logging/test_asynclog.cpp index 216cc320d38..994c4df6fa6 100644 --- a/test/hotspot/gtest/logging/test_asynclog.cpp +++ b/test/hotspot/gtest/logging/test_asynclog.cpp @@ -69,21 +69,22 @@ LOG_LEVEL_LIST log_debug(logging)("log_debug-test"); } + // Caveat: BufferUpdater is not MT-safe. We use it only for testing. + // We would observe missing loglines if we interleaved buffers. + // Emit all logs between constructor and destructor of BufferUpdater. void test_asynclog_drop_messages() { - auto writer = AsyncLogWriter::instance(); - if (writer != nullptr) { - const size_t sz = 2000; + const size_t sz = 2000; - // shrink async buffer. - AsyncLogWriter::BufferUpdater saver(1024); - LogMessage(logging) lm; + // shrink async buffer. + AsyncLogWriter::BufferUpdater saver(1024); + test_asynclog_ls(); // roughly 200 bytes. + LogMessage(logging) lm; - // write more messages than its capacity in burst - for (size_t i = 0; i < sz; ++i) { - lm.debug("a lot of log..."); - } - lm.flush(); + // write more messages than its capacity in burst + for (size_t i = 0; i < sz; ++i) { + lm.debug("a lot of log..."); } + lm.flush(); } // stdout/stderr support @@ -93,8 +94,7 @@ LOG_LEVEL_LIST if (f != NULL) { size_t sz = output.size(); size_t written = fwrite(output.c_str(), sizeof(char), output.size(), f); - // at least see "header" - return fclose(f) == 0 && sz == written && sz >= 6; + return fclose(f) == 0 && sz == written; } return false; @@ -244,33 +244,34 @@ TEST_VM_F(AsyncLogTest, logBuffer) { } TEST_VM_F(AsyncLogTest, droppingMessage) { + if (AsyncLogWriter::instance() == nullptr) { + return; + } + set_log_config(TestLogFileName, "logging=debug"); test_asynclog_drop_messages(); - - AsyncLogWriter::flush(); - if (AsyncLogWriter::instance() != nullptr) { - EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); - } + EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); } TEST_VM_F(AsyncLogTest, stdoutOutput) { testing::internal::CaptureStdout(); - fprintf(stdout, "header"); set_log_config("stdout", "logging=debug"); - test_asynclog_ls(); - test_asynclog_drop_messages(); + bool async = AsyncLogWriter::instance() != nullptr; + if (async) { + test_asynclog_drop_messages(); + AsyncLogWriter::flush(); + } else { + test_asynclog_ls(); + } - AsyncLogWriter::flush(); fflush(nullptr); - if (write_to_file(testing::internal::GetCapturedStdout())) { - EXPECT_TRUE(file_contains_substring(TestLogFileName, "header")); EXPECT_TRUE(file_contains_substring(TestLogFileName, "LogStreamWithAsyncLogImpl")); EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream msg1-msg2-msg3")); EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream newline")); - if (AsyncLogWriter::instance() != nullptr) { + if (async) { EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); } } @@ -278,22 +279,23 @@ TEST_VM_F(AsyncLogTest, stdoutOutput) { TEST_VM_F(AsyncLogTest, stderrOutput) { testing::internal::CaptureStderr(); - fprintf(stderr, "header"); set_log_config("stderr", "logging=debug"); - test_asynclog_ls(); - test_asynclog_drop_messages(); + bool async = AsyncLogWriter::instance() != nullptr; + if (async) { + test_asynclog_drop_messages(); + AsyncLogWriter::flush(); + } else { + test_asynclog_ls(); + } - AsyncLogWriter::flush(); fflush(nullptr); - if (write_to_file(testing::internal::GetCapturedStderr())) { - EXPECT_TRUE(file_contains_substring(TestLogFileName, "header")); EXPECT_TRUE(file_contains_substring(TestLogFileName, "LogStreamWithAsyncLogImpl")); EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream msg1-msg2-msg3")); EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream newline")); - if (AsyncLogWriter::instance() != nullptr) { + if (async) { EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); } } diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 9b0c7d38507..246b56fb4b9 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -169,31 +169,31 @@ static void do_test_print_hex_dump(address addr, size_t len, int unitsize, const buf[0] = '\0'; stringStream ss(buf, sizeof(buf)); os::print_hex_dump(&ss, addr, addr + len, unitsize); -// tty->print_cr("expected: %s", expected); -// tty->print_cr("result: %s", buf); - ASSERT_NE(strstr(buf, expected), (char*)NULL); + // tty->print_cr("expected: %s", expected); + // tty->print_cr("result: %s", buf); + EXPECT_THAT(buf, testing::HasSubstr(expected)); } TEST_VM(os, test_print_hex_dump) { const char* pattern [4] = { #ifdef VM_LITTLE_ENDIAN - "00 01 02 03 04 05 06 07", - "0100 0302 0504 0706", - "03020100 07060504", - "0706050403020100" + "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f", + "0100 0302 0504 0706 0908 0b0a 0d0c 0f0e", + "03020100 07060504 0b0a0908 0f0e0d0c", + "0706050403020100 0f0e0d0c0b0a0908" #else - "00 01 02 03 04 05 06 07", - "0001 0203 0405 0607", - "00010203 04050607", - "0001020304050607" + "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f", + "0001 0203 0405 0607 0809 0a0b 0c0d 0e0f", + "00010203 04050607 08090a0b 0c0d0e0f", + "0001020304050607 08090a0b0c0d0e0f" #endif }; const char* pattern_not_readable [4] = { - "?? ?? ?? ?? ?? ?? ?? ??", - "???? ???? ???? ????", - "???????? ????????", - "????????????????" + "?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??", + "???? ???? ???? ???? ???? ???? ???? ????", + "???????? ???????? ???????? ????????", + "???????????????? ????????????????" }; // On AIX, zero page is readable. diff --git a/test/hotspot/gtest/runtime/test_os_linux.cpp b/test/hotspot/gtest/runtime/test_os_linux.cpp index b1826276e00..460c23c3cd8 100644 --- a/test/hotspot/gtest/runtime/test_os_linux.cpp +++ b/test/hotspot/gtest/runtime/test_os_linux.cpp @@ -427,6 +427,40 @@ TEST_VM(os_linux, reserve_memory_special_concurrent) { } } +TEST_VM(os_linux, pretouch_thp_and_use_concurrent) { + // Explicitly enable thp to test cocurrent system calls. + const size_t size = 1 * G; + const bool useThp = UseTransparentHugePages; + UseTransparentHugePages = true; + char* const heap = os::reserve_memory(size, false, mtInternal); + EXPECT_NE(heap, nullptr); + EXPECT_TRUE(os::commit_memory(heap, size, false)); + + { + auto pretouch = [heap, size](Thread*, int) { + os::pretouch_memory(heap, heap + size, os::vm_page_size()); + }; + auto useMemory = [heap, size](Thread*, int) { + int* iptr = reinterpret_cast(heap); + for (int i = 0; i < 1000; i++) *iptr++ = i; + }; + TestThreadGroup pretouchThreads{pretouch, 4}; + TestThreadGroup useMemoryThreads{useMemory, 4}; + useMemoryThreads.doit(); + pretouchThreads.doit(); + useMemoryThreads.join(); + pretouchThreads.join(); + } + + int* iptr = reinterpret_cast(heap); + for (int i = 0; i < 1000; i++) + EXPECT_EQ(*iptr++, i); + + EXPECT_TRUE(os::uncommit_memory(heap, size, false)); + EXPECT_TRUE(os::release_memory(heap, size)); + UseTransparentHugePages = useThp; +} + // Check that method JNI_CreateJavaVM is found. TEST(os_linux, addr_to_function_valid) { char buf[128] = ""; diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt index 6780e5a5b58..1a1eb1fd9c6 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -48,3 +48,5 @@ vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manySame_a/TestDescription.java vmTestbase/vm/mlvm/indy/func/jvmti/redefineClassInTarget/TestDescription.java 8308367 windows-x64 vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 8299493 macosx-x64 + +gc/arguments/TestNewSizeFlags.java 8299116 macosx-aarch64 diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index 9598cc36ae4..0ae85b38460 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -33,7 +33,7 @@ serviceability/sa/ClhsdbJhisto.java 8276539 generic- serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java 8276539 generic-all serviceability/sa/ClhsdbFindPC.java#xcomp-core 8284045 generic-all -serviceability/sa/TestJmapCore.java 8268283,8270202 linux-aarch64,linux-x64,macosx-aarch64 +serviceability/sa/TestJmapCore.java 8268283,8270202 generic-all serviceability/sa/TestJmapCoreMetaspace.java 8268636 generic-all serviceability/sa/TestJhsdbJstackMixed.java 8248912 generic-all diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index e43d968fcfa..d3712014e23 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -73,6 +73,8 @@ compiler/vectorapi/VectorLogicalOpIdentityTest.java 8302459 linux-x64,windows-x6 compiler/jvmci/TestUncaughtErrorInCompileMethod.java 8309073 generic-all +compiler/codecache/CheckLargePages.java 8319795 linux-x64 + ############################################################################# # :hotspot_gc @@ -136,6 +138,8 @@ serviceability/sa/TestJmapCoreMetaspace.java 8294316,8267433 macosx-x64 serviceability/attach/ConcAttachTest.java 8290043 linux-all +serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64 + ############################################################################# # :hotspot_misc diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index 7b1212ec373..a67235c2736 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -64,6 +64,7 @@ requires.properties= \ vm.gc.ZGenerational \ vm.gc.ZSinglegen \ vm.jvmci \ + vm.jvmci.enabled \ vm.emulatedClient \ vm.cpu.features \ vm.pageSize \ diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 4923fbd5b27..8df213c1fab 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -57,6 +57,13 @@ hotspot_runtime_no_cds = \ runtime \ -runtime/cds +hotspot_runtime_non_cds_mode = \ + runtime \ + -runtime/cds/CheckSharingWithDefaultArchive.java \ + -runtime/cds/appcds/dynamicArchive/DynamicSharedSymbols.java \ + -runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchive.java \ + -runtime/cds/appcds/jcmd + hotspot_handshake = \ runtime/handshake diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyOfRangeGuards.java b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyOfRangeGuards.java new file mode 100644 index 00000000000..e5886d7002b --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyOfRangeGuards.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8323682 + * @summary Test that the appropriate guards are generated for the copyOfRange + * intrinsic, even if the result of the array copy is not used. + * + * @run main/othervm -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.arraycopy.TestArrayCopyOfRangeGuards::test + * -Xbatch + * compiler.arraycopy.TestArrayCopyOfRangeGuards + */ + +package compiler.arraycopy; + +import java.util.Arrays; + +public class TestArrayCopyOfRangeGuards { + static int counter = 0; + + public static void main(String[] args) { + Object[] array = new Object[10]; + for (int i = 0; i < 50_000; i++) { + test(array); + } + if (counter != 50_000) { + throw new RuntimeException("Test failed"); + } + } + + static void test(Object[] array) { + try { + Arrays.copyOfRange(array, 15, 20, Object[].class); + } catch (ArrayIndexOutOfBoundsException e) { + // Expected + counter++; + } + } +} diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestObjectArrayClone.java b/test/hotspot/jtreg/compiler/arraycopy/TestObjectArrayClone.java index e4fac6c78df..b7e5b135c64 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/TestObjectArrayClone.java +++ b/test/hotspot/jtreg/compiler/arraycopy/TestObjectArrayClone.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8155643 8268125 8270461 8270098 + * @bug 8155643 8268125 8270461 8270098 8332959 * @summary Test Object.clone() intrinsic. * @modules java.base/java.lang:+open * @@ -41,6 +41,7 @@ * @run main/othervm -Xbatch -XX:-UseTypeProfile * -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone* * -XX:CompileCommand=compileonly,jdk.internal.reflect.GeneratedMethodAccessor*::invoke + * -XX:CompileCommand=compileonly,*::invokeVirtual * compiler.arraycopy.TestObjectArrayClone */ @@ -188,10 +189,18 @@ public static Object testCloneObject(Method clone, Object obj) throws Exception return clone.invoke(obj); } - public static void main(String[] args) throws Exception { + public static Object testCloneObjectWithMethodHandle(MethodHandle clone, Object obj) throws Throwable { + return clone.invokeExact(obj); + } + + public static void main(String[] args) throws Throwable { Method clone = Object.class.getDeclaredMethod("clone"); clone.setAccessible(true); + MethodHandles.Lookup privateLookup = MethodHandles.privateLookupIn(Object.class, MethodHandles.lookup()); + MethodType mt = MethodType.methodType(Object.class); + MethodHandle mh = privateLookup.findVirtual(Object.class, "clone", mt); + String[] arr1 = new String[42]; for (int j = 0; j < arr1.length; j++) { arr1[j] = new String(Integer.toString(j)); @@ -258,6 +267,17 @@ public static void main(String[] args) throws Exception { verifyStr(value, value2); } + for (int i = 0; i < 50_000; i++) { + String[] arr2 = (String[]) testCloneObjectWithMethodHandle(mh, (Object)arr1); + verifyStr(arr1, arr2); + String[] arr3 = (String[]) testCloneObjectWithMethodHandle(mh, (Object)arr1); + verifyStr(arr1, arr3); + String[] arr4 = (String[]) testCloneObjectWithMethodHandle(mh, (Object)arr1); + verifyStr(arr1, arr4); + verifyStr(arr1, arr3); + verifyStr(arr1, arr2); + } + int[] arr2 = new int[42]; for (int i = 0; i < arr2.length; i++) { arr2[i] = i; @@ -320,6 +340,17 @@ public static void main(String[] args) throws Exception { verifyPayload2(p2, p3); verifyPayload2(p1, p3); } + + for (int i = 0; i < 50_000; i++) { + Payload2 p1 = (Payload2) testCloneObjectWithMethodHandle(mh, ref2); + verifyPayload2(ref2, p1); + Payload2 p2 = (Payload2) testCloneObjectWithMethodHandle(mh, ref2); + verifyPayload2(ref2, p2); + Payload2 p3 = (Payload2) testCloneObjectWithMethodHandle(mh, ref2); + verifyPayload2(ref2, p3); + verifyPayload2(p2, p3); + verifyPayload2(p1, p3); + } } public static void verifyPayload(Payload p1, Payload p2) { diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestTailCallInArrayCopyStub.java b/test/hotspot/jtreg/compiler/arraycopy/TestTailCallInArrayCopyStub.java new file mode 100644 index 00000000000..19ea82509bc --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/TestTailCallInArrayCopyStub.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @key stress randomness + * @bug 8329258 + * @summary Test correct execution of the tail call at the end of the arraycopy stub. + * @requires vm.compiler2.enabled + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -Xbatch -XX:-TieredCompilation + * -XX:+StressGCM -XX:+StressLCM + * -XX:CompileCommand=quiet -XX:CompileCommand=compileonly,*::test + * compiler.arraycopy.TestTailCallInArrayCopyStub + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -Xbatch -XX:-TieredCompilation + * -XX:+StressGCM -XX:+StressLCM -XX:StressSeed=75451718 + * -XX:CompileCommand=quiet -XX:CompileCommand=compileonly,*::test + * compiler.arraycopy.TestTailCallInArrayCopyStub + */ + +package compiler.arraycopy; + +public class TestTailCallInArrayCopyStub { + + public static void test(byte[] src, byte[] dst) { + try { + System.arraycopy(src, -1, dst, 0, src.length); + } catch (Exception e) { + // Expected + } + } + + public static void main(String[] args) { + byte[] array = new byte[5]; + for (int i = 0; i < 10_000; ++i) { + test(array, array); + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/TestFoldIfRemovesTopNode.java b/test/hotspot/jtreg/compiler/c2/TestFoldIfRemovesTopNode.java new file mode 100644 index 00000000000..e36897aa7d8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestFoldIfRemovesTopNode.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * 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 8308660 + * @summary C2 compilation hits 'node must be dead' assert + * @requires vm.compiler2.enabled + * @run main/othervm -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:-UseOnStackReplacement + * -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:StressSeed=242006623 TestFoldIfRemovesTopNode + * @run main/othervm -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:-UseOnStackReplacement + * -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN TestFoldIfRemovesTopNode + * + */ + +public class TestFoldIfRemovesTopNode { + + public static void main(String[] args) { + int[] array = new int[100]; + for (int i = 0; i < 20_000; i++) { + test(false, true, 0, array); + test(false, false, 0, array); + testHelper2(false, false, 0, array); + testHelper(0, true, array); + } + } + + private static void test(boolean flag, boolean flag2, int k, int[] array) { + if (flag2) { + testHelper2(flag, flag2, k, array); + } + } + + private static void testHelper2(boolean flag, boolean flag2, int k, int[] array) { + if (flag2) { + k = -1; + } + testHelper(k, flag, array); + } + + private static void testHelper(int k, boolean flag, int[] array) { + if (flag) { + k = new int[k].length; + int j = k + 3; + if (j >= 0 && j <= array.length) { + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/TestUninitializedKlassField.java b/test/hotspot/jtreg/compiler/c2/TestUninitializedKlassField.java index 3bad2bde7b1..63daec895ef 100644 --- a/test/hotspot/jtreg/compiler/c2/TestUninitializedKlassField.java +++ b/test/hotspot/jtreg/compiler/c2/TestUninitializedKlassField.java @@ -4,9 +4,7 @@ * * 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. + * 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 diff --git a/test/hotspot/jtreg/compiler/c2/cr7200264/TestDriver.java b/test/hotspot/jtreg/compiler/c2/cr7200264/TestDriver.java deleted file mode 100644 index 9975fd7511c..00000000000 --- a/test/hotspot/jtreg/compiler/c2/cr7200264/TestDriver.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package compiler.c2.cr7200264; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import jdk.test.lib.Asserts; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; - -public class TestDriver { - private final Map expectedVectorizationNumbers - = new HashMap<>(); - - public void addExpectedVectorization(String v, long num) { - expectedVectorizationNumbers.put(v, num); - } - - public void run() throws Throwable { - verifyVectorizationNumber(executeApplication()); - } - - private List executeApplication() throws Throwable { - OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava( - "-Xbatch", - "-XX:-TieredCompilation", - "-XX:+PrintCompilation", - "-XX:+TraceNewVectors", - "-XX:+IgnoreUnrecognizedVMOptions", - "-XX:StressLongCountedLoop=0", // make sure int loops do not get converted to long - TestIntVect.class.getName()); - outputAnalyzer.shouldHaveExitValue(0); - return outputAnalyzer.asLines(); - } - - private void verifyVectorizationNumber(List vectorizationLog) { - for (Map.Entry entry : expectedVectorizationNumbers.entrySet()) { - String v = entry.getKey(); - long actualNum = vectorizationLog.stream() - .filter(s -> s.contains(v)).count(); - long expectedNum = entry.getValue(); - Asserts.assertGTE(actualNum, expectedNum, - "Unexpected " + entry.getKey() + " number"); - } - } -} diff --git a/test/hotspot/jtreg/compiler/c2/cr7200264/TestIntVect.java b/test/hotspot/jtreg/compiler/c2/cr7200264/TestIntVect.java index 51226a8576e..d39c195b55f 100644 --- a/test/hotspot/jtreg/compiler/c2/cr7200264/TestIntVect.java +++ b/test/hotspot/jtreg/compiler/c2/cr7200264/TestIntVect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,622 +21,870 @@ * questions. */ +/** + * @test + * @bug 7200264 + * @summary 7192963 changes disabled shift vectors + * @library /test/lib / + * @run driver compiler.c2.cr7200264.TestIntVect + */ + package compiler.c2.cr7200264; + +import compiler.lib.ir_framework.*; + /* - * Copy of test/compiler/6340864/TestIntVect.java without performance tests. + * Based on test/hotspot/jtreg/compiler/c2/cr6340864/TestIntVect.java without performance tests. */ public class TestIntVect { - private static final int ARRLEN = 997; - private static final int ITERS = 11000; - private static final int ADD_INIT = Integer.MAX_VALUE-500; - private static final int BIT_MASK = 0xEC80F731; - private static final int VALUE = 15; - private static final int SHIFT = 32; - - public static void main(String args[]) { - System.out.println("Testing Integer vectors"); - int errn = test(); - if (errn > 0) { - System.err.println("FAILED: " + errn + " errors"); - System.exit(97); - } - System.out.println("PASSED"); - } - - static int test() { - int[] a0 = new int[ARRLEN]; - int[] a1 = new int[ARRLEN]; - int[] a2 = new int[ARRLEN]; - int[] a3 = new int[ARRLEN]; - int[] a4 = new int[ARRLEN]; - long[] p2 = new long[ARRLEN/2]; - // Initialize - int gold_sum = 0; - for (int i=0; i>>VALUE)); - } - test_srlv(a0, a1, VALUE); - for (int i=0; i>>VALUE)); - } - - test_srac(a0, a1); - for (int i=0; i>VALUE)); - } - test_srav(a0, a1, VALUE); - for (int i=0; i>VALUE)); - } - - test_sllc_n(a0, a1); - for (int i=0; i>>(-VALUE))); - } - test_srlv(a0, a1, -VALUE); - for (int i=0; i>>(-VALUE))); - } - - test_srac_n(a0, a1); - for (int i=0; i>(-VALUE))); - } - test_srav(a0, a1, -VALUE); - for (int i=0; i>(-VALUE))); - } - - test_sllc_o(a0, a1); - for (int i=0; i>>SHIFT)); - } - test_srlv(a0, a1, SHIFT); - for (int i=0; i>>SHIFT)); - } - - test_srac_o(a0, a1); - for (int i=0; i>SHIFT)); - } - test_srav(a0, a1, SHIFT); - for (int i=0; i>SHIFT)); - } - - test_sllc_on(a0, a1); - for (int i=0; i>>(-SHIFT))); - } - test_srlv(a0, a1, -SHIFT); - for (int i=0; i>>(-SHIFT))); - } - - test_srac_on(a0, a1); - for (int i=0; i>(-SHIFT))); - } - test_srav(a0, a1, -SHIFT); - for (int i=0; i>(-SHIFT))); - } - - test_pack2(p2, a1); - for (int i=0; i>>VALUE)); + } + test_srlv(a0, a1, VALUE); + for (int i=0; i>>VALUE)); + } + + test_srac(a0, a1); + for (int i=0; i>VALUE)); + } + test_srav(a0, a1, VALUE); + for (int i=0; i>VALUE)); + } + + test_sllc_n(a0, a1); + for (int i=0; i>>(-VALUE))); + } + test_srlv(a0, a1, -VALUE); + for (int i=0; i>>(-VALUE))); + } + + test_srac_n(a0, a1); + for (int i=0; i>(-VALUE))); + } + test_srav(a0, a1, -VALUE); + for (int i=0; i>(-VALUE))); + } + + test_sllc_o(a0, a1); + for (int i=0; i>>SHIFT)); + } + test_srlv(a0, a1, SHIFT); + for (int i=0; i>>SHIFT)); + } + + test_srac_o(a0, a1); + for (int i=0; i>SHIFT)); + } + test_srav(a0, a1, SHIFT); + for (int i=0; i>SHIFT)); + } + + test_sllc_on(a0, a1); + for (int i=0; i>>(-SHIFT))); + } + test_srlv(a0, a1, -SHIFT); + for (int i=0; i>>(-SHIFT))); + } + + test_srac_on(a0, a1); + for (int i=0; i>(-SHIFT))); + } + test_srav(a0, a1, -SHIFT); + for (int i=0; i>(-SHIFT))); + } + + test_pack2(p2, a1); + for (int i=0; i 0) { + throw new Error("FAILED: " + errn + " errors"); + } + System.out.println("PASSED"); + + } + + // Not vectorized: simple addition not profitable, see JDK-8307516. NOTE: + // This check does not document the _desired_ behavior of the system but + // the current behavior (no vectorization) + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0" }) + int test_sum(int[] a1) { + int sum = 0; + for (int i = 0; i < a1.length; i+=1) { + sum += a1[i]; + } + return sum; + } + + @Test + @IR(counts = { IRNode.ADD_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_addc(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]+VALUE); + } + } + + @Test + @IR(counts = { IRNode.ADD_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_addv(int[] a0, int[] a1, int b) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]+b); + } + } + + @Test + @IR(counts = { IRNode.ADD_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_adda(int[] a0, int[] a1, int[] a2) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]+a2[i]); + } + } + + @Test + @IR(counts = { IRNode.ADD_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_subc(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]-VALUE); + } + } + + @Test + @IR(counts = { IRNode.SUB_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_subv(int[] a0, int[] a1, int b) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]-b); + } + } + + @Test + @IR(counts = { IRNode.SUB_VI, "> 0", }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_suba(int[] a0, int[] a1, int[] a2) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]-a2[i]); + } + } + + @Test + @IR(counts = { IRNode.SUB_VI, "> 0", IRNode.LSHIFT_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_mulc(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]*VALUE); + } + } + + @Test + @IR(counts = { IRNode.SUB_VI, "> 0", IRNode.LSHIFT_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_mulc_n(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]*(-VALUE)); + } + } + + @Test + @IR(counts = { IRNode.MUL_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + void test_mulv(int[] a0, int[] a1, int b) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]*b); + } + } + + @Test + @IR(counts = { IRNode.MUL_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse4.1", "true", "asimd", "true"}) + void test_mula(int[] a0, int[] a1, int[] a2) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]*a2[i]); + } + } + + @Test + @IR(counts = { IRNode.ADD_VI, + IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.RSHIFT_VI, + IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.SUB_VI, + IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0" }, + applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + // Not vectorized: On aarch64, vectorization for this example results in + // MulVL nodes, which asimd does not support. + @IR(counts = { IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0", + IRNode.MUL_L, "> 0" }, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + void test_divc(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]/VALUE); + } + } + + @Test + @IR(counts = { IRNode.ADD_VI, + IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.RSHIFT_VI, + IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.SUB_VI, + IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0" }, + applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + // Not vectorized: On aarch64, vectorization for this example results in + // MulVL nodes, which asimd does not support. + @IR(counts = { IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0", + IRNode.MUL_L, "> 0" }, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) + void test_divc_n(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]/(-VALUE)); + } + } + + // Not vectorized: no vector div. NOTE: This check does not document the + // _desired_ behavior of the system but the current behavior (no + // vectorization) + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0" }) + void test_divv(int[] a0, int[] a1, int b) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]/b); + } + } + + // Not vectorized: no vector div. NOTE: This check does not document the + // _desired_ behavior of the system but the current behavior (no + // vectorization) + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0" }) + void test_diva(int[] a0, int[] a1, int[] a2) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]/a2[i]); + } + } + + @Test + @IR(counts = { IRNode.AND_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_andc(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]&BIT_MASK); + } + } + + @Test + @IR(counts = { IRNode.AND_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_andv(int[] a0, int[] a1, int b) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]&b); + } + } + + @Test + @IR(counts = { IRNode.AND_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_anda(int[] a0, int[] a1, int[] a2) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]&a2[i]); + } + } + + @Test + @IR(counts = { IRNode.OR_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_orc(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]|BIT_MASK); + } + } + + @Test + @IR(counts = { IRNode.OR_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_orv(int[] a0, int[] a1, int b) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]|b); + } + } + + @Test + @IR(counts = { IRNode.OR_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_ora(int[] a0, int[] a1, int[] a2) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]|a2[i]); + } + } + + @Test + @IR(counts = { IRNode.XOR_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_xorc(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]^BIT_MASK); + } + } + + @Test + @IR(counts = { IRNode.XOR_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_xorv(int[] a0, int[] a1, int b) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]^b); + } + } + + @Test + @IR(counts = { IRNode.XOR_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_xora(int[] a0, int[] a1, int[] a2) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]^a2[i]); + } + } + + @Test + @IR(counts = { IRNode.LSHIFT_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_sllc(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]< 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_sllc_n(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]<<(-VALUE)); + } + } + + // Vector shift not expected as shift is a NOP. + @Test + @IR(counts = { IRNode.LSHIFT_VI, "= 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_sllc_o(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]< 0", + IRNode.STORE_VECTOR, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_sllc_on(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]<<(-SHIFT)); + } + } + + @Test + @IR(counts = { IRNode.LSHIFT_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_sllv(int[] a0, int[] a1, int b) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]< 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_srlc(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]>>>VALUE); + } + } + + @Test + @IR(counts = { IRNode.URSHIFT_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_srlc_n(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]>>>(-VALUE)); + } + } + + // Vector shift not expected as shift is a NOP. + @Test + @IR(counts = { IRNode.URSHIFT_VI, "= 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_srlc_o(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]>>>SHIFT); + } + } + + // Vector shift not expected as shift is a NOP. + @Test + @IR(counts = { IRNode.URSHIFT_VI, "= 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_srlc_on(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]>>>(-SHIFT)); + } + } + + @Test + @IR(counts = { IRNode.URSHIFT_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_srlv(int[] a0, int[] a1, int b) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]>>>b); + } + } + + @Test + @IR(counts = { IRNode.RSHIFT_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_srac(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]>>VALUE); + } + } + + @Test + @IR(counts = { IRNode.RSHIFT_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_srac_n(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]>>(-VALUE)); + } + } + + // Vector shift not expected as shift is a NOP. + @Test + @IR(counts = { IRNode.RSHIFT_VI, "= 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_srac_o(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]>>SHIFT); + } + } + + // Vector shift not expected as shift is a NOP. + @Test + @IR(counts = { IRNode.RSHIFT_VI, "= 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_srac_on(int[] a0, int[] a1) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]>>(-SHIFT)); + } + } + + @Test + @IR(counts = { IRNode.RSHIFT_VI, "> 0" }, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + void test_srav(int[] a0, int[] a1, int b) { + for (int i = 0; i < a0.length; i+=1) { + a0[i] = (int)(a1[i]>>b); + } + } + + // Not vectorized currently. NOTE: This check does not document the + // _desired_ behavior of the system but the current behavior (no + // vectorization) + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0" }) + void test_pack2(long[] p2, int[] a1) { + if (p2.length*2 > a1.length) return; + for (int i = 0; i < p2.length; i+=1) { + long l0 = (long)a1[i*2+0]; + long l1 = (long)a1[i*2+1]; + p2[i] = (l1 << 32) | (l0 & 0xFFFFFFFFl); + } + } + + // Not vectorized currently. NOTE: This check does not document the + // _desired_ behavior of the system but the current behavior (no + // vectorization) + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0" }) + void test_unpack2(int[] a0, long[] p2) { + if (p2.length*2 > a0.length) return; + for (int i = 0; i < p2.length; i+=1) { + long l = p2[i]; + a0[i*2+0] = (int)(l & 0xFFFFFFFFl); + a0[i*2+1] = (int)(l >> 32); + } + } + + // Not vectorized currently. NOTE: This check does not document the + // _desired_ behavior of the system but the current behavior (no + // vectorization) + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0" }) + void test_pack2_swap(long[] p2, int[] a1) { + if (p2.length*2 > a1.length) return; + for (int i = 0; i < p2.length; i+=1) { + long l0 = (long)a1[i*2+0]; + long l1 = (long)a1[i*2+1]; + p2[i] = (l0 << 32) | (l1 & 0xFFFFFFFFl); + } + } + + // Not vectorized currently. NOTE: This check does not document the + // _desired_ behavior of the system but the current behavior (no + // vectorization) + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, "= 0", + IRNode.STORE_VECTOR, "= 0" }) + void test_unpack2_swap(int[] a0, long[] p2) { + if (p2.length*2 > a0.length) return; + for (int i = 0; i < p2.length; i+=1) { + long l = p2[i]; + a0[i*2+0] = (int)(l >> 32); + a0[i*2+1] = (int)(l & 0xFFFFFFFFl); + } + } + + static int verify(String text, int i, int elem, int val) { + if (elem != val) { + System.err.println(text + "[" + i + "] = " + elem + " != " + val); + return 1; + } + return 0; + } + + static int verify(String text, int i, long elem, long val) { + if (elem != val) { + System.err.println(text + "[" + i + "] = " + Long.toHexString(elem) + " != " + Long.toHexString(val)); + return 1; + } + return 0; } - } - - static void test_orc(int[] a0, int[] a1) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]|BIT_MASK); - } - } - static void test_orv(int[] a0, int[] a1, int b) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]|b); - } - } - static void test_ora(int[] a0, int[] a1, int[] a2) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]|a2[i]); - } - } - - static void test_xorc(int[] a0, int[] a1) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]^BIT_MASK); - } - } - static void test_xorv(int[] a0, int[] a1, int b) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]^b); - } - } - static void test_xora(int[] a0, int[] a1, int[] a2) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]^a2[i]); - } - } - - static void test_sllc(int[] a0, int[] a1) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]<>>VALUE); - } - } - static void test_srlc_n(int[] a0, int[] a1) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]>>>(-VALUE)); - } - } - static void test_srlc_o(int[] a0, int[] a1) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]>>>SHIFT); - } - } - static void test_srlc_on(int[] a0, int[] a1) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]>>>(-SHIFT)); - } - } - static void test_srlv(int[] a0, int[] a1, int b) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]>>>b); - } - } - - static void test_srac(int[] a0, int[] a1) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]>>VALUE); - } - } - static void test_srac_n(int[] a0, int[] a1) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]>>(-VALUE)); - } - } - static void test_srac_o(int[] a0, int[] a1) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]>>SHIFT); - } - } - static void test_srac_on(int[] a0, int[] a1) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]>>(-SHIFT)); - } - } - static void test_srav(int[] a0, int[] a1, int b) { - for (int i = 0; i < a0.length; i+=1) { - a0[i] = (int)(a1[i]>>b); - } - } - - static void test_pack2(long[] p2, int[] a1) { - if (p2.length*2 > a1.length) return; - for (int i = 0; i < p2.length; i+=1) { - long l0 = (long)a1[i*2+0]; - long l1 = (long)a1[i*2+1]; - p2[i] = (l1 << 32) | (l0 & 0xFFFFFFFFl); - } - } - static void test_unpack2(int[] a0, long[] p2) { - if (p2.length*2 > a0.length) return; - for (int i = 0; i < p2.length; i+=1) { - long l = p2[i]; - a0[i*2+0] = (int)(l & 0xFFFFFFFFl); - a0[i*2+1] = (int)(l >> 32); - } - } - static void test_pack2_swap(long[] p2, int[] a1) { - if (p2.length*2 > a1.length) return; - for (int i = 0; i < p2.length; i+=1) { - long l0 = (long)a1[i*2+0]; - long l1 = (long)a1[i*2+1]; - p2[i] = (l0 << 32) | (l1 & 0xFFFFFFFFl); - } - } - static void test_unpack2_swap(int[] a0, long[] p2) { - if (p2.length*2 > a0.length) return; - for (int i = 0; i < p2.length; i+=1) { - long l = p2[i]; - a0[i*2+0] = (int)(l >> 32); - a0[i*2+1] = (int)(l & 0xFFFFFFFFl); - } - } - - static int verify(String text, int i, int elem, int val) { - if (elem != val) { - System.err.println(text + "[" + i + "] = " + elem + " != " + val); - return 1; - } - return 0; - } - - static int verify(String text, int i, long elem, long val) { - if (elem != val) { - System.err.println(text + "[" + i + "] = " + Long.toHexString(elem) + " != " + Long.toHexString(val)); - return 1; - } - return 0; - } } diff --git a/test/hotspot/jtreg/compiler/c2/cr7200264/TestSSE2IntVect.java b/test/hotspot/jtreg/compiler/c2/cr7200264/TestSSE2IntVect.java deleted file mode 100644 index c78e2cd398b..00000000000 --- a/test/hotspot/jtreg/compiler/c2/cr7200264/TestSSE2IntVect.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @bug 7200264 - * @summary 7192963 changes disabled shift vectors - * @requires vm.cpu.features ~= ".*sse2.*" & vm.debug & vm.flavor == "server" - * @requires !vm.emulatedClient & !vm.graal.enabled - * @library /test/lib / - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:StressLongCountedLoop=0 - * compiler.c2.cr7200264.TestSSE2IntVect - */ - -package compiler.c2.cr7200264; - -public class TestSSE2IntVect { - public static void main(String[] args) throws Throwable { - TestDriver test = new TestDriver(); - test.addExpectedVectorization("AddVI", 4); - test.addExpectedVectorization("SubVI", 4); - test.addExpectedVectorization("AndV", 3); - test.addExpectedVectorization("OrV", 3); - test.addExpectedVectorization("XorV", 3); - test.addExpectedVectorization("LShiftVI", 5); - test.addExpectedVectorization("RShiftVI", 3); - test.addExpectedVectorization("URShiftVI", 3); - test.run(); - } -} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIterativeEA.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIterativeEA.java index 1bfaebabec8..0229fdc3038 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestIterativeEA.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIterativeEA.java @@ -78,7 +78,7 @@ public GenericHolder(Object obj) { } @Test - @Arguments({ Argument.RANDOM_EACH }) + @Arguments(values = { Argument.RANDOM_EACH }) @IR(failOn = { IRNode.ALLOC }) public static int testSlow(int val) { MyClass obj = new MyClass(val); @@ -88,7 +88,7 @@ public static int testSlow(int val) { } @Test - @Arguments({ Argument.RANDOM_EACH }) + @Arguments(values = { Argument.RANDOM_EACH }) @IR(failOn = { IRNode.ALLOC }) public static int testFast(int val) { MyClass obj = new MyClass(val); @@ -119,7 +119,7 @@ public C(B b) { } @Test - @Arguments({ Argument.RANDOM_EACH }) + @Arguments(values = { Argument.RANDOM_EACH }) @IR(failOn = { IRNode.ALLOC }) static int testNested(int i) { C c = new C(new B(new A(i))); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestOptimizeUnstableIf.java b/test/hotspot/jtreg/compiler/c2/irTests/TestOptimizeUnstableIf.java index ea64b43908a..2b4fab4a521 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestOptimizeUnstableIf.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestOptimizeUnstableIf.java @@ -41,7 +41,7 @@ public static void main(String[] args) { } @Test - @Arguments({Argument.MAX}) // the argument needs to be big enough to fall out of cache. + @Arguments(values = {Argument.MAX}) // the argument needs to be big enough to fall out of cache. @IR(failOn = {IRNode.ALLOC_OF, "Integer"}) public static int boxing_object(int value) { Integer ii = Integer.valueOf(value); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestRemixAddressExpressions.java b/test/hotspot/jtreg/compiler/c2/irTests/TestRemixAddressExpressions.java index f35b9273a56..a02372e5e67 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestRemixAddressExpressions.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestRemixAddressExpressions.java @@ -40,7 +40,7 @@ public static void main(String[] args) { @Test @IR(counts = { IRNode.ADD_I, "1", IRNode.LSHIFT_I, "2" }) - @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) public static float invPlusVarLshiftInt(int inv, int scale) { float res = 0; for (int i = 1; i < 100; i *= 11) { @@ -51,7 +51,7 @@ public static float invPlusVarLshiftInt(int inv, int scale) { @Test @IR(counts = { IRNode.ADD_L, "1", IRNode.LSHIFT_L, "2" }) - @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) public static float invPlusVarLshiftLong(long inv, int scale) { float res = 0; for (long i = 1; i < 100; i *= 11) { @@ -62,7 +62,7 @@ public static float invPlusVarLshiftLong(long inv, int scale) { @Test @IR(counts = { IRNode.ADD_I, "1", IRNode.SUB_I, "1", IRNode.LSHIFT_I, "2" }) - @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) public static float invMinusVarLshiftInt(int inv, int scale) { float res = 0; for (int i = 1; i < 100; i *= 11) { @@ -73,7 +73,7 @@ public static float invMinusVarLshiftInt(int inv, int scale) { @Test @IR(counts = { IRNode.ADD_L, "1", IRNode.SUB_L, "1", IRNode.LSHIFT_L, "2" }) - @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) public static float invMinusVarLshiftLong(long inv, int scale) { float res = 0; for (long i = 1; i < 100; i *= 11) { @@ -84,7 +84,7 @@ public static float invMinusVarLshiftLong(long inv, int scale) { @Test @IR(counts = { IRNode.ADD_I, "1", IRNode.SUB_I, "1", IRNode.LSHIFT_I, "2" }) - @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) public static float varMinusInvLshiftInt(int inv, int scale) { float res = 0; for (int i = 1; i < 100; i *= 11) { @@ -95,7 +95,7 @@ public static float varMinusInvLshiftInt(int inv, int scale) { @Test @IR(counts = { IRNode.ADD_L, "1", IRNode.SUB_L, "1", IRNode.LSHIFT_L, "2" }) - @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) public static float varMinusInvLshiftLong(long inv, int scale) { float res = 0; for (long i = 1; i < 100; i *= 11) { diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java b/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java index 523b31711f0..4396873425a 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java @@ -44,7 +44,7 @@ public static void main(String[] args) { } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) @IR(failOn = { IRNode.AND_I, IRNode.LSHIFT_I }) public static int shiftMaskInt(int i) { return (i << 2) & 3; // transformed to: return 0; @@ -58,7 +58,7 @@ public static void checkShiftMaskInt(int res) { } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) @IR(failOn = { IRNode.AND_L, IRNode.LSHIFT_L }) public static long shiftMaskLong(long i) { return (i << 2) & 3; // transformed to: return 0; @@ -75,7 +75,7 @@ public static void checkShiftMaskLong(long res) { static volatile int barrier; @Test - @Arguments({Argument.RANDOM_EACH, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) @IR(failOn = { IRNode.AND_I, IRNode.LSHIFT_I }) public static int shiftNonConstMaskInt(int i, boolean flag) { int mask; @@ -96,7 +96,7 @@ public static void checkShiftNonConstMaskInt(int res) { } @Test - @Arguments({Argument.RANDOM_EACH, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) @IR(failOn = { IRNode.AND_L, IRNode.LSHIFT_L }) public static long shiftNonConstMaskLong(long i, boolean flag) { long mask; @@ -207,7 +207,7 @@ public static void addSshiftNonConstMaskLong_runner() { } @Test - @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) @IR(failOn = { IRNode.AND_I, IRNode.ADD_I, IRNode.LSHIFT_I }) public static int addShiftMaskInt2(int i, int j) { return ((j << 2) + (i << 2)) & 3; // transformed to: return 0; @@ -221,7 +221,7 @@ public static void checkAddShiftMaskInt2(int res) { } @Test - @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) @IR(failOn = { IRNode.AND_L, IRNode.ADD_L, IRNode.LSHIFT_L }) public static long addShiftMaskLong2(long i, long j) { return ((j << 2) + (i << 2)) & 3; // transformed to: return 0; @@ -274,7 +274,7 @@ public static void addShiftMaskLong3_runner() { } @Test - @Arguments({Argument.RANDOM_EACH}) + @Arguments(values = {Argument.RANDOM_EACH}) @IR(failOn = { IRNode.AND_L, IRNode.LSHIFT_I, IRNode.CONV_I2L }) public static long shiftConvMask(int i) { return ((long)(i << 2)) & 3; // transformed to: return 0; @@ -288,7 +288,7 @@ public static void checkShiftConvMask(long res) { } @Test - @Arguments({Argument.RANDOM_EACH, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) @IR(failOn = { IRNode.AND_L, IRNode.LSHIFT_I, IRNode.CONV_I2L }) public static long shiftNotConstConvMask(int i, boolean flag) { long mask; @@ -326,7 +326,7 @@ public static void addShiftConvMask_runner() { } @Test - @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) @IR(failOn = { IRNode.AND_L, IRNode.ADD_L, IRNode.LSHIFT_I, IRNode.CONV_I2L }) public static long addShiftConvMask2(int i, int j) { return (((long)(j << 2)) + ((long)(i << 2))) & 3; // transformed to: return 0; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestSpecialCasesOf_AMinusB_Plus_CMinusD_InAddIdeal.java b/test/hotspot/jtreg/compiler/c2/irTests/TestSpecialCasesOf_AMinusB_Plus_CMinusD_InAddIdeal.java index 4cbbcd93301..3728caa0b6b 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestSpecialCasesOf_AMinusB_Plus_CMinusD_InAddIdeal.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestSpecialCasesOf_AMinusB_Plus_CMinusD_InAddIdeal.java @@ -43,7 +43,7 @@ public static void main(String[] args) { } @Test - @Arguments({Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) + @Arguments(values = {Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) @IR(failOn = {IRNode.ADD_I}) @IR(counts = {IRNode.SUB_I, "1"}) public int test1Int(int a, int b, int c) { @@ -51,7 +51,7 @@ public int test1Int(int a, int b, int c) { } @Test - @Arguments({Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) + @Arguments(values = {Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) @IR(failOn = {IRNode.ADD_L}) @IR(counts = {IRNode.SUB_L, "1"}) public long test1Long(long a, long b, long c) { @@ -59,7 +59,7 @@ public long test1Long(long a, long b, long c) { } @Test - @Arguments({Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) + @Arguments(values = {Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) @IR(failOn = {IRNode.ADD_I}) @IR(counts = {IRNode.SUB_I, "1"}) public int test2Int(int b, int a, int c) { // make sure inputs sorted @@ -67,7 +67,7 @@ public int test2Int(int b, int a, int c) { // make sure inputs sorted } @Test - @Arguments({Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) + @Arguments(values = {Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) @IR(failOn = {IRNode.ADD_L}) @IR(counts = {IRNode.SUB_L, "1"}) public long test2Long(long b, long a, long c) { // make sure inputs sorted diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeTypeConversion.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeTypeConversion.java index 67c26ecbddf..899be4bbc9c 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeTypeConversion.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeTypeConversion.java @@ -58,10 +58,7 @@ public static void main(String[] args) { // Mixing types of different sizes has the effect that some vectors are shorter than the type allows. @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "min(max_int, max_double)", ">0", IRNode.VECTOR_CAST_I2D, IRNode.VECTOR_SIZE + "min(max_int, max_double)", ">0", - IRNode.STORE_VECTOR, ">0"}, - // The vectorization of some conversions may fail when `+AlignVector`. - // We can remove the condition after JDK-8303827. - applyIf = {"AlignVector", "false"}) + IRNode.STORE_VECTOR, ">0"}) private static void testConvI2D(double[] d, int[] a) { for(int i = 0; i < d.length; i++) { d[i] = (double) (a[i]); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestIntegerMulRing.java b/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestIntegerMulRing.java index 44c494ce448..bd7600d5503 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestIntegerMulRing.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestIntegerMulRing.java @@ -114,7 +114,7 @@ public static void testLongNegative2() { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_L, "1"}) public static void testLongMinValueMinus1(boolean flag, boolean flag2) { long l = flag ? -1 : Long.MIN_VALUE; @@ -129,7 +129,7 @@ public static void testLongMinValueMinus1(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = {IRNode.MUL_L, IRNode.STORE_L}, counts = {IRNode.STORE_I, "1"}) public static void testLongMinValuePlus1(boolean flag, boolean flag2) { long l = flag ? -1 : Long.MIN_VALUE; @@ -144,7 +144,7 @@ public static void testLongMinValuePlus1(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = {IRNode.MUL_L, IRNode.STORE_L, IRNode.LSHIFT}, counts = {IRNode.STORE_I, "1"}) public static void testLongMinValueUnderflowOnce(boolean flag, boolean flag2) { long l = flag ? Long.MIN_VALUE/2 : Long.MIN_VALUE/2 + 1; @@ -159,7 +159,7 @@ public static void testLongMinValueUnderflowOnce(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_I, "1", IRNode.STORE_L, "1", IRNode.MUL_L, "1"}) public static void testLongMinValueUnderflowOnceTwice(boolean flag, boolean flag2) { long l = flag ? Long.MIN_VALUE/2 : Long.MIN_VALUE/2 + 1; @@ -174,7 +174,7 @@ public static void testLongMinValueUnderflowOnceTwice(boolean flag, boolean flag @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = {IRNode.MUL_L, IRNode.STORE_L, IRNode.LSHIFT}, counts = {IRNode.STORE_I, "1"}) public static void testLongMinValueUnderflowTwice(boolean flag, boolean flag2) { long l = flag ? Long.MIN_VALUE/2 : Long.MIN_VALUE/2 + 1; @@ -189,7 +189,7 @@ public static void testLongMinValueUnderflowTwice(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = {IRNode.MUL_L, IRNode.STORE_L, IRNode.LSHIFT}, counts = {IRNode.STORE_I, "1"}) public static void testLongMaxValueOverflowOnce(boolean flag, boolean flag2) { long l = flag2 ? Long.MAX_VALUE/2 - 1 : Long.MAX_VALUE/2; @@ -204,7 +204,7 @@ public static void testLongMaxValueOverflowOnce(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_I, "1", IRNode.STORE_L, "1", IRNode.MUL_L, "1"}) public static void testLongMaxValueOverflowOnceTwice(boolean flag, boolean flag2) { long l = flag2 ? Long.MAX_VALUE/2 - 1 : Long.MAX_VALUE/2; @@ -219,7 +219,7 @@ public static void testLongMaxValueOverflowOnceTwice(boolean flag, boolean flag2 @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = {IRNode.MUL_L, IRNode.STORE_L, IRNode.LSHIFT}, counts = {IRNode.STORE_I, "1"}) public static void testLongMaxValueOverflowTwice(boolean flag, boolean flag2) { long l = flag2 ? Long.MAX_VALUE/2 - 1 : Long.MAX_VALUE/2; @@ -234,7 +234,7 @@ public static void testLongMaxValueOverflowTwice(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = IRNode.MUL_L, counts = {IRNode.STORE_L, "1"}) public static void testLongProductsOverflowOnceAtMin(boolean flag, boolean flag2) { long l = flag ? Long.MAX_VALUE/2 + 1 : Long.MAX_VALUE/2 + 2; @@ -251,7 +251,7 @@ public static void testLongProductsOverflowOnceAtMin(boolean flag, boolean flag2 @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = IRNode.MUL_L, counts = {IRNode.STORE_L, "1"}) public static void testLongProductsOverflowOnceAtMax(boolean flag, boolean flag2) { // 88971434439113593 * 311 = Long.MAX_VALUE*3 + 2 --cast to long--> Long.MAX_VALUE @@ -269,7 +269,7 @@ public static void testLongProductsOverflowOnceAtMax(boolean flag, boolean flag2 @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = IRNode.MUL_L, counts = {IRNode.STORE_L, "1"}) public static void testLongProductsUnderflowOnceAtMin(boolean flag, boolean flag2) { long l = flag ? Long.MIN_VALUE/3 - 1 : Long.MIN_VALUE/3 - 2; @@ -286,7 +286,7 @@ public static void testLongProductsUnderflowOnceAtMin(boolean flag, boolean flag @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = IRNode.MUL_L, counts = {IRNode.STORE_L, "1"}) public static void testLongProductsUnderflowOnceAtMax(boolean flag, boolean flag2) { // -6917529027641081856 * 4 = Long.MIN_VALUE*3 --cast to long--> Long.MIN_VALUE @@ -304,7 +304,7 @@ public static void testLongProductsUnderflowOnceAtMax(boolean flag, boolean flag @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_L, "1"}) public static void testLongProductsDifferentNumberOfOverflow(boolean flag, boolean flag2) { // 88971434439113593 * 311 = Long.MAX_VALUE*3 + 2 --cast to long--> Long.MAX_VALUE // Overflown once @@ -322,7 +322,7 @@ public static void testLongProductsDifferentNumberOfOverflow(boolean flag, boole @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_L, "1"}) public static void testLongProductsDifferentNumberOfUnderflows(boolean flag, boolean flag2) { // -6917529027641081856 * 4 = Long.MIN_VALUE*3 --cast to long--> Long.MIN_VALUE // Underflown once @@ -340,7 +340,7 @@ public static void testLongProductsDifferentNumberOfUnderflows(boolean flag, boo @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_L, "1"}) public static void testLongNotSameOverflow1(boolean flag, boolean flag2) { long l = flag ? 1 : Long.MAX_VALUE; @@ -355,7 +355,7 @@ public static void testLongNotSameOverflow1(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_L, "1"}) public static void testLongNotSameOverflow2(boolean flag, boolean flag2) { long l = flag ? 1 : Long.MIN_VALUE; @@ -370,7 +370,7 @@ public static void testLongNotSameOverflow2(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_L, "1"}) public static void testLongNotSameOverflow3(boolean flag, boolean flag2) { long l = flag ? -1 : Long.MIN_VALUE; @@ -385,7 +385,7 @@ public static void testLongNotSameOverflow3(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_L, "1"}) public static void testLongNotSameOverflow4(boolean flag, boolean flag2) { long l = flag ? -1 : Long.MAX_VALUE; @@ -400,7 +400,7 @@ public static void testLongNotSameOverflow4(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_L, "1"}) public static void testLongNotSameOverflow5(boolean flag, boolean flag2) { long l = flag ? Long.MIN_VALUE : Long.MAX_VALUE; @@ -492,7 +492,7 @@ public static void testIntNegative2() { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_I, "1"}) public static void testIntMinValueMinus1(boolean flag, boolean flag2) { int l = flag ? -1 : Integer.MIN_VALUE; @@ -508,7 +508,7 @@ public static void testIntMinValueMinus1(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = {IRNode.MUL_I, IRNode.STORE_L}, counts = {IRNode.STORE_I, "1"}) public static void testIntMinValuePlus1(boolean flag, boolean flag2) { int l = flag ? -1 : Integer.MIN_VALUE; @@ -523,7 +523,7 @@ public static void testIntMinValuePlus1(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = {IRNode.MUL_I, IRNode.STORE_L, IRNode.LSHIFT}, counts = {IRNode.STORE_I, "1"}) public static void testIntMinValueUnderflowOnce(boolean flag, boolean flag2) { int l = flag ? Integer.MIN_VALUE/2 : Integer.MIN_VALUE/2 + 1; @@ -538,7 +538,7 @@ public static void testIntMinValueUnderflowOnce(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_I, "1", IRNode.STORE_L, "1", IRNode.MUL_I, "1"}) public static void testIntMinValueUnderflowOnceTwice(boolean flag, boolean flag2) { int l = flag ? Integer.MIN_VALUE/2 : Integer.MIN_VALUE/2 + 1; @@ -553,7 +553,7 @@ public static void testIntMinValueUnderflowOnceTwice(boolean flag, boolean flag2 @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = {IRNode.MUL_I, IRNode.STORE_L, IRNode.LSHIFT}, counts = {IRNode.STORE_I, "1"}) public static void testIntMinValueUnderflowTwice(boolean flag, boolean flag2) { int l = flag ? Integer.MIN_VALUE/2 : Integer.MIN_VALUE/2 + 1; @@ -568,7 +568,7 @@ public static void testIntMinValueUnderflowTwice(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = {IRNode.MUL_I, IRNode.STORE_L, IRNode.LSHIFT}, counts = {IRNode.STORE_I, "1"}) public static void testIntMaxValueOverflowOnce(boolean flag, boolean flag2) { int l = flag2 ? Integer.MAX_VALUE/2 - 1 : Integer.MAX_VALUE/2; @@ -583,7 +583,7 @@ public static void testIntMaxValueOverflowOnce(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_I, "1", IRNode.STORE_L, "1", IRNode.MUL_I, "1"}) public static void testIntMaxValueOverflowOnceTwice(boolean flag, boolean flag2) { int l = flag2 ? Integer.MAX_VALUE/2 - 1 : Integer.MAX_VALUE/2; @@ -598,7 +598,7 @@ public static void testIntMaxValueOverflowOnceTwice(boolean flag, boolean flag2) @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = {IRNode.MUL_I, IRNode.STORE_L, IRNode.LSHIFT}, counts = {IRNode.STORE_I, "1"}) public static void testIntMaxValueOverflowTwice(boolean flag, boolean flag2) { int l = flag2 ? Integer.MAX_VALUE/2 - 1 : Integer.MAX_VALUE/2; @@ -613,7 +613,7 @@ public static void testIntMaxValueOverflowTwice(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = IRNode.MUL_I, counts = {IRNode.STORE_L, "1"}) public static void testIntProductsOverflowOnceAtMin(boolean flag, boolean flag2) { int l = flag ? Integer.MAX_VALUE/2 + 1 : Integer.MAX_VALUE/2 + 2; @@ -630,7 +630,7 @@ public static void testIntProductsOverflowOnceAtMin(boolean flag, boolean flag2) @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = IRNode.MUL_I, counts = {IRNode.STORE_L, "1"}) public static void testIntProductsOverflowOnceAtMax(boolean flag, boolean flag2) { // 63786643 * 101 = Integer.MAX_VALUE*3 + 2 --cast to int--> Integer.MAX_VALUE @@ -648,7 +648,7 @@ public static void testIntProductsOverflowOnceAtMax(boolean flag, boolean flag2) @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = IRNode.MUL_I, counts = {IRNode.STORE_L, "1"}) public static void testIntProductsUnderflowOnceAtMin(boolean flag, boolean flag2) { int l = flag ? Integer.MIN_VALUE/3 - 1 : Integer.MIN_VALUE/3 - 2; @@ -665,7 +665,7 @@ public static void testIntProductsUnderflowOnceAtMin(boolean flag, boolean flag2 @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(failOn = IRNode.MUL_I, counts = {IRNode.STORE_L, "1"}) public static void testIntProductsUnderflowOnceAtMax(boolean flag, boolean flag2) { // -1610612736 * 4 = Integer.MIN_VALUE*3 --cast to int--> Integer.MIN_VALUE @@ -683,7 +683,7 @@ public static void testIntProductsUnderflowOnceAtMax(boolean flag, boolean flag2 @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_I, "1"}) public static void testIntProductsDifferentNumberOfOverflow(boolean flag, boolean flag2) { // 63786643 * 101 = Integer.MAX_VALUE*3 + 2 --cast to int--> Integer.MAX_VALUE // Overflown once @@ -701,7 +701,7 @@ public static void testIntProductsDifferentNumberOfOverflow(boolean flag, boolea @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_I, "1"}) public static void testIntProductsDifferentNumberOfUnderflows(boolean flag, boolean flag2) { // -1610612736 * 4 = Integer.MIN_VALUE*3 --cast to int--> Integer.MIN_VALUE // Underflown once @@ -719,7 +719,7 @@ public static void testIntProductsDifferentNumberOfUnderflows(boolean flag, bool @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_I, "1"}) public static void testIntNotSameOverflow1(boolean flag, boolean flag2) { int l = flag ? 1 : Integer.MAX_VALUE; @@ -734,7 +734,7 @@ public static void testIntNotSameOverflow1(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_I, "1"}) public static void testIntNotSameOverflow2(boolean flag, boolean flag2) { int l = flag ? 1 : Integer.MIN_VALUE; @@ -749,7 +749,7 @@ public static void testIntNotSameOverflow2(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_I, "1"}) public static void testIntNotSameOverflow3(boolean flag, boolean flag2) { int l = flag ? -1 : Integer.MIN_VALUE; @@ -764,7 +764,7 @@ public static void testIntNotSameOverflow3(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_I, "1"}) public static void testIntNotSameOverflow4(boolean flag, boolean flag2) { int l = flag ? -1 : Integer.MAX_VALUE; @@ -779,7 +779,7 @@ public static void testIntNotSameOverflow4(boolean flag, boolean flag2) { @Test @Warmup(0) - @Arguments({Argument.TRUE, Argument.FALSE}) + @Arguments(values = {Argument.TRUE, Argument.FALSE}) @IR(counts = {IRNode.STORE_L, "2", IRNode.MUL_I, "1"}) public static void testIntNotSameOverflow5(boolean flag, boolean flag2) { int l = flag ? Integer.MIN_VALUE : Integer.MAX_VALUE; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/ScalarReplacementTests.java b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/ScalarReplacementTests.java index 191f995962d..1c332ac976b 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/ScalarReplacementTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/ScalarReplacementTests.java @@ -55,7 +55,7 @@ public static void main(String[] args) { } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) @IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC}) public String stringConstant(int age) { Person p = new Person("Java", age); @@ -63,7 +63,7 @@ public String stringConstant(int age) { } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) @IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC}) public int intConstant(int age) { Person p = new Person("Java", age); @@ -71,7 +71,7 @@ public int intConstant(int age) { } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) @IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC}) public String nestedStringConstant(int age) { Person p1 = new Person("Java", age); @@ -80,7 +80,7 @@ public String nestedStringConstant(int age) { } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) @IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC}) public int nestedIntConstant(int age) { Person p1 = new Person("Java", age); @@ -89,7 +89,7 @@ public int nestedIntConstant(int age) { } @Test - @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) @IR(failOn = {IRNode.CALL, IRNode.LOAD, IRNode.STORE, IRNode.FIELD_ACCESS, IRNode.ALLOC}) public int nestedConstants(int age1, int age2) { Person p = new Person( diff --git a/test/hotspot/jtreg/compiler/calls/NativeCalls.java b/test/hotspot/jtreg/compiler/calls/NativeCalls.java new file mode 100644 index 00000000000..64a7acbc117 --- /dev/null +++ b/test/hotspot/jtreg/compiler/calls/NativeCalls.java @@ -0,0 +1,87 @@ +/* + * 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 8329126 + * @summary check that native methods get compiled + * + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:-UseOnStackReplacement -XX:+TieredCompilation compiler.calls.NativeCalls + * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:-UseOnStackReplacement -XX:-TieredCompilation compiler.calls.NativeCalls + * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:-UseOnStackReplacement -XX:+TieredCompilation -XX:TieredStopAtLevel=1 compiler.calls.NativeCalls + * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:-UseOnStackReplacement -XX:+TieredCompilation -XX:TieredStopAtLevel=2 compiler.calls.NativeCalls + * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:-UseOnStackReplacement -XX:+TieredCompilation -XX:TieredStopAtLevel=3 compiler.calls.NativeCalls + * @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:-UseOnStackReplacement -XX:+TieredCompilation -XX:TieredStopAtLevel=4 compiler.calls.NativeCalls + */ + +package compiler.calls; + +import java.lang.reflect.Method; + +import jdk.test.whitebox.WhiteBox; + +public class NativeCalls { + static Method emptyStaticNativeMethod; + static Method callNativeMethod; + static WhiteBox wb; + static { + init(); + } + static void init() { + System.loadLibrary("NativeCalls"); + wb = WhiteBox.getWhiteBox(); + try { + emptyStaticNativeMethod = NativeCalls.class.getDeclaredMethod("emptyStaticNative"); + callNativeMethod = NativeCalls.class.getDeclaredMethod("callNative"); + } catch (NoSuchMethodException nsme) { + throw new Error("TEST BUG: can't find test method", nsme); + } + } + + native static void emptyStaticNative(); + + static void callNative() { + emptyStaticNative(); + } + + static public void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + callNative(); + } + if (wb.getMethodCompilationLevel(callNativeMethod) > 0) { + if (!wb.isMethodCompiled(emptyStaticNativeMethod)) { + throw new Error("TEST BUG: '" + emptyStaticNativeMethod + "' should be compiled"); + } + } + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/NativeUtils.java b/test/hotspot/jtreg/compiler/calls/libNativeCalls.c similarity index 80% rename from test/hotspot/jtreg/vmTestbase/nsk/share/NativeUtils.java rename to test/hotspot/jtreg/compiler/calls/libNativeCalls.c index 4fb0db7675d..6a08dfdacb1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/NativeUtils.java +++ b/test/hotspot/jtreg/compiler/calls/libNativeCalls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -20,12 +20,8 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package nsk.share; -public class NativeUtils { - static { - System.loadLibrary("native_utils"); - } +#include "jni.h" - public static native long getCurrentPID(); -} +JNIEXPORT +void JNICALL Java_compiler_calls_NativeCalls_emptyStaticNative(JNIEnv* env, jclass jclazz) {} diff --git a/test/hotspot/jtreg/compiler/ccp/TestPushCmpU3Node.java b/test/hotspot/jtreg/compiler/ccp/TestPushCmpU3Node.java new file mode 100644 index 00000000000..96643826dcd --- /dev/null +++ b/test/hotspot/jtreg/compiler/ccp/TestPushCmpU3Node.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8333366 + * @summary Test that CmpU3Nodes are pushed back to the CCP worklist such that the type can be re-evaluated. + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,*TestPushCmpU3Node::test + * compiler.ccp.TestPushCmpU3Node + */ + +package compiler.ccp; + +import static java.lang.Integer.*; + +public class TestPushCmpU3Node { + public static void main(String[] args) { + for (int i = 0; i < 10_000; ++i) { + test(); + } + } + + public static void test() { + for (int i = MAX_VALUE - 50_000; compareUnsigned(i, -1) < 0; ++i) { + if (compareUnsigned(MIN_VALUE, i) < 0) { + return; + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java b/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java index 5e05a0fae57..5b6274681f7 100644 --- a/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java +++ b/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java @@ -62,7 +62,7 @@ public static void main(String[] args) throws Exception { out.shouldMatch("Code cache size too small for \\S* pages\\. Reverting to smaller page size \\((\\S*)\\)\\."); out.shouldHaveExitValue(0); // Parse page sizes to find next biggest page - String sizes = out.firstMatch("Usable page sizes:(.*)", 1); + String sizes = out.firstMatch("Usable page sizes:([^.]+)", 1); List sizeList = Arrays.stream(sizes.trim().split("\\s*,\\s*")).map(CheckLargePages::parseMemoryString).sorted().toList(); final int smallerPageSizeIndex = sizeList.indexOf(largePageSize) - 1; Asserts.assertGreaterThanOrEqual(smallerPageSizeIndex, 0); diff --git a/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java b/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java index fa2cfa98ccb..f3233bdaeca 100644 --- a/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java +++ b/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java @@ -45,12 +45,20 @@ public static void main(String args[]) throws Throwable { } } - public static void wasteCodeCache() throws Exception { + public static void wasteCodeCache() throws Throwable { URL url = CodeCacheFullCountTest.class.getProtectionDomain().getCodeSource().getLocation(); - for (int i = 0; i < 500; i++) { - ClassLoader cl = new MyClassLoader(url); - refClass(cl.loadClass("SomeClass")); + try { + for (int i = 0; i < 500; i++) { + ClassLoader cl = new MyClassLoader(url); + refClass(cl.loadClass("SomeClass")); + } + } catch (Throwable t) { + // Expose the root cause of the Throwable instance. + while (t.getCause() != null) { + t = t.getCause(); + } + throw t; } } @@ -59,7 +67,7 @@ public static void runTest() throws Throwable { "-XX:ReservedCodeCacheSize=2496k", "-XX:-UseCodeCacheFlushing", "-XX:-MethodFlushing", "CodeCacheFullCountTest", "WasteCodeCache"); OutputAnalyzer oa = ProcessTools.executeProcess(pb); // Ignore adapter creation failures - if (oa.getExitValue() != 0 && !oa.getStderr().contains("Out of space in CodeCache for adapters")) { + if (oa.getExitValue() != 0 && !oa.getOutput().contains("Out of space in CodeCache")) { oa.reportDiagnosticSummary(); throw new RuntimeException("VM finished with exit code " + oa.getExitValue()); } diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestNestedRelockAtDeopt.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestNestedRelockAtDeopt.java new file mode 100644 index 00000000000..45bd97b7bc6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestNestedRelockAtDeopt.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8324174 + * @summary During deoptimization locking and unlocking for nested locks are executed in incorrect order. + * @requires vm.compMode != "Xint" + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -Xmx128M + * -XX:CompileCommand=exclude,TestNestedRelockAtDeopt::main TestNestedRelockAtDeopt + */ + +import java.util.ArrayList; +public class TestNestedRelockAtDeopt { + + static final int CHUNK = 1000; + static ArrayList arr = null; + + public static void main(String[] args) { + arr = new ArrayList<>(); + try { + while (true) { + test1(); + } + } catch (OutOfMemoryError oom) { + arr = null; // Free memory + System.out.println("OOM caught in test1"); + } + arr = new ArrayList<>(); + try { + while (true) { + test2(); + } + } catch (OutOfMemoryError oom) { + arr = null; // Free memory + System.out.println("OOM caught in test2"); + } + arr = new ArrayList<>(); + TestNestedRelockAtDeopt obj = new TestNestedRelockAtDeopt(); + try { + while (true) { + test3(obj); + } + } catch (OutOfMemoryError oom) { + arr = null; // Free memory + System.out.println("OOM caught in test3"); + } + arr = new ArrayList<>(); + try { + while (true) { + test4(obj); + } + } catch (OutOfMemoryError oom) { + arr = null; // Free memory + System.out.println("OOM caught in test4"); + } + } + + // Nested locks in one method + static void test1() { // Nested lock in one method + synchronized (TestNestedRelockAtDeopt.class) { + synchronized (new TestNestedRelockAtDeopt()) { // lock eliminated - not escaped allocation + synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated + synchronized (new TestNestedRelockAtDeopt()) { // lock eliminated - not escaped allocation + synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated + arr.add(new byte[CHUNK]); + } + } + } + } + } + } + + // Nested locks in inlined method + static void foo() { + synchronized (new TestNestedRelockAtDeopt()) { // lock eliminated - not escaped allocation + synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated when inlined + arr.add(new byte[CHUNK]); + } + } + } + + static void test2() { + synchronized (TestNestedRelockAtDeopt.class) { + synchronized (new TestNestedRelockAtDeopt()) { // lock eliminated - not escaped allocation + synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated + foo(); // Inline + } + } + } + } + + // Nested locks in one method + static void test3(TestNestedRelockAtDeopt obj) { + synchronized (TestNestedRelockAtDeopt.class) { + synchronized (obj) { // lock not eliminated - external object + synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated + synchronized (obj) { // nested lock eliminated + synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated + arr.add(new byte[CHUNK]); + } + } + } + } + } + } + + // Nested locks with different objects in inlined method + static void bar(TestNestedRelockAtDeopt obj) { + synchronized (obj) { // nested lock eliminated when inlined + synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated when inlined + arr.add(new byte[CHUNK]); + } + } + } + + static void test4(TestNestedRelockAtDeopt obj) { + synchronized (TestNestedRelockAtDeopt.class) { + synchronized (obj) { // lock not eliminated - external object + synchronized (TestNestedRelockAtDeopt.class) { // nested lock eliminated + bar(obj); // Inline + } + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java index c144194333b..e87944f3ca9 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, 2022, Arm Limited. All rights reserved. + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, Arm Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -255,10 +255,11 @@ public void emitPrologue() { // Must be patchable by NativeJump::patch_verified_entry emitNop(); if (config.ropProtection) { - code.emitInt(0xdac103be); // pacia x30, x29 + code.emitInt(0xf94003df); // ldr xzr, [x30] + code.emitInt(0xd503231f); // paciaz } - code.emitInt(0xa9be7bfd); // stp x29, x30, [sp, #-32]! - code.emitInt(0x910003fd); // mov x29, sp + code.emitInt(0xa9bf7bfd); // stp x29, x30, [sp, #-16]! + code.emitInt(0x910003fd); // mov x29, sp setDeoptRescueSlot(newStackSlot(AArch64Kind.QWORD)); } @@ -468,23 +469,25 @@ public void emitTrap(DebugInfo info) { @Override public void emitIntRet(Register a) { emitMov(AArch64.r0, a); - code.emitInt(0x910003bf); // mov sp, x29 - code.emitInt(0xa8c27bfd); // ldp x29, x30, [sp], #32 + code.emitInt(0x910003bf); // mov sp, x29 + code.emitInt(0xa8c17bfd); // ldp x29, x30, [sp], #16 if (config.ropProtection) { - code.emitInt(0xdac113be); // autia x30, x29 + code.emitInt(0xd503239f); // autiaz + code.emitInt(0xf94003df); // ldr xzr, [x30] } - code.emitInt(0xd65f03c0); // ret + code.emitInt(0xd65f03c0); // ret } @Override public void emitFloatRet(Register a) { assert a == AArch64.v0 : "Unimplemented move " + a; - code.emitInt(0x910003bf); // mov sp, x29 - code.emitInt(0xa8c27bfd); // ldp x29, x30, [sp], #32 + code.emitInt(0x910003bf); // mov sp, x29 + code.emitInt(0xa8c17bfd); // ldp x29, x30, [sp], #16 if (config.ropProtection) { - code.emitInt(0xdac113be); // autia x30, x29 + code.emitInt(0xd503239f); // autiaz + code.emitInt(0xf94003df); // ldr xzr, [x30] } - code.emitInt(0xd65f03c0); // ret + code.emitInt(0xd65f03c0); // ret } @Override diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/Arguments.java b/test/hotspot/jtreg/compiler/lib/ir_framework/Arguments.java index 35a5a4aa894..90e57f27c32 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/Arguments.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/Arguments.java @@ -27,8 +27,10 @@ import java.lang.annotation.RetentionPolicy; /** - * This annotation is used to specify well-defined {@link Argument} values for test methods (specifying {@link Test}) when - * used as part of a base test or checked test. + * This annotation is used for test methods (see {@link Test}) to specify what values should be passed as arguments. + * One can either specify the individual arguments with values (see {@link Argument}), or use + * a setup method (see {@link Setup}) to define more complex arguments and/or even set fields values. + * This annotation can only be applied to a normal test. * * @see Argument * @see Test @@ -37,7 +39,11 @@ @Retention(RetentionPolicy.RUNTIME) public @interface Arguments { /** - * Get the argument value. + * Get the argument values. */ - Argument[] value(); + Argument[] values() default {}; + /** + * Get the setup method name. + */ + String setup() default ""; } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java index 8f7cbc53157..fd2cd69056a 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IR.java @@ -108,23 +108,44 @@ */ String[] applyIf() default {}; + /** + * Accepts a single pair composed of a platform string followed by a true/false + * value where a true value necessitates that we are currently testing on that platform and vice-versa. + * IR checks are enforced only if the specified platform constraint is met. + */ + String[] applyIfPlatform() default {}; + + /** + * Accepts a list of pairs where each pair is composed of a platform string followed by a true/false + * value where a true value necessitates that we are currently testing on that platform and vice-versa. + * IR checks are enforced only if all the specified platform constraints are met. + */ + String[] applyIfPlatformAnd() default {}; + + /** + * Accepts a list of pairs where each pair is composed of a platform string followed by a true/false + * value where a true value necessitates that we are currently testing on that platform and vice-versa. + * IR checks are enforced if any of the specified platform constraints are met. + */ + String[] applyIfPlatformOr() default {}; + /** * Accepts a single feature pair which is composed of CPU feature string followed by a true/false - * value where a true value necessities existence of CPU feature and vice-versa. + * value where a true value necessitates existence of CPU feature and vice-versa. * IR verifications checks are enforced only if the specified feature constraint is met. */ String[] applyIfCPUFeature() default {}; /** * Accepts a list of feature pairs where each pair is composed of target feature string followed by a true/false - * value where a true value necessities existence of target feature and vice-versa. + * value where a true value necessitates existence of target feature and vice-versa. * IR verifications checks are enforced only if all the specified feature constraints are met. */ String[] applyIfCPUFeatureAnd() default {}; /** * Accepts a list of feature pairs where each pair is composed of target feature string followed by a true/false - * value where a true value necessities existence of target feature and vice-versa. + * value where a true value necessitates existence of target feature and vice-versa. * IR verifications checks are enforced if any of the specified feature constraint is met. */ String[] applyIfCPUFeatureOr() default {}; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index a7087166729..900f61d78ba 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -730,6 +730,11 @@ public class IRNode { beforeMatchingNameRegex(LOAD_VECTOR_GATHER, "LoadVectorGather"); } + public static final String LOAD_VECTOR_MASKED = PREFIX + "LOAD_VECTOR_MASKED" + POSTFIX; + static { + beforeMatchingNameRegex(LOAD_VECTOR_MASKED, "LoadVectorMasked"); + } + public static final String LOAD_VECTOR_GATHER_MASKED = PREFIX + "LOAD_VECTOR_GATHER_MASKED" + POSTFIX; static { beforeMatchingNameRegex(LOAD_VECTOR_GATHER_MASKED, "LoadVectorGatherMasked"); @@ -1406,6 +1411,11 @@ public class IRNode { beforeMatchingNameRegex(STORE_VECTOR_SCATTER, "StoreVectorScatter"); } + public static final String STORE_VECTOR_MASKED = PREFIX + "STORE_VECTOR_MASKED" + POSTFIX; + static { + beforeMatchingNameRegex(STORE_VECTOR_MASKED, "StoreVectorMasked"); + } + public static final String STORE_VECTOR_SCATTER_MASKED = PREFIX + "STORE_VECTOR_SCATTER_MASKED" + POSTFIX; static { beforeMatchingNameRegex(STORE_VECTOR_SCATTER_MASKED, "StoreVectorScatterMasked"); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md index bd66d765284..5f444b137ec 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md @@ -34,19 +34,29 @@ There are various ways how to set up and run a test within the `main()` method o The framework offers various annotations and flags to control how your test code should be invoked and being checked. This section gives an overview over all these features. ### 2.1 Different Tests -There are three kinds of tests depending on how much control is needed over the test invocation. -#### Base Tests -The simplest form of testing provides a single `@Test` annotated method which the framework will invoke as part of the testing. The test method has no or well-defined arguments that the framework can automatically provide. +There are two ways a test can be written, depending on how much control is needed over the test invocation. -More information on base tests with a precise definition can be found in the Javadocs of [Test](./Test.java). Concrete examples on how to specify a base test can be found in [BaseTestsExample](../../../testlibrary_tests/ir_framework/examples/BaseTestExample.java). +#### Normal Test +The normal and simplest form of testing provides a single `@Test` annotated method which the framework invokes directly as part of the testing. The test method either has no arguments, or they must be specified with an `@Arguments` annotation. -#### Checked Tests -The base tests do not provide any way of verification by user code. A checked test enables this by allowing the user to define an additional `@Check` annotated method which is invoked directly after the `@Test` annotated method. This allows the user to perform various checks about the test method including return value verification. +Arguments can be provided with `@Arguments(values = {...})` by providing well-specified inputs for each individual argument. Alternatively, a setup method can be chosen with `@Arguments(setup = "setupMethodName")`, which computes arguments and can also set fields. -More information on checked tests with a precise definition can be found in the Javadocs of [Check](./Check.java). Concrete examples on how to specify a checked test can be found in [CheckedTestsExample](../../../testlibrary_tests/ir_framework/examples/CheckedTestExample.java). +More information on normal test methods with a precise definition can be found in the Javadocs of [Test](./Test.java). Concrete examples on how to specify a normal test can be found in [NormalTestExample](../../../testlibrary_tests/ir_framework/examples/NormalTestExample.java). + +##### Setup Method +A `@Setup` annotated method can provide custom arguments and set fields before a normal test is run. A `@Test` annotated method can additionally be annotated with `@Arguments(setup = "setupMethodName")` to define the dedicated `@Setup` method. + +More information on normal tests with `@Setup` methods together with a precise definition can be found in the Javadocs of [Setup](./Setup.java). Concrete examples on how to specify a setup method can be found in [SetupExample](../../../testlibrary_tests/ir_framework/examples/SetupExample.java). + +##### Check Method +A `@Check(test = "checkMethodName")` annotated method is invoked directly after the `@Test` annotated method `checkMethodName()` is executed. The user can perform various checks, such as test method return value and field value verification. + +More information on check methods with a precise definition can be found in the Javadocs of [Check](./Check.java). Concrete examples on how to specify check methods can be found in [CheckedTestExample](../../../testlibrary_tests/ir_framework/examples/CheckedTestExample.java). + +Note: `@Setup` and `@Check` methods can only be specified for normal but not for custom run tests (see next section). #### Custom Run Tests -Neither the base nor the checked tests provide any control over how a `@Test` annotated method is invoked in terms of customized argument values and/or conditions for the invocation itself. A custom run test gives full control over the invocation of the `@Test` annotated method to the user. The framework calls a dedicated `@Run` annotated method from which the user can invoke the `@Test` method according to his/her needs. +A custom run test gives full control over the invocation of the `@Test` annotated method to the user which includes argument and field setup as well as result and field value verification. The framework calls a dedicated `@Run` annotated method from which the user can invoke the `@Test` method according to their needs. More information on checked tests with a precise definition can be found in the Javadocs of [Run](./Run.java). Concrete examples on how to specify a custom run test can be found in [CustomRunTestsExample](../../../testlibrary_tests/ir_framework/examples/CustomRunTestExample.java). @@ -114,8 +124,14 @@ One might also want to restrict the application of certain `@IR` rules depending - `applyIfOr`: Only apply a rule if **at least one** flag has the specified value/range of values. #### Disable/Enable IR Rules based on available CPU Features -Sometimes, an `@IR` rule should only be applied if a certain CPU feature is present. This can be done with -the attributes `applyIfCPUFeatureXXX` in [@IR](./IR.java) which follow the same logic as the `applyIfXXX` methods for flags in the previous section. If a `@Test` annotated method has multiple preconditions (for example `applyIf` and `applyIfCPUFeature`), they are evaluated as a logical conjunction. An example with `applyIfCPUFeatureXXX` can be found in [TestCPUFeatureCheck](../../../testlibrary_tests/ir_framework/tests/TestCPUFeatureCheck.java) (internal framework test). +Sometimes, an `@IR` rule should only be applied if a certain CPU feature is present. This can be done with the attributes `applyIfCPUFeatureXXX` in [@IR](./IR.java) which follow the same logic as the `applyIfXXX` methods for flags in the previous section. An example with `applyIfCPUFeatureXXX` can be found in [TestCPUFeatureCheck](../../../testlibrary_tests/ir_framework/tests/TestCPUFeatureCheck.java) (internal framework test). + +If a `@Test` annotated method has multiple preconditions (for example `applyIf` and `applyIfCPUFeature`), they are evaluated as a logical conjunction. It's worth noting that flags in `applyIf` are checked only if the CPU features in `applyIfCPUFeature` are matched when they are both specified. This avoids the VM flag being evaluated on hardware that does not support it. An example with both `applyIfCPUFeatureXXX` and `applyIfXXX` can be found in [TestPreconditions](../../../testlibrary_tests/ir_framework/tests/TestPreconditions.java) (internal framework test). + +#### Disable/Enable IR Rules based on Platform +`@IR` rules based on the platform can be specified using `applyIfPlatformXXX` in [@IR](./IR.java). A reference for using these attributes can be found in [TestPlatformChecks](../../../testlibrary_tests/ir_framework/tests/TestPlatformChecks.java) (internal framework test). + +Platform attributes are evaluated as a logical conjunction, and take precedence over VM Flag attributes. An example with both `applyIfPlatformXXX` and `applyIfXXX` can be found in [TestPreconditions](../../../testlibrary_tests/ir_framework/tests/TestPreconditions.java) (internal framework test). #### Implicitly Skipping IR Verification An IR verification cannot always be performed. Certain VM flags explicitly disable IR verification, change the IR shape in unexpected ways letting IR rules fail or even make IR verification impossible: diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/Setup.java b/test/hotspot/jtreg/compiler/lib/ir_framework/Setup.java new file mode 100644 index 00000000000..2d2d5c68545 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/Setup.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.lib.ir_framework; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This annotation is used to identify Setup methods. These can be used to compute arbitrary arguments for a test + * method (see {@link Test}), as well as to set field values. A test method can use a setup method, by specifying + * it in a {@link Arguments} annotation. A setup method can optionally take a {@link SetupInfo} as an argument. The + * arguments for the test methods are returned as a new object array. + * + * Examples on how to use test methods can be found in {@link ir_framework.examples.SetupExample} and also as part of the + * internal testing in the package {@link ir_framework.tests}. + * + * @see Arguments + * @see Setup + * @see SetupInfo + * @see Test + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface Setup { +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_utils.cpp b/test/hotspot/jtreg/compiler/lib/ir_framework/SetupInfo.java similarity index 63% rename from test/hotspot/jtreg/vmTestbase/nsk/share/native/native_utils.cpp rename to test/hotspot/jtreg/compiler/lib/ir_framework/SetupInfo.java index 4331eb37286..49bfb8a1553 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/native/native_utils.cpp +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/SetupInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,24 +20,22 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -#include -#if (defined(WIN32) || defined (_WIN32)) -#include -#define getpid _getpid -#define pidType int -#else -#include -#define pidType pid_t -#endif +package compiler.lib.ir_framework; -#include -#include - -extern "C" { +/** + * Info optionally passed to {@link Setup} annotated methods. + * + * @see Setup + */ +public record SetupInfo(int invocationCounter) { -JNIEXPORT jlong -JNICALL Java_nsk_share_NativeUtils_getCurrentPID(JNIEnv * jni, jobject jobj) { - return (jlong) getpid(); -} + /** + * Get the invocation counter, which increments with every invocation of the setup method. It allows the creation + * of deterministically different inputs to the test method for every invocation. + */ + @Override + public int invocationCounter() { + return invocationCounter; + } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/Test.java b/test/hotspot/jtreg/compiler/lib/ir_framework/Test.java index 9f7cfd752d8..39cbd9c9eef 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/Test.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/Test.java @@ -71,7 +71,7 @@ * * *

- * Examples on how to write base tests can be found in {@link ir_framework.examples.BaseTestExample} + * Examples on how to write base tests can be found in {@link ir_framework.examples.NormalTestExample} * and also as part of the internal testing in the package {@link ir_framework.tests}. * * @see Arguments diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/AbstractTest.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/AbstractTest.java index 68d8d0f5aaf..e74877c351b 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/AbstractTest.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/AbstractTest.java @@ -94,7 +94,6 @@ public void run() { if (skip) { return; } - onStart(); for (int i = 0; i < warmupIterations; i++) { invokeTest(); } @@ -104,10 +103,6 @@ public void run() { invokeTest(); } - protected void onStart() { - // Do nothing by default. - } - abstract protected void invokeTest(); abstract protected void onWarmupFinished(); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/ArgumentValue.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ArgumentValue.java index 7c5a9edec71..836f37f6656 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/ArgumentValue.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ArgumentValue.java @@ -68,18 +68,14 @@ private ArgumentValue(Object argumentValue, Class randomClass) { } /** - * Return all arguments for the @Arguments annotation. + * From the @Arguments(value = {...}) annotation, determine the list of ArgumentValues for a specific test method m. * * @param m The @Test method. + * @param values The argument values specified in the annotation. * @return Returns an array with Argument objects for each specified argument in the @Arguments annotation of m. * Returns null if method has no @Arguments annotation. */ - public static ArgumentValue[] getArguments(Method m) { - Arguments argumentsAnno = m.getAnnotation(Arguments.class); - if (argumentsAnno == null) { - return null; - } - Argument[] values = argumentsAnno.value(); + public static ArgumentValue[] getArgumentValues(Method m, Argument[] values) { ArgumentValue[] arguments = new ArgumentValue[values.length]; Class[] declaredParameters = m.getParameterTypes(); Parameter[] declaredParameterObjects = m.getParameters(); @@ -250,7 +246,7 @@ public boolean isFixedRandom() { return isFixedRandom; } - public Object getArgument() { + public Object getValue() { if (isRandomEach) { return getRandom(randomClass); } else { @@ -322,7 +318,7 @@ class BooleanToggleValue extends ArgumentValue { } @Override - public Object getArgument() { + public Object getValue() { previousBoolean = !previousBoolean; return previousBoolean; } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/ArgumentsProvider.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ArgumentsProvider.java new file mode 100644 index 00000000000..3a3388baf14 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ArgumentsProvider.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.lib.ir_framework.test; + +import compiler.lib.ir_framework.shared.TestFormat; +import compiler.lib.ir_framework.shared.TestRunException; +import compiler.lib.ir_framework.Argument; +import compiler.lib.ir_framework.Arguments; +import compiler.lib.ir_framework.SetupInfo; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Arrays; + +/** + * This interface provides arguments (and can set fields) for a test method. Different implementations are chosen + * based on the @Arguments annotation for the @Test method. + */ +interface ArgumentsProvider { + /** + * Compute arguments (and possibly set fields) for a test method. + * + * @param invocationTarget object on which the test method is called, or null if the test method is static. + * @param invocationCounter is incremented for every set of arguments to be provided for the test method. + * It can be used to create deterministic inputs, that vary between different + * invocations of the test method. + * @return Returns the arguments to be passed into the test method. + */ + Object[] getArguments(Object invocationTarget, int invocationCounter); + +} + +/** + * For a test method, determine what ArgumentsProvider is to be constructed, given its @Arguments annotation, + * and the available setup methods. + */ +class ArgumentsProviderBuilder { + public static ArgumentsProvider build(Method method, + HashMap setupMethodMap) { + Arguments argumentsAnnotation = method.getAnnotation(Arguments.class); + if (argumentsAnnotation == null) { + return new DefaultArgumentsProvider(); + } + + Argument[] values = argumentsAnnotation.values(); + String setupMethodName = argumentsAnnotation.setup(); + + if (!setupMethodName.isEmpty()) { + TestFormat.check(values.length == 0, + "@Arguments: Can only specify \"setup\" or \"values\" but not both in " + method); + TestFormat.check(setupMethodMap.containsKey(setupMethodName), + "@Arguments setup: did not find " + setupMethodName + + " for " + method); + Method setupMethod = setupMethodMap.get(setupMethodName); + return new SetupArgumentsProvider(setupMethod); + } else { + TestFormat.check(values.length > 0, + "@Arguments: Empty annotation not allowed. Either specify \"values\" or \"setup\" in " + method); + ArgumentValue[] argumentValues = ArgumentValue.getArgumentValues(method, values); + return new ValueArgumentsProvider(argumentValues); + } + } +} + +/** + * Default: when no @Arguments annotation is provided (including for custom run tests). + */ +final class DefaultArgumentsProvider implements ArgumentsProvider { + @Override + public Object[] getArguments(Object invocationTarget, int invocationCounter) { + return new Object[]{}; + } +} + +/** + * Used for @Arguments(values = {...}) to specify individual arguments directly. + */ +final class ValueArgumentsProvider implements ArgumentsProvider { + ArgumentValue[] argumentValues; + + ValueArgumentsProvider(ArgumentValue[] argumentValues) { + this.argumentValues = argumentValues; + } + + @Override + public Object[] getArguments(Object invocationTarget, int invocationCounter) { + return Arrays.stream(argumentValues).map(v -> v.getValue()).toArray(); + } +} + +/** + * Used for @Arguments(setup = "setupMethodName") to specify a setup method to provide arguments + * and possibly set fields. + */ +final class SetupArgumentsProvider implements ArgumentsProvider { + Method setupMethod; + + SetupArgumentsProvider(Method setupMethod) { + this.setupMethod = setupMethod; + } + + @Override + public Object[] getArguments(Object invocationTarget, int invocationCounter) { + Object target = Modifier.isStatic(setupMethod.getModifiers()) ? null + : invocationTarget; + try { + if (setupMethod.getParameterCount() == 1) { + return (Object[]) setupMethod.invoke(target, new SetupInfo(invocationCounter)); + } else { + return (Object[]) setupMethod.invoke(target); + } + } catch (Exception e) { + throw new TestRunException("There was an error while invoking setup method " + + setupMethod + " on " + target, e); + } + } +} + diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/BaseTest.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/BaseTest.java index a17eb91884d..ee36f13fc7d 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/BaseTest.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/BaseTest.java @@ -38,6 +38,7 @@ class BaseTest extends AbstractTest { protected final Object invocationTarget; private final boolean shouldCompile; private final boolean waitForCompilation; + private int invocationCounter; public BaseTest(DeclaredTest test, boolean skip) { super(test.getWarmupIterations(), skip); @@ -47,6 +48,7 @@ public BaseTest(DeclaredTest test, boolean skip) { this.invocationTarget = createInvocationTarget(testMethod); this.shouldCompile = shouldCompile(test); this.waitForCompilation = isWaitForCompilation(test); + this.invocationCounter = 0; } @Override @@ -59,11 +61,6 @@ public String getName() { return testMethod.getName(); } - @Override - protected void onStart() { - test.printFixedRandomArguments(); - } - @Override public void onWarmupFinished() { testInfo.setWarmUpFinished(); @@ -74,16 +71,18 @@ protected void invokeTest() { verify(invokeTestMethod()); } + /** + * Compute arguments (and possibly set fields), and invoke the test method. + */ private Object invokeTestMethod() { + Object[] arguments = test.getArguments(invocationTarget, invocationCounter++); try { - if (test.hasArguments()) { - return testMethod.invoke(invocationTarget, test.getArguments()); - } else { - return testMethod.invoke(invocationTarget); - } + return testMethod.invoke(invocationTarget, arguments); } catch (Exception e) { - throw new TestRunException("There was an error while invoking @Test method " + testMethod - + ". Used arguments: " + test.getArgumentsString(), e); + throw new TestRunException("There was an error while invoking @Test method " + testMethod + + ". Target: " + invocationTarget + + ". Arguments: " + test.formatArguments(arguments), + e); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/DeclaredTest.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/DeclaredTest.java index 3f1bfbba8b5..91cf6f8c27a 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/DeclaredTest.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/DeclaredTest.java @@ -27,24 +27,23 @@ import compiler.lib.ir_framework.shared.TestRunException; import java.lang.reflect.Method; -import java.util.Arrays; /** * This class represents a @Test method. */ public class DeclaredTest { private final Method testMethod; - private final ArgumentValue[] arguments; + private final ArgumentsProvider argumentsProvider; private final int warmupIterations; private final CompLevel compLevel; private Method attachedMethod; - public DeclaredTest(Method testMethod, ArgumentValue[] arguments, CompLevel compLevel, int warmupIterations) { + public DeclaredTest(Method testMethod, ArgumentsProvider argumentsProvider, CompLevel compLevel, int warmupIterations) { // Make sure we can also call non-public or public methods in package private classes testMethod.setAccessible(true); this.testMethod = testMethod; this.compLevel = compLevel; - this.arguments = arguments; + this.argumentsProvider = argumentsProvider; this.warmupIterations = warmupIterations; this.attachedMethod = null; } @@ -61,12 +60,8 @@ public int getWarmupIterations() { return warmupIterations; } - public boolean hasArguments() { - return arguments != null; - } - - public Object[] getArguments() { - return Arrays.stream(arguments).map(ArgumentValue::getArgument).toArray(); + public Object[] getArguments(Object invocationTarget, int invocationCounter) { + return argumentsProvider.getArguments(invocationTarget, invocationCounter); } public void setAttachedMethod(Method m) { @@ -77,41 +72,22 @@ public Method getAttachedMethod() { return attachedMethod; } - public void printFixedRandomArguments() { - if (hasArguments()) { - boolean hasRandomArgs = false; - StringBuilder builder = new StringBuilder("Fixed random arguments for method ").append(testMethod).append(": "); - for (int i = 0; i < arguments.length; i++) { - ArgumentValue argument = arguments[i]; - if (argument.isFixedRandom()) { - hasRandomArgs = true; - Object argumentVal = argument.getArgument(); - builder.append("arg ").append(i).append(": ").append(argumentVal.toString()); - if (argumentVal instanceof Character) { - builder.append(" (").append((int)(Character)argumentVal).append(")"); - } - builder.append(", "); - } - } - if (hasRandomArgs) { - // Drop the last comma and space. - builder.setLength(builder.length() - 2); - System.out.println(builder.toString()); - } + /** + * Format an array of arguments to string for error reporting. + */ + public String formatArguments(Object[] arguments) { + if (arguments == null) { + return ""; } - } - - public String getArgumentsString() { - if (hasArguments()) { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < arguments.length; i++) { - builder.append("arg ").append(i).append(": ").append(arguments[i].getArgument()).append(", "); - } - builder.setLength(builder.length() - 2); - return builder.toString(); - } else { + if (arguments.length == 0) { return ""; } + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < arguments.length; i++) { + builder.append("arg ").append(i).append(": ").append(arguments[i]).append(", "); + } + builder.setLength(builder.length() - 2); + return builder.toString(); } public Object invoke(Object obj, Object... args) { 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 c7dc832a1c9..a6927469d0e 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java @@ -27,6 +27,7 @@ import compiler.lib.ir_framework.IRNode; import compiler.lib.ir_framework.TestFramework; import compiler.lib.ir_framework.shared.*; +import jdk.test.lib.Platform; import jdk.test.whitebox.WhiteBox; import java.lang.reflect.Method; @@ -55,6 +56,27 @@ public class IREncodingPrinter { private Method method; private int ruleIndex; + // Platforms for use in IR preconditions. Please verify that e.g. there is + // a corresponding use in a jtreg @requires annotation before adding new platforms, + // as adding non-existent platforms can lead to skipped tests. + private static final List irTestingPlatforms = new ArrayList(Arrays.asList( + // os.family + "linux", + "mac", + "windows", + // vm.simpleArch + "aarch64", + "arm", + "ppc", + "riscv64", + "s390", + "x64", + "x86", + // corresponds to vm.bits + "32-bit", + "64-bit" + )); + // Please verify new CPU features before adding them. If we allow non-existent features // on this list, we will ignore tests and never execute them. Consult CPU_FEATURE_FLAGS // in corresponding vm_version_.hpp file to find correct cpu feature's name. @@ -78,7 +100,9 @@ public class IREncodingPrinter { // AArch64 "sha3", "asimd", - "sve" + "sve", + // Riscv64 + "rvv" )); public IREncodingPrinter() { @@ -132,17 +156,14 @@ private boolean shouldApplyIrRule(IR irAnno, String m, int ruleIndex, int ruleMa checkIRAnnotations(irAnno); if (isIRNodeUnsupported(irAnno)) { return false; - } else if (irAnno.applyIf().length != 0 && !hasAllRequiredFlags(irAnno.applyIf(), "applyIf")) { - printDisableReason(m, "Flag constraint not met (applyIf)", irAnno.applyIf(), ruleIndex, ruleMax); + } else if (irAnno.applyIfPlatform().length != 0 && !hasAllRequiredPlatform(irAnno.applyIfPlatform())) { + printDisableReason(m, "Constraint not met (applyIfPlatform)", irAnno.applyIfPlatform(), ruleIndex, ruleMax); return false; - } else if (irAnno.applyIfNot().length != 0 && !hasNoRequiredFlags(irAnno.applyIfNot(), "applyIfNot")) { - printDisableReason(m, "Flag constraint not met (applyIfNot)", irAnno.applyIfNot(), ruleIndex, ruleMax); + } else if (irAnno.applyIfPlatformAnd().length != 0 && !hasAllRequiredPlatform(irAnno.applyIfPlatformAnd())) { + printDisableReason(m, "Not all constraints are met (applyIfPlatformAnd)", irAnno.applyIfPlatformAnd(), ruleIndex, ruleMax); return false; - } else if (irAnno.applyIfAnd().length != 0 && !hasAllRequiredFlags(irAnno.applyIfAnd(), "applyIfAnd")) { - printDisableReason(m, "Not all flag constraints are met (applyIfAnd)", irAnno.applyIfAnd(), ruleIndex, ruleMax); - return false; - } else if (irAnno.applyIfOr().length != 0 && hasNoRequiredFlags(irAnno.applyIfOr(), "applyIfOr")) { - printDisableReason(m, "None of the flag constraints met (applyIfOr)", irAnno.applyIfOr(), ruleIndex, ruleMax); + } else if (irAnno.applyIfPlatformOr().length != 0 && !hasAnyRequiredPlatform(irAnno.applyIfPlatformOr())) { + printDisableReason(m, "None of the constraints are met (applyIfPlatformOr)", irAnno.applyIfPlatformOr(), ruleIndex, ruleMax); return false; } else if (irAnno.applyIfCPUFeature().length != 0 && !hasAllRequiredCPUFeature(irAnno.applyIfCPUFeature())) { printDisableReason(m, "Feature constraint not met (applyIfCPUFeature)", irAnno.applyIfCPUFeature(), ruleIndex, ruleMax); @@ -153,6 +174,18 @@ private boolean shouldApplyIrRule(IR irAnno, String m, int ruleIndex, int ruleMa } else if (irAnno.applyIfCPUFeatureOr().length != 0 && !hasAnyRequiredCPUFeature(irAnno.applyIfCPUFeatureOr())) { printDisableReason(m, "None of the feature constraints met (applyIfCPUFeatureOr)", irAnno.applyIfCPUFeatureOr(), ruleIndex, ruleMax); return false; + } else if (irAnno.applyIf().length != 0 && !hasAllRequiredFlags(irAnno.applyIf(), "applyIf")) { + printDisableReason(m, "Flag constraint not met (applyIf)", irAnno.applyIf(), ruleIndex, ruleMax); + return false; + } else if (irAnno.applyIfNot().length != 0 && !hasNoRequiredFlags(irAnno.applyIfNot(), "applyIfNot")) { + printDisableReason(m, "Flag constraint not met (applyIfNot)", irAnno.applyIfNot(), ruleIndex, ruleMax); + return false; + } else if (irAnno.applyIfAnd().length != 0 && !hasAllRequiredFlags(irAnno.applyIfAnd(), "applyIfAnd")) { + printDisableReason(m, "Not all flag constraints are met (applyIfAnd)", irAnno.applyIfAnd(), ruleIndex, ruleMax); + return false; + } else if (irAnno.applyIfOr().length != 0 && hasNoRequiredFlags(irAnno.applyIfOr(), "applyIfOr")) { + printDisableReason(m, "None of the flag constraints met (applyIfOr)", irAnno.applyIfOr(), ruleIndex, ruleMax); + return false; } else { // All preconditions satisfied: apply rule. return true; @@ -163,6 +196,7 @@ private void checkIRAnnotations(IR irAnno) { TestFormat.checkNoThrow(irAnno.counts().length != 0 || irAnno.failOn().length != 0, "Must specify either counts or failOn constraint" + failAt()); int flagConstraints = 0; + int platformConstraints = 0; int cpuFeatureConstraints = 0; if (irAnno.applyIfAnd().length != 0) { flagConstraints++; @@ -179,6 +213,21 @@ private void checkIRAnnotations(IR irAnno) { TestFormat.checkNoThrow(irAnno.applyIf().length <= 2, "Use applyIfAnd or applyIfOr or only 1 condition for applyIf" + failAt()); } + if (irAnno.applyIfPlatform().length != 0) { + platformConstraints++; + TestFormat.checkNoThrow(irAnno.applyIfPlatform().length == 2, + "applyIfPlatform expects single platform pair" + failAt()); + } + if (irAnno.applyIfPlatformAnd().length != 0) { + platformConstraints++; + TestFormat.checkNoThrow(irAnno.applyIfPlatformAnd().length % 2 == 0, + "applyIfPlatformAnd expects more than one platform pair" + failAt()); + } + if (irAnno.applyIfPlatformOr().length != 0) { + platformConstraints++; + TestFormat.checkNoThrow(irAnno.applyIfPlatformOr().length % 2 == 0, + "applyIfPlatformOr expects more than one platform pair" + failAt()); + } if (irAnno.applyIfCPUFeature().length != 0) { cpuFeatureConstraints++; TestFormat.checkNoThrow(irAnno.applyIfCPUFeature().length == 2, @@ -200,6 +249,7 @@ private void checkIRAnnotations(IR irAnno) { "Use applyIfAnd or applyIfOr or only 1 condition for applyIfNot" + failAt()); } TestFormat.checkNoThrow(flagConstraints <= 1, "Can only specify one flag constraint" + failAt()); + TestFormat.checkNoThrow(platformConstraints <= 1, "Can only specify one platform constraint" + failAt()); TestFormat.checkNoThrow(cpuFeatureConstraints <= 1, "Can only specify one CPU feature constraint" + failAt()); } @@ -233,6 +283,82 @@ private boolean hasAllRequiredFlags(String[] andRules, String ruleType) { return returnValue; } + private boolean hasAllRequiredPlatform(String[] andRules) { + boolean returnValue = true; + for (int i = 0; i < andRules.length; i++) { + String platform = andRules[i].trim(); + i++; + String value = andRules[i].trim(); + returnValue &= checkPlatform(platform, value); + } + return returnValue; + } + + private boolean hasAnyRequiredPlatform(String[] orRules) { + boolean returnValue = false; + for (int i = 0; i < orRules.length; i++) { + String platform = orRules[i].trim(); + i++; + String value = orRules[i].trim(); + returnValue |= checkPlatform(platform, value); + } + return returnValue; + } + + private boolean checkPlatform(String platform, String value) { + if (platform.isEmpty()) { + TestFormat.failNoThrow("Provided empty platform" + failAt()); + return false; + } + if (value.isEmpty()) { + TestFormat.failNoThrow("Provided empty value for platform " + platform + failAt()); + return false; + } + + if (!irTestingPlatforms.contains(platform)) { + TestFormat.failNoThrow("Provided platform is not in verified list: " + platform + failAt()); + return false; + } + + boolean trueValue = value.contains("true"); + boolean falseValue = value.contains("false"); + + if (!trueValue && !falseValue) { + TestFormat.failNoThrow("Provided incorrect value for platform " + platform + failAt()); + return false; + } + + String os = ""; + if (Platform.isLinux()) { + os = "linux"; + } else if (Platform.isOSX()) { + os = "mac"; + } else if (Platform.isWindows()) { + os = "windows"; + } + + String arch = ""; + if (Platform.isAArch64()) { + arch = "aarch64"; + } else if (Platform.isARM()) { + arch = "arm"; + } else if (Platform.isPPC()) { + arch = "ppc"; + } else if (Platform.isRISCV64()) { + arch = "riscv64"; + } else if (Platform.isS390x()) { + arch = "s390"; + } else if (Platform.isX64()) { + arch = "x64"; + } else if (Platform.isX86()) { + arch = "x86"; + } + + String currentPlatform = os + " " + arch + " " + (Platform.is32bit() ? "32-bit" : "64-bit"); + + return (trueValue && currentPlatform.contains(platform)) || (falseValue && !currentPlatform.contains(platform)); + } + private boolean hasAllRequiredCPUFeature(String[] andRules) { boolean returnValue = true; for (int i = 0; i < andRules.length; i++) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java index be65bd6e207..5eaf69562ad 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java @@ -107,6 +107,7 @@ assertions from main() of your test! private final HashMap declaredTests = new HashMap<>(); private final List allTests = new ArrayList<>(); private final HashMap testMethodMap = new HashMap<>(); + private final HashMap setupMethodMap = new HashMap<>(); private final List excludeList; private final List testList; private Set> helperClasses = null; // Helper classes that contain framework annotations to be processed. @@ -225,6 +226,8 @@ private void checkAnnotationsInClass(Class c, String clazzType) { "Cannot use @Run annotation in " + clazzType + " " + c + " at " + m); TestFormat.checkNoThrow(getAnnotation(m, Check.class) == null, "Cannot use @Check annotation in " + clazzType + " " + c + " at " + m); + TestFormat.checkNoThrow(getAnnotation(m, Setup.class) == null, + "Cannot use @Setup annotation in " + clazzType + " " + c + " at " + m); } } @@ -256,6 +259,11 @@ private void setupTests() { if (DUMP_REPLAY) { addReplay(); } + + // Collect the @Setup methods so we can reference them + // from the test methods + collectSetupMethods(); + // Make sure to first setup test methods and make them non-inlineable and only then process compile commands. setupDeclaredTests(); processControlAnnotations(testClass); @@ -495,6 +503,35 @@ static void enqueueForCompilation(Executable ex, CompLevel requestedCompLevel) { } } + + /** + * Collect all @Setup annotated methods and add them to setupMethodMap, for convenience to reference later from + * tests with @Arguments(setup = "setupMethodName"). + */ + private void collectSetupMethods() { + for (Method m : testClass.getDeclaredMethods()) { + Setup setupAnnotation = getAnnotation(m, Setup.class); + if (setupAnnotation != null) { + addSetupMethod(m); + } + } + } + + private void addSetupMethod(Method m) { + TestFormat.checkNoThrow(getAnnotation(m, Test.class) == null, + "@Setup method cannot have @Test annotation: " + m); + TestFormat.checkNoThrow(getAnnotation(m, Check.class) == null, + "@Setup method cannot have @Check annotation: " + m); + TestFormat.checkNoThrow(getAnnotation(m, Arguments.class) == null, + "@Setup method cannot have @Arguments annotation: " + m); + TestFormat.checkNoThrow(getAnnotation(m, Run.class) == null, + "@Setup method cannot have @Run annotation: " + m); + Method mOverloaded = setupMethodMap.put(m.getName(), m); + TestFormat.checkNoThrow(mOverloaded == null, + "@Setup method cannot be overloaded: " + mOverloaded + " with " + m); + m.setAccessible(true); + } + /** * Setup @Test annotated method an add them to the declaredTests map to have a convenient way of accessing them * once setting up a framework test (base checked, or custom run test). @@ -540,7 +577,8 @@ private void addDeclaredTest(Method m) { if (EXCLUDE_RANDOM) { compLevel = compLevel.excludeCompilationRandomly(m); } - DeclaredTest test = new DeclaredTest(m, ArgumentValue.getArguments(m), compLevel, warmupIterations); + ArgumentsProvider argumentsProvider = ArgumentsProviderBuilder.build(m, setupMethodMap); + DeclaredTest test = new DeclaredTest(m, argumentsProvider, compLevel, warmupIterations); declaredTests.put(m, test); testMethodMap.put(m.getName(), m); } @@ -729,7 +767,8 @@ private void checkCustomRunTest(Method m, String testName, Method testMethod, De TestFormat.check(attachedMethod == null, "Cannot use @Test " + testMethod + " for more than one @Run/@Check method. Found: " + m + ", " + attachedMethod); - TestFormat.check(!test.hasArguments(), + Arguments argumentsAnno = getAnnotation(testMethod, Arguments.class); + TestFormat.check(argumentsAnno == null, "Cannot use @Arguments at test method " + testMethod + " in combination with @Run method " + m); Warmup warmupAnno = getAnnotation(testMethod, Warmup.class); TestFormat.checkNoThrow(warmupAnno == null, diff --git a/test/hotspot/jtreg/compiler/locks/TestCoarsenedAndNestedLocksElimination.java b/test/hotspot/jtreg/compiler/locks/TestCoarsenedAndNestedLocksElimination.java new file mode 100644 index 00000000000..d1b7a2eda9b --- /dev/null +++ b/test/hotspot/jtreg/compiler/locks/TestCoarsenedAndNestedLocksElimination.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8324969 + * @summary C2 incorrectly marks unbalanced (after coarsened locks were eliminated) + * nested locks for elimination. + * @requires vm.compMode != "Xint" + * @run main/othervm -XX:-BackgroundCompilation TestCoarsenedAndNestedLocksElimination + */ + +public class TestCoarsenedAndNestedLocksElimination { + + public static void main(String[] strArr) { + for (int i = 0; i < 12000; ++i) { + test1(-1); + test2(-1); + } + } + + static synchronized int methodA(int var) { + return var; + } + + static synchronized int methodB(int var) { + return var; + } + + static int varA = 0; + static int varB = 0; + + static void test1(int var) { + synchronized (TestNestedLocksElimination.class) { + for (int i2 = 0; i2 < 3; i2++) { // Fully unrolled + varA = methodA(i2); // Nested synchronized methods also use + varB = i2 + methodB(var); // TestNestedLocksElimination.class for lock + } + } + TestNestedLocksElimination t = new TestNestedLocksElimination(); // Triggers EA + } + + static boolean test2(int var) { + synchronized (TestNestedLocksElimination.class) { + for (int i1 = 0; i1 < 100; i1++) { + switch (42) { + case 42: + short[] sArr = new short[256]; // Big enough to avoid scalarization checks + case 50: + for (int i2 = 2; i2 < 8; i2 += 2) { // Fully unrolled + for (int i3 = 1;;) { + int var1 = methodA(i2); + int var2 = i2 + methodB(i3); + break; + } + } + } + } + } + return var > 0; + } +} diff --git a/test/hotspot/jtreg/compiler/locks/TestCoarsenedAndNotEscapedLocksElimination.java b/test/hotspot/jtreg/compiler/locks/TestCoarsenedAndNotEscapedLocksElimination.java new file mode 100644 index 00000000000..4b20ddc0033 --- /dev/null +++ b/test/hotspot/jtreg/compiler/locks/TestCoarsenedAndNotEscapedLocksElimination.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8334421 + * @summary C2 incorrectly marks not-escaped locks for elimination after + * coarsened locks were eliminated and created unbalanced regions. + * @requires vm.compMode != "Xint" + * @run main/othervm -XX:-TieredCompilation TestCoarsenedAndNotEscapedLocksElimination + * @run main TestCoarsenedAndNotEscapedLocksElimination + */ + +import java.util.Vector; + +class TestVector extends Vector { + + TestVector() { + super(); + } + + TestVector(int initialCapacity) { + super(initialCapacity); + } + + TestVector(int initialCapacity, int capacityIncrement) { + super(initialCapacity, capacityIncrement); + } + + Object[] getElementData () { + return elementData; // access protected field + } +} + +public class TestCoarsenedAndNotEscapedLocksElimination { + + public static void main(String[] strArr) { + TestCoarsenedAndNotEscapedLocksElimination tc = new TestCoarsenedAndNotEscapedLocksElimination(); + String result = null; + for (int i = 0; i < 12000; ++i) { + result = tc.test(); + if (result != null) break; + } + System.out.println(result == null? "passed" : result); + } + + int [][] vector_types = { + {-1, -1}, + {0, -1}, + {1, -1}, + {2, -1}, + {1025, -1}, + {0, -2}, + {1, -2}, + {2, -2}, + {1025, -2}, + {0, 0}, + {1, 0}, + {2, 0}, + {1025, 0}, + {0, 1}, + {1, 1}, + {2, 1}, + {1025, 1}, + {0, 1025 }, + {1, 1025 }, + {2, 1025 }, + {1025, 1025 } + }; + + Object [] elems = { + null, + new Object(), + new Vector(), + new Object[0] + }; + + int cntr = 0, mode = 0; + + void reset() { + cntr = 0; + mode = 0; + } + + TestVector nextVector() { + if (cntr == vector_types.length) { + return null; + } else { + TestVector vect; + if (vector_types[cntr][0] < 0) { + vect = new TestVector(); + } else if (vector_types[cntr][1] == -2) { + vect = new TestVector(vector_types[cntr][0]); + } else { + vect = new TestVector(vector_types[cntr][0], vector_types[cntr][1]); + } + if (mode == 1) { + vect.addElement(null); + vect.addElement(new Object()); + vect.addElement(new Vector()); + vect.addElement(new Object[0]); + } else if (mode == 2) { + int cap = vect.capacity(); + vect.addElement(null); + for (int i = 0; i < cap; i++) { + vect.addElement(new Object()); + } + } + if (++mode == 3) { + mode = 0; + cntr++; + } + return vect; + } + } + + public String test() { + reset(); + TestVector vect = (TestVector)nextVector(); + while (vect != null) { + Object [] backup_array = new Object[vect.size()]; + System.arraycopy(vect.getElementData(),0,backup_array,0,vect.size()); + + int old_size = vect.size(); + vect.setSize(vect.size()); + if (vect.size() != old_size) { + return "Vector: "+vect+" size changed after setSize(size())"; + } + for (int i = 0; i < vect.size(); i++) { + if (vect.elementAt(i) != backup_array[i]) { + return "Vector: "+vect+" : "+i+"th element changed after setSize(size())"; + } + } + + old_size = vect.size(); + vect.setSize(vect.size()*2); + if (vect.size() != old_size*2) { + return "Vector: "+vect+" size incorrectly changed after setSize(size()*2)"; + } + for (int i = 0; i < old_size; i++) { + if (vect.elementAt(i) != backup_array[i]) { + return "Vector: "+vect+" : "+i+"th element changed after setSize(size()*2)"; + } + } + for (int i = old_size; i < old_size*2; i++) { + if (vect.elementAt(i) != null) { + return "Vector: "+vect+" : "+i+"th element not null after setSize(size()*2)"; + } + } + + old_size = vect.size(); + int old_cap = vect.capacity(); + vect.setSize(vect.capacity()+1); + if (vect.size() != old_cap+1) { + return "Vector: "+vect+" size incorrectly changed after setSize(capacity()+1)"; + } + for (int i = 0; i < old_size && i < backup_array.length; i++) { + if (vect.elementAt(i) != backup_array[i]) { + return "Vector: "+vect+" : "+i+"th element changed after setSize(capacity()+1)"; + } + } + for (int i = old_size; i < old_cap + 1; i++) { + if (vect.elementAt(i) != null) { + return "Vector: "+vect+" : "+i+"th element not null after setSize(capacity()+1)"; + } + } + + old_size = vect.size(); + vect.setSize(vect.size()/2); + if (vect.size() != old_size/2) { + return "Vector: "+vect+" size incorrectly changed after setSize(size()/2)"; + } + for (int i = 0; i < old_size/2 && i < backup_array.length; i++) { + if (vect.elementAt(i) != backup_array[i]) { + return "Vector: "+vect+" : "+i+"th element changed after setSize(size()/2)"; + } + } + + vect = nextVector(); + } + return null; + } + +} + diff --git a/test/hotspot/jtreg/compiler/locks/TestLocksInOSR.java b/test/hotspot/jtreg/compiler/locks/TestLocksInOSR.java new file mode 100644 index 00000000000..3516e62e46f --- /dev/null +++ b/test/hotspot/jtreg/compiler/locks/TestLocksInOSR.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8322743 + * @summary EA incorrectly marks locks for elimination for escaped object which comes from Interpreter in OSR compilation. + * @run main/othervm -XX:-TieredCompilation -Xcomp -XX:CompileCommand=compileonly,TestLocksInOSR*::* -XX:CompileCommand=quiet TestLocksInOSR + * @run main TestLocksInOSR + */ + +public class TestLocksInOSR { + + public static void main(String[] args) throws Exception { + // Triggers assert(this->held_monitor_count() == this->jni_monitor_count()) failed: held monitor count should be equal to jni: 1 != 0 + test1(); + + // Triggers assert(current->held_monitor_count() == 0) failed: Should not be possible + test2(); + } + + static void test1() throws Exception { + Thread writeThread = new Thread(new Runnable() { + @Override + public void run() { + for (int i = 0; i < 2; ++i) { + synchronized (new Object()) { + // Trigger OSR compilation + for (int j = 0; j < 100_000; ++j) { + // We still have safepoint left in code + } + } + } + } + }); + writeThread.start(); + writeThread.join(); + } + + static void test2() { + for (int i = 0; i < 2; ++i) { + synchronized (new Object()) { + // Trigger OSR compilation + for (int j = 0; j < 100_000; ++j) { + // We still have safepoint left in code + } + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/locks/TestNestedSynchronize.java b/test/hotspot/jtreg/compiler/locks/TestNestedSynchronize.java new file mode 100644 index 00000000000..874d56fc93b --- /dev/null +++ b/test/hotspot/jtreg/compiler/locks/TestNestedSynchronize.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8322996 + * @summary Ensure no assert error in C2 with deeply nested synchronize + * statements. + * @run main/othervm -XX:CompileCommand=compileonly,compiler.locks.TestNestedSynchronize::test + * -Xcomp + * compiler.locks.TestNestedSynchronize + */ + +package compiler.locks; + +public class TestNestedSynchronize { + + public static void main(String[] args) { + test(); + } + + public static void test() { + + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + synchronized (TestNestedSynchronize.class) { + + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/cr7200264/TestSSE4IntVect.java b/test/hotspot/jtreg/compiler/longcountedloops/TestInaccurateInnerLoopLimit.java similarity index 59% rename from test/hotspot/jtreg/compiler/c2/cr7200264/TestSSE4IntVect.java rename to test/hotspot/jtreg/compiler/longcountedloops/TestInaccurateInnerLoopLimit.java index a7dbbceef91..4e75859bc2a 100644 --- a/test/hotspot/jtreg/compiler/c2/cr7200264/TestSSE4IntVect.java +++ b/test/hotspot/jtreg/compiler/longcountedloops/TestInaccurateInnerLoopLimit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,21 +23,20 @@ /** * @test - * @bug 7200264 - * @summary 7192963 changes disabled shift vectors - * @requires vm.cpu.features ~= ".*sse4\\.1.*" & vm.debug & vm.flavor == "server" - * @requires !vm.emulatedClient & !vm.graal.enabled - * @library /test/lib / - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:StressLongCountedLoop=0 - * compiler.c2.cr7200264.TestSSE4IntVect + * @bug 8323972 + * @summary C2 compilation fails with assert(!x->as_Loop()->is_loop_nest_inner_loop()) failed: loop was transformed + * + * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,TestInaccurateInnerLoopLimit::test* -XX:-TieredCompilation TestInaccurateInnerLoopLimit + * */ -package compiler.c2.cr7200264; +public class TestInaccurateInnerLoopLimit { + + public static void main(String args[]) { + test(); + } -public class TestSSE4IntVect { - public static void main(String[] args) throws Throwable { - TestDriver test = new TestDriver(); - test.addExpectedVectorization("MulVI", 2); - test.run(); + public static void test() { + for (long i = 9223372034707292164L; i > 9223372034707292158L; i += -2L) { } } } diff --git a/test/hotspot/jtreg/compiler/loopopts/TestEmptyPreLoopForDifferentMainLoop.java b/test/hotspot/jtreg/compiler/loopopts/TestEmptyPreLoopForDifferentMainLoop.java new file mode 100644 index 00000000000..1843742da26 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestEmptyPreLoopForDifferentMainLoop.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 8327423 + * @summary Test empty loop removal of pre-loop, with different main-loop after it. + * @run main/othervm -Xcomp + * -XX:CompileCommand=compileonly,compiler.loopopts.TestEmptyPreLoopForDifferentMainLoop::test + * compiler.loopopts.TestEmptyPreLoopForDifferentMainLoop + * @run main compiler.loopopts.TestEmptyPreLoopForDifferentMainLoop + */ + +package compiler.loopopts; + +public class TestEmptyPreLoopForDifferentMainLoop { + static int sink; + + public static void main(String args[]) { + test(false); + } + + static void test(boolean flag) { + int x = 8; + for (int j = 0; j < 100; j++) { + for (int k = 0; k < 100; k++) { + if (flag) { + x += k; + sink = 42; + } + } + if (flag) { + break; + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestNotifyOpaqueZeroTripGuardToCmpI.java b/test/hotspot/jtreg/compiler/loopopts/TestNotifyOpaqueZeroTripGuardToCmpI.java new file mode 100644 index 00000000000..c00dea51e32 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestNotifyOpaqueZeroTripGuardToCmpI.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * 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 8316361 + * @summary Test that if input to OpaqueZeroTripGuard changes, we notify down to CmpI. + * @run main/othervm -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=10 + * -XX:CompileCommand=compileonly,compiler.loopopts.TestNotifyOpaqueZeroTripGuardToCmpI::test + * compiler.loopopts.TestNotifyOpaqueZeroTripGuardToCmpI + */ +package compiler.loopopts; + +public class TestNotifyOpaqueZeroTripGuardToCmpI { + static int x, y; + + public static void main(String[] strArr) { + test(); + } + + static void test() { + for (int i = 6; i < 43; i++) { + for (int j = i; j < 11; j++) { + x = y; + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java b/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java new file mode 100644 index 00000000000..bc0e2daff69 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestPartialPeelAtUnsignedTestsNegativeLimit.java @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=Xbatch + * @bug 8332920 + * @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit". + * @run main/othervm -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,*TestPartialPeel*::original* + * -XX:CompileCommand=compileonly,*TestPartialPeel*::test* + * compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit + */ + +/* + * @test id=Xcomp-run-inline + * @bug 8332920 + * @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit". + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,*TestPartialPeel*::original* + * -XX:CompileCommand=compileonly,*TestPartialPeel*::run* + * -XX:CompileCommand=compileonly,*TestPartialPeel*::test* + * -XX:CompileCommand=inline,*TestPartialPeelAtUnsignedTestsNegativeLimit::test* + * -XX:CompileCommand=dontinline,*TestPartialPeelAtUnsignedTestsNegativeLimit::check + * compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit + */ + +/* + * @test id=Xcomp-compile-test + * @bug 8332920 + * @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit". + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,*TestPartialPeel*::original* + * -XX:CompileCommand=compileonly,*TestPartialPeel*::test* + * compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit + */ + +/* + * @test id=vanilla + * @bug 8332920 + * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) + * @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit". + * Only run this test with C2 since it is time-consuming and only tests a C2 issue. + * @run main compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit + */ + +package compiler.loopopts; + +import java.util.Random; + +import static java.lang.Integer.*; + +public class TestPartialPeelAtUnsignedTestsNegativeLimit { + static int iFld = 10000; + static int iterations = 0; + static int iFld2; + static boolean flag; + final static Random RANDOM = new Random(); + + public static void main(String[] args) { + compareUnsigned(3, 3); // Load Integer class for -Xcomp + for (int i = 0; i < 2; i++) { + if (!originalTest()) { + throw new RuntimeException("originalTest() failed"); + } + } + + for (int i = 0; i < 2000; i++) { + // For profiling + iFld = -1; + originalTestVariation1(); + + // Actual run + iFld = MAX_VALUE - 100_000; + if (!originalTestVariation1()) { + throw new RuntimeException("originalTestVariation1() failed"); + } + } + + for (int i = 0; i < 2000; ++i) { + // For profiling + iFld = MAX_VALUE; + originalTestVariation2(); + + // Actual run + iFld = MIN_VALUE + 100000; + if (!originalTestVariation2()) { + throw new RuntimeException("originalTestVariation2() failed"); + } + } + + runWhileLTIncr(); + runWhileLTDecr(); + } + + // Originally reported simplified regression test with 2 variations (see below). + public static boolean originalTest() { + for (int i = MAX_VALUE - 50_000; compareUnsigned(i, -1) < 0; i++) { + if (compareUnsigned(MIN_VALUE, i) < 0) { + return true; + } + } + return false; + } + + public static boolean originalTestVariation1() { + int a = 0; + for (int i = iFld; compareUnsigned(i, -1) < 0; ++i) { // i = Integer.MIN_VALUE + 1 && i <= 100) { // Transformed to unsigned test. + return true; + } + a *= 23; + } + return false; + } + + public static boolean originalTestVariation2() { + int a = 0; + for (int i = iFld; compareUnsigned(i, -1000) < 0; i--) { // i 0) { + return true; + } + a = i; + } + System.out.println(a); + return false; + } + + + public static void testWhileLTIncr(int init, int limit) { + int i = init; + while (true) { + // + + // Found as loop head in ciTypeFlow, but both paths inside loop -> head not cloned. + // As a result, this head has the safepoint as backedge instead of the loop exit test + // and we cannot create a counted loop (yet). We first need to partial peel. + if (flag) { + } + + iFld2++; + + // Loop exit test i >=u limit (i.e. "while (i = limit && i >=u limit + // where the signed condition can be used as proper loop exit condition for a counted loop + // (we cannot use an unsigned counted loop exit condition). + // + // After Partial Peeling, we have: + // if (i >= limit) goto Exit + // Loop: + // if (i >=u limit) goto Exit + // ... + // i++; + // if (i >= limit) goto Exit + // goto Loop + // Exit: + // ... + // + // If init = MAX_VALUE and limit = MIN_VALUE: + // i >= limit + // MAX_VALUE >= MIN_VALUE + // which is true where + // i >=u limit + // MAX_VALUE >=u MIN_VALUE + // MAX_VALUE >=u (uint)(MAX_INT + 1) + // is false and we wrongly never enter the loop even though we should have. + // This results in a wrong execution. + if (compareUnsigned(i, limit) >= 0) { + return; + } + // <-- Partial Peeling CUT --> + // Safepoint + // + iterations++; + i++; + } + } + + // Same as testWhileLTIncr() but with decrement instead. + public static void testWhileLTDecr(int init, int limit) { + int i = init; + while (true) { + if (flag) { + } + + // Loop exit test. + if (compareUnsigned(i, limit) >= 0) { // While (i 10; --i) { + for (int j = i; j < 10; ++j) { + switch (j) { + case 1: + if (j != 0) { + return; + } + } + } + } + } + + public static void main(String[] args) { + for (int i = 0; i < 10_000; ++i) { + test(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Long.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Long.java index ea41a652940..0cbb027bf03 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Long.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Long.java @@ -25,7 +25,6 @@ * @test * @bug 8076276 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : long test - * @requires vm.bits == "64" * @library /test/lib / * @run driver compiler.loopopts.superword.SumRed_Long */ @@ -93,7 +92,8 @@ public static void sumReductionInit( @Test @IR(applyIf = {"SuperWordReductions", "false"}, failOn = {IRNode.ADD_REDUCTION_VL}) - @IR(applyIfCPUFeature = {"avx2", "true"}, + @IR(applyIfPlatform = {"32-bit", "false"}, + applyIfCPUFeature = {"avx2", "true"}, applyIfAnd = {"SuperWordReductions", "true", "LoopMaxUnroll", ">= 8"}, counts = {IRNode.ADD_REDUCTION_VL, ">= 1", IRNode.ADD_REDUCTION_VL, "<= 2"}) // one for main-loop, one for vector-post-loop public static long sumReductionImplement( diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentMainLoopAlignment.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentMainLoopAlignment.java new file mode 100644 index 00000000000..f0bdb2d2516 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentMainLoopAlignment.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8330819 + * @summary Case where VPointer finds an "adr" CastX2P, which contains a CastLL, + * that has a ctrl after the pre-loop. This value cannot be used in the + * pre-loop limit for main-loop adjustment. + * @modules java.base/jdk.internal.misc + * @modules java.base/jdk.internal.util + * @compile --enable-preview -source ${jdk.version} TestMemorySegmentMainLoopAlignment.java + * @run main/othervm --enable-preview -Xbatch compiler.loopopts.superword.TestMemorySegmentMainLoopAlignment + */ + +package compiler.loopopts.superword; + +import java.lang.foreign.*; +import jdk.internal.misc.Unsafe; +import jdk.internal.util.Preconditions; + +public class TestMemorySegmentMainLoopAlignment { + static final ValueLayout.OfInt ELEMENT_LAYOUT = ValueLayout.JAVA_INT.withByteAlignment(1); + static final Unsafe UNSAFE = Unsafe.getUnsafe(); + static long RANGE = 6400; + + // Type definition for the lambda + interface MSOp { + int apply(MemorySegment memory, long offset, int i); + } + + // Type definition for the lambda + interface MemoryUnsafeOp { + int apply(long base, long offset, int i); + } + + public static void main(String[] args) { + // Allocate some raw memory: + MemorySegment ms = Arena.ofAuto().allocate(6400, Integer.SIZE); + for (int i = 0; i < 10_000; i++) { + test1(ms, 0, TestMemorySegmentMainLoopAlignment::memorySegmentGet); + } + // Allocate some raw memory: + long base = UNSAFE.allocateMemory(6400); + for (int i = 0; i < 10_000; i++) { + test2(base, 0, TestMemorySegmentMainLoopAlignment::memoryUnsafeGet); + } + } + + // Somehow, it is necessary to pass this as a lambda + // the checkIndex inside the "get" method produces the CastLL, which eventually pins the index + // between the pre and main loop. + static int memorySegmentGet(MemorySegment ms, long o, int i) { + return ms.get(ELEMENT_LAYOUT, o + i * 4L); + } + + static int test1(MemorySegment a, long offset, MSOp f) { + // Constant size array size allows a known range for the array access/loop iv i. + int size = 16; + int[] res = new int[size]; + int sum = 0; + for (int i = 0; i < size; i++) { + // With inlining, this eventually becomes: + // sum += LoadI(MemorySegment / unsafe) + LoadI(array) + // and we attempt vectorization. + sum += f.apply(a, offset, i) + res[i]; + } + return sum; + } + + // Somehow, it is necessary to pass this as a lambda + static int memoryUnsafeGet(long base, long o, int i) { + long index = o + i * 4L; + // checkIndex -> CastLL: index >= 0. + // Together with the info about i (known range for phi), this CastLL floats up to + // the offset. Then we get adr = CastX2P(base + CastLL(offset)), where the CastLL + // is pinned between the pre and main loop. + Preconditions.checkIndex(index, RANGE, null); + return UNSAFE.getInt(base + index); + } + + static int test2(long base, long offset, MemoryUnsafeOp f) { + // Constant size array size allows a known range for the array access/loop iv i. + int size = 16; + int[] res = new int[size]; + int sum = 0; + for (int i = 0; i < size; i++) { + // With inlining, this eventually becomes: + // sum += LoadI(unsafe) + LoadI(array) + // and we attempt vectorization. + sum += f.apply(base, offset, i) + res[i]; + } + return sum; + } +} diff --git a/test/hotspot/jtreg/compiler/predicates/TestAssertionPredicateDoesntConstantFold.java b/test/hotspot/jtreg/compiler/predicates/TestAssertionPredicateDoesntConstantFold.java new file mode 100644 index 00000000000..25b15c90db7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/predicates/TestAssertionPredicateDoesntConstantFold.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8325494 + * @summary C2: Broken graph after not skipping CastII node anymore for Assertion Predicates after JDK-8309902 + * @run main/othervm -XX:-TieredCompilation -Xcomp -XX:CompileOnly=TestAssertionPredicateDoesntConstantFold::test TestAssertionPredicateDoesntConstantFold + * + */ + +public class TestAssertionPredicateDoesntConstantFold { + static boolean bFld; + static int iArrFld[]; + static long lArrFld[]; + + public static void main(String[] strArr) { + try { + test(); + } catch (NullPointerException npe) {} + } + + static long test() { + int i6 = 1, i7, i11; + do { + for (i7 = 1; i7 < 9; ++i7) { + for (i11 = 2; i6 < i11; i11 -= 2) { + if (bFld) { + break; + } + + lArrFld[i11 + 1] = 6; + iArrFld[i11 % 20] = 3; + } + } + } while (++i6 < 8); + + return i6; + } +} + diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterPartialPeeling.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterPartialPeeling.java new file mode 100644 index 00000000000..c5b99593c62 --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterPartialPeeling.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * 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 8323274 + * @summary partial peeling loop can cause an array load to become dependent on a test other than its range check + * @run main/othervm -XX:-UseOnStackReplacement -XX:-TieredCompilation -XX:-BackgroundCompilation TestArrayAccessAboveRCAfterPartialPeeling + */ + +public class TestArrayAccessAboveRCAfterPartialPeeling { + private static volatile int volatileField; + + public static void main(String[] args) { + int[] array = new int[100]; + for (int i = 0; i < 20_000; i++) { + test(array, 2, true, 1); + test(array, 2, false, 1); + inlined(array, 2, 42, true, 42, 1, 1); + inlined(array, 2, 42, false, 42, 1, 1); + } + try { + test(array, 2, true, -1); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + } + + private static int test(int[] array, int k, boolean flag, int j) { + int l; + for (l = 1; l < 2; l *= 2) { + + } + int m; + for (m = 0; m < 42; m += l) { + + } + int n; + for (n = 0; n < 10; n += m/42) { + + } + return inlined(array, k, l, flag, m, n/10, j); + } + + private static int inlined(int[] array, int k, int l, boolean flag, int m, int n, int j) { + if (array == null) { + } + int[] otherArray = new int[100]; + int i = 0; + int v = 0; + if (k == m) { + } + + if (flag) { + v += array[j]; + v += otherArray[i]; + + for (; ; ) { + synchronized (new Object()) { + } + if (j >= 100) { + break; + } + if (k == 42) { + } + v += array[j]; + v += otherArray[i]; + if (i >= n) { + otherArray[i] = v; + } + v += array[j]; + if (l == 2) { + break; + } + i++; + j *= 2; + volatileField = 42; + k = 2; + l = 42; + } + } else { + v += array[j]; + v += otherArray[i]; + + for (; ; ) { + synchronized (new Object()) { + } + if (j >= 100) { + break; + } + if (k == 42) { + } + v += array[j]; + v += otherArray[i]; + if (i >= n) { + otherArray[i] = v; + } + v += array[j]; + if (l == 2) { + break; + } + i++; + j *= 2; + volatileField = 42; + k = 2; + l = 42; + } + } + return v; + } +} diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterSinking.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterSinking.java new file mode 100644 index 00000000000..a06fb40db29 --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterSinking.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * 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 8323274 + * @summary sinking an array load out of loop can cause it to become dependent on a test other than its range check + * @run main/othervm -XX:-UseOnStackReplacement -XX:-TieredCompilation -XX:-BackgroundCompilation TestArrayAccessAboveRCAfterSinking + */ + + +import java.util.Arrays; + +public class TestArrayAccessAboveRCAfterSinking { + public static void main(String[] args) { + boolean[] allFalse = new boolean[100]; + boolean[] allTrue = new boolean[100]; + Arrays.fill(allTrue, true); + int[] array = new int[100]; + for (int i = 0; i < 20_000; i++) { + test1(allTrue, array, 0, true, 0); + test1(allTrue, array, 0, false, 0); + inlined1(allFalse, array, 2, 0); + inlined1(allFalse, array, 42, 0); + inlined1(allTrue, array, 2, 0); + test2(allTrue, array, 0, true, 0); + test2(allTrue, array, 0, false, 0); + inlined2(allFalse, array, 2, 0); + inlined2(allFalse, array, 42, 0); + inlined2(allTrue, array, 2, 0); + } + try { + test1(allTrue, array, -1, true, 0); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test2(allTrue, array, -1, true, 0); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + } + + private static int test1(boolean[] flags, int[] array, int k, boolean flag, int v) { + if (flags == null) { + } + if (array == null) { + } + int j = 1; + for (; j < 2; j *= 2) { + } + int i; + for (i = 0; i < 10; i += j) { + + } + if (flags[i - 10]) { + if (flag) { + return inlined1(flags, array, j, k); + } else { + return inlined1(flags, array, j, k) + v; + } + } + return 0; + } + + private static int inlined1(boolean[] flags, int[] array, int j, int k) { + for (int i = 0; i < 100; i++) { + final boolean flag = flags[i & (j - 3)]; + int v = array[i + k]; + if (flag) { + return v; + } + if (j + (i & (j - 2)) == 2) { + break; + } + } + return 0; + } + + private static int test2(boolean[] flags, int[] array, int k, boolean flag, int v) { + if (flags == null) { + } + if (array == null) { + } + int j = 1; + for (; j < 2; j *= 2) { + } + int i; + for (i = 0; i < 10; i += j) { + + } + if (flags[i - 10]) { + if (flag) { + return inlined2(flags, array, j, k); + } else { + return inlined2(flags, array, j, k) + v; + } + } + return 0; + } + + private static int inlined2(boolean[] flags, int[] array, int j, int k) { + for (int i = 0; i < 100; i++) { + int v = array[i + k]; + if (flags[i & (j - 3)]) { + return v; + } + if (j + (i & (j - 2)) == 2) { + break; + } + } + return 0; + } +} diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterSmearingOrPredication.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterSmearingOrPredication.java new file mode 100644 index 00000000000..97137fd1d8b --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterSmearingOrPredication.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2023, Red Hat, Inc. All rights reserved. + * 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 8319793 + * @summary Replacing a test with a dominating test can cause an array load to float above a range check that guards it + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:-TieredCompilation TestArrayAccessAboveRCAfterSmearingOrPredication + */ + + +public class TestArrayAccessAboveRCAfterSmearingOrPredication { + private static int field; + private static int flagField; + private static volatile int volatileField; + + public static void main(String[] args) { + float[] array = new float[100]; + for (int i = 0; i < 20_000; i++) { + testRangeCheckSmearing(array, 0, 1, true, true, true); + testRangeCheckSmearing(array, 0, 1, true, false, true); + testRangeCheckSmearing(array, 0, 1, false, false, true); + testRangeCheckSmearing(array, 0, 1, true, true, false); + testRangeCheckSmearing(array, 0, 1, true, false, false); + testRangeCheckSmearing(array, 0, 1, false, false, false); + testHelper(0); + + testLoopPredication(array, 0, 1, true, true, true); + testLoopPredication(array, 0, 1, true, false, true); + testLoopPredication(array, 0, 1, false, false, true); + testLoopPredication(array, 0, 1, true, true, false); + testLoopPredication(array, 0, 1, true, false, false); + testLoopPredication(array, 0, 1, false, false, false); + } + try { + testRangeCheckSmearing(array, Integer.MAX_VALUE, 1, false, false, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + testLoopPredication(array, Integer.MAX_VALUE, 1, false, false, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + } + + private static float testRangeCheckSmearing(float[] array, int i, int flag, boolean flag2, boolean flag3, boolean flag4) { + if (array == null) { + } + flagField = flag; + int j; + for (j = 0; j < 10; j++) { + } + for (int k = 0; k < 10; k++) { + for (int l = 0; l < 10; l++) { + } + } + testHelper(j); + float v = 0; + if (flag == 1) { + if (flag4) { + v += array[i]; + if (flag2) { + if (flag3) { + field = 0x42; + } + } + if (flagField == 1) { + v += array[i]; + } + } else { + v += array[i]; + if (flag2) { + if (flag3) { + field = 0x42; + } + } + if (flagField == 1) { + v += array[i]; + } + } + } + return v; + } + + private static void testHelper(int j) { + if (j == 10) { + return; + } + flagField = 0; + } + + private static float testLoopPredication(float[] array, int i, int flag, boolean flag2, boolean flag3, boolean flag4) { + i = Math.min(i, Integer.MAX_VALUE - 2); + if (array == null) { + } + flagField = flag; + int j; + for (j = 0; j < 10; j++) { + for (int k = 0; k < 10; k++) { + } + } + testHelper(j); + + float v = 0; + if (flag == 1) { + if (flag4) { + float dummy = array[i]; + dummy = array[i + 2]; + if (flag2) { + if (flag3) { + field = 0x42; + } + } + if (flagField == 1) { + for (int m = 0; m < 3; m++) { + v += array[i + m]; + } + } + volatileField = 42; + } else { + float dummy = array[i]; + dummy = array[i + 2]; + if (flag2) { + if (flag3) { + field = 0x42; + } + } + if (flagField == 1) { + for (int m = 0; m < 3; m++) { + v += array[i + m]; + } + } + volatileField = 42; + } + } + + return v; + } +} diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterSplitIf.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterSplitIf.java new file mode 100644 index 00000000000..e1e3969cfcd --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterSplitIf.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * 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 8323274 + * @summary split if can cause an array load to become dependent on a test other than its range check + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation TestArrayAccessAboveRCAfterSplitIf + */ + +public class TestArrayAccessAboveRCAfterSplitIf { + private static volatile int volatileField; + + public static void main(String[] args) { + int[] array = new int[1000]; + for (int i = 0; i < 20_000; i++) { + test1(array, array, 0, 2, true); + inlined1(42, array, array, 0, 2, 10, true); + inlined1(2, array, array, 0, 2, 10, true); + inlined1(42, array, array, 0, 2, 10, false); + inlined1(2, array, array, 0, 2, 10, false); + test2(array, array, 0, 2, true); + inlined2(42, array, array, 0, 2, 10, true); + inlined2(2, array, array, 0, 2, 10, true); + inlined2(42, array, array, 0, 2, 10, false); + inlined2(2, array, array, 0, 2, 10, false); + } + try { + test1(array, array, -1, 2, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test2(array, array, -1, 2, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + } + + private static int test1(int[] array1, int[] array2, int i, int l, boolean flag) { + for (int j = 0; j < 10; j++) { + } + int k; + for (k = 1; k < 2; k *= 2) { + + } + int m; + for (m = 0; m < 10; m+=k) { + + } + return inlined1(k, array1, array2, i, l, m, flag); + } + + private static int inlined1(int k, int[] array1, int[] array2, int i, int l, int m, boolean flag) { + int v; + int[] array; + if (array1 == null) { + } + if (l == 10) { + + } + if (flag) { + if (k == 2) { + v = array1[i]; + array = array1; + if (l == m) { + } + } else { + v = array2[i]; + array = array2; + } + v += array[i]; + v += array2[i]; + } else { + if (k == 2) { + v = array1[i]; + array = array1; + if (l == m) { + } + } else { + v = array2[i]; + array = array2; + } + v += array[i]; + v += array2[i]; + } + return v; + } + + private static int test2(int[] array1, int[] array2, int i, int l, boolean flag) { + for (int j = 0; j < 10; j++) { + } + int k; + for (k = 1; k < 2; k *= 2) { + + } + int m; + for (m = 0; m < 10; m+=k) { + + } + return inlined2(k, array1, array2, i, l, m, flag); + } + + private static int inlined2(int k, int[] array1, int[] array2, int i, int l, int m, boolean flag) { + int v; + int[] array; + if (array1 == null) { + } + if (l == 10) { + + } + if (flag) { + if (k == 2) { + v = array1[i]; + array = array1; + if (l == m) { + } + } else { + v = array2[i]; + array = array2; + } + if (Integer.compareUnsigned(i, array.length) >= 0) { + } + v += array[i]; + v += array2[i]; + } else { + if (k == 2) { + v = array1[i]; + array = array1; + if (l == m) { + } + } else { + v = array2[i]; + array = array2; + } + if (Integer.compareUnsigned(i, array.length) >= 0) { + } + v += array[i]; + v += array2[i]; + } + return v; + } +} diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterUnswitching.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterUnswitching.java new file mode 100644 index 00000000000..1fc7111ff82 --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterUnswitching.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * 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 8323274 + * @summary loop unswitching can cause an array load to become dependent on a test other than its range check + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:CompileOnly=TestArrayAccessAboveRCAfterUnswitching::test + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:StressSeed=148059521 TestArrayAccessAboveRCAfterUnswitching + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:CompileOnly=TestArrayAccessAboveRCAfterUnswitching::test + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM TestArrayAccessAboveRCAfterUnswitching + */ + +import java.util.Arrays; + +public class TestArrayAccessAboveRCAfterUnswitching { + private static int field; + + public static void main(String[] args) { + int[] array = new int[1000]; + boolean[] allFalse = new boolean[1000]; + boolean[] allTrue = new boolean[1000]; + Arrays.fill(allTrue, true); + for (int i = 0; i < 20_000; i++) { + inlined(array, allFalse, 42, 2, 2, 0); + inlined(array, allFalse, 2, 42, 2, 0); + inlined(array, allFalse, 2, 2, 2, 0); + inlined(array, allFalse, 2, 2, 42, 0); + inlined(array, allTrue, 2, 2, 2, 0); + test(array, allTrue, 0); + } + try { + test(array, allTrue, -1); + } catch (ArrayIndexOutOfBoundsException aioobe) { + } + } + + private static int test(int[] array, boolean[] flags, int start) { + if (flags == null) { + } + if (array == null) { + } + int j = 1; + for (; j < 2; j *= 2) { + } + int k = 1; + for (; k < 2; k *= 2) { + } + int l = 1; + for (; l < 2; l *= 2) { + } + int i; + for (i = 0; i < 10; i += l) { + + } + if (flags[i - 10]) { + return inlined(array, flags, j, k, l, start); + } + return 0; + } + + private static int inlined(int[] array, boolean[] flags, int j, int k, int l, int start) { + for (int i = 0; i < 100; i++) { + final boolean flag = flags[i & (j - 3)]; + int v = array[(i + start) & (j - 3)]; + if (flag) { + return v; + } + if (j != 2) { + field = v; + } else { + if (k != 2) { + field = 42; + } else { + if (l == 2) { + break; + } + } + } + } + return 0; + } +} diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCForArrayCopyLoad.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCForArrayCopyLoad.java new file mode 100644 index 00000000000..46438579f4a --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCForArrayCopyLoad.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * 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 8323274 + * @summary converting an array copy to a series of loads/stores add loads that can float + * @run main/othervm -XX:-UseOnStackReplacement -XX:-TieredCompilation -XX:-BackgroundCompilation TestArrayAccessAboveRCForArrayCopyLoad + */ + +public class TestArrayAccessAboveRCForArrayCopyLoad { + public static void main(String[] args) { + int[] array = new int[10]; + for (int i = 0; i < 20_000; i++) { + test(array, 0, array, 1, false); + test(array, 0, array, 1, true); + } + try { + test(array, -1, array, 0, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + + } + } + + private static void test(int[] src, int srcPos, int[] dst, int dstPos, boolean flag) { + if (src == null) { + } + if (srcPos < dstPos) { + if (flag) { + System.arraycopy(src, srcPos, dst, dstPos, 2); + } else { + System.arraycopy(src, srcPos, dst, dstPos, 2); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessCastIIAboveRC.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessCastIIAboveRC.java new file mode 100644 index 00000000000..e8eb1e16a7a --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessCastIIAboveRC.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023, Red Hat, Inc. All rights reserved. + * 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 8319793 + * @summary Replacing a test with a dominating test can cause an array access CastII to float above a range check that guards it + * @run main/othervm -Xbatch -XX:-TieredCompilation TestArrayAccessCastIIAboveRC + */ + +public class TestArrayAccessCastIIAboveRC { + static int N = 400; + static int iArrFld[] = new int[N]; + + static void test() { + float fArr[] = new float[N]; + int i9, i10, i12; + long lArr1[] = new long[N]; + for (i9 = 7; i9 < 43; i9++) { + try { + i10 = 7 % i9; + iArrFld[i9 + 1] = i9 / i10; + } catch (ArithmeticException a_e) { + } + for (i12 = 1; 7 > i12; i12++) + lArr1[i9 - 1] = 42; + iArrFld[i12] = 4; + fArr[i9 - 1] = 0; + } + } + + public static void main(String[] args) { + for (int i = 0; i < 50_000; ++i) { + test(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckHoistingScaledIV.java b/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckHoistingScaledIV.java index 390a0dcdd3f..e8759a2bee1 100644 --- a/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckHoistingScaledIV.java +++ b/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckHoistingScaledIV.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Arm Limited. All rights reserved. + * Copyright (c) 2022, 2023, Arm Limited. All rights reserved. * 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,6 +26,7 @@ * @bug 8289996 * @summary Test range check hoisting for some scaled iv at array index * @library /test/lib / + * @requires vm.flagless * @requires vm.debug & vm.compiler2.enabled & (os.simpleArch == "x64" | os.arch == "aarch64") * @modules jdk.incubator.vector * @compile --enable-preview -source ${jdk.version} TestRangeCheckHoistingScaledIV.java diff --git a/test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloaded.java b/test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloaded.java new file mode 100644 index 00000000000..8a1be961c80 --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloaded.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8322726 + * @library /test/lib + * @modules java.base/jdk.internal.org.objectweb.asm + * + * @compile TestMHUnloaded.java TestMHUnloadedHelper.java + * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.runtime.unloaded.TestMHUnloadedHelper + * + * @run main/othervm -Xbootclasspath/a:. + * -Xbatch -XX:-TieredCompilation -XX:CompileCommand=exclude,*::test + * -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining + * compiler.runtime.unloaded.TestMHUnloaded + * + * @run main/othervm -Xbootclasspath/a:. + * -Xbatch -XX:-TieredCompilation -XX:CompileCommand=exclude,*::test + * -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining + * -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline + * compiler.runtime.unloaded.TestMHUnloaded + */ + +package compiler.runtime.unloaded; + +import java.lang.invoke.MethodHandles; + +public class TestMHUnloaded { + public static void main(String[] args) { + TestMHUnloadedHelper.test(MethodHandles.lookup()); // launch test in bootstrap loader context + TestMHUnloadedHelper.testConstant(MethodHandles.lookup()); // launch test in bootstrap loader context + System.out.println("TEST PASSED"); + } +} diff --git a/test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloadedHelper.java b/test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloadedHelper.java new file mode 100644 index 00000000000..176945572e8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/unloaded/TestMHUnloadedHelper.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.runtime.unloaded; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.function.BiPredicate; +import jdk.internal.org.objectweb.asm.ClassWriter; + +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +// Operates in bootstrap loader context. +public class TestMHUnloadedHelper { + private static final MethodType METHOD_TYPE = MethodType.methodType(BiPredicate.class, + BiPredicate.class, BiPredicate.class); + + static byte[] generateClassFile(Class caller) { + var cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + String name = caller.getName().replace('.', '/'); + cw.visit(V19, ACC_PUBLIC | ACC_SUPER, name, null, "java/lang/Object", null); + { + var mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "test", METHOD_TYPE.toMethodDescriptorString(), null, null); + mv.visitCode(); + mv.visitIntInsn(ALOAD, 1); + mv.visitInsn(ARETURN); + mv.visitMaxs(0, 0); + } + return cw.toByteArray(); + } + + public static MethodHandle generateTest(MethodHandles.Lookup caller) { + // Loaded in the caller context. + byte[] classBytes = generateClassFile(caller.lookupClass()); + try { + MethodHandles.Lookup lookup = caller.defineHiddenClass(classBytes, true); + MethodHandle test = lookup.findStatic(lookup.lookupClass(), "test", METHOD_TYPE); + test = MethodHandles.permuteArguments(test, test.type(), 1, 0); // mix arguments + return test; + } catch (Throwable e) { + throw new AssertionError(e); + } + } + + static BiPredicate[] ps = new BiPredicate[] { (a, b) -> false, + (a, b) -> true }; + + public static void test(MethodHandles.Lookup caller) { + MethodHandle test = generateTest(caller); + + for (int i = 0; i < 20_000; i++) { + try { + BiPredicate pr = (BiPredicate)test.invokeExact(ps[1], ps[0]); + if (pr != ps[1]) { + throw new AssertionError("mismatch"); + } + } catch (Throwable e) { + throw new AssertionError(e); + } + } + } + + public static void testConstant(MethodHandles.Lookup caller) { + MethodHandle test = generateTest(caller); + + // testMH() { return test(ps2, ps1); } where test(a, b) { return b; }. + test = test.bindTo(ps[1]).bindTo(ps[0]); // make argument concrete types visible to the JIT-compiler + + for (int i = 0; i < 20_000; i++) { + try { + BiPredicate pr = (BiPredicate)test.invokeExact(); + if (pr != ps[1]) { + throw new AssertionError("mismatch"); + } + } catch (Throwable e) { + throw new AssertionError(e); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/splitif/TestLongCountedLoopConvL2I.java b/test/hotspot/jtreg/compiler/splitif/TestLongCountedLoopConvL2I.java new file mode 100644 index 00000000000..957ebaf4531 --- /dev/null +++ b/test/hotspot/jtreg/compiler/splitif/TestLongCountedLoopConvL2I.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * 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 8331575 + * @summary C2: crash when ConvL2I is split thru phi at LongCountedLoop + * @run main/othervm -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:-UseOnStackReplacement + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:StressSeed=92643864 TestLongCountedLoopConvL2I + * @run main/othervm -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:-UseOnStackReplacement + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM TestLongCountedLoopConvL2I + * @run main/othervm -XX:-BackgroundCompilation -XX:-TieredCompilation + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM TestLongCountedLoopConvL2I + */ + +public class TestLongCountedLoopConvL2I { + private static volatile int volatileField; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + testHelper1(42); + test1(0); + } + } + + private static int test1(int res) { + int k = 1; + for (; k < 2; k *= 2) { + } + long i = testHelper1(k); + for (; i > 0; i--) { + res += 42 / ((int) i); + for (int j = 1; j < 10; j *= 2) { + + } + } + return res; + } + + private static long testHelper1(int k) { + if (k == 2) { + return 100; + } else { + return 99; + } + } +} diff --git a/test/hotspot/jtreg/compiler/splitif/TestLongCountedLoopConvL2I2.java b/test/hotspot/jtreg/compiler/splitif/TestLongCountedLoopConvL2I2.java new file mode 100644 index 00000000000..311dbdfb19b --- /dev/null +++ b/test/hotspot/jtreg/compiler/splitif/TestLongCountedLoopConvL2I2.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * 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 8331575 + * @summary C2: crash when ConvL2I is split thru phi at LongCountedLoop + * @run main/othervm -Xcomp -XX:CompileOnly=TestLongCountedLoopConvL2I2.* TestLongCountedLoopConvL2I2 + */ + +public class TestLongCountedLoopConvL2I2 { + static int x = 34; + + public static void main(String[] strArr) { + for (int i = 0; i < 2; i++) { + test(); + } + } + + static int test() { + int a = 5, b = 6; + long lArr[] = new long[2]; + + for (long i = 159; i > 1; i -= 3) { + a += 3; + for (int j = 1; j < 4; j++) { + if (a == 9) { + if (x == 73) { + try { + b = 10 / (int) i; + } catch (ArithmeticException a_e) { + } + } + } + } + } + return b; + } +} diff --git a/test/hotspot/jtreg/compiler/unsafe/UnsafeArrayCopy.java b/test/hotspot/jtreg/compiler/unsafe/UnsafeArrayCopy.java new file mode 100644 index 00000000000..ac94609be34 --- /dev/null +++ b/test/hotspot/jtreg/compiler/unsafe/UnsafeArrayCopy.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8316756 + * @summary Test UNSAFE.copyMemory in combination with Escape Analysis + * @library /test/lib + * + * @modules java.base/jdk.internal.misc + * + * @run main/othervm -XX:-TieredCompilation -Xbatch -XX:CompileCommand=quiet -XX:CompileCommand=compileonly,compiler.unsafe.UnsafeArrayCopy::test* + * compiler.unsafe.UnsafeArrayCopy + */ + +package compiler.unsafe; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.misc.Unsafe; + + +public class UnsafeArrayCopy { + + private static Unsafe UNSAFE = Unsafe.getUnsafe(); + + static long SRC_BASE = UNSAFE.allocateMemory(4); + static long DST_BASE = UNSAFE.allocateMemory(4); + + static class MyClass { + int x; + } + + static int test() { + MyClass obj = new MyClass(); // Non-escaping to trigger Escape Analysis + UNSAFE.copyMemory(null, SRC_BASE, null, DST_BASE, 4); + obj.x = 42; + return obj.x; + } + + static int[] test2() { + int[] src = new int[4]; + int[] dst = new int[4]; + MyClass obj = new MyClass(); + UNSAFE.copyMemory(src, 0, dst, 0, 4); + obj.x = 42; + dst[1] = obj.x; + return dst; + } + + public static void main(String[] args) { + for (int i = 0; i < 50_000; ++i) { + test(); + test2(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java b/test/hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java index ddd47c9d56c..b6bcd2d5631 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2021, 2022, THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +38,18 @@ * -XX:-TieredCompilation compiler.vectorapi.TestIntrinsicBailOut */ +/* + * @test + * @enablePreview + * @bug 8317299 + * @summary Vector API intrinsincs should handle JVM state correctly whith late inlining when compiling with -InlineUnsafeOps + * @modules jdk.incubator.vector + * @requires vm.cpu.features ~= ".*avx512.*" + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:-InlineUnsafeOps -XX:+IgnoreUnrecognizedVMOptions -XX:UseAVX=3 + * -XX:CompileCommand=compileonly,compiler.vectorapi.TestIntrinsicBailOut::test -XX:CompileCommand=quiet + * -XX:-TieredCompilation compiler.vectorapi.TestIntrinsicBailOut + */ + public class TestIntrinsicBailOut { static final VectorSpecies SPECIES256 = DoubleVector.SPECIES_256; diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestIsLoadVector.java b/test/hotspot/jtreg/compiler/vectorapi/TestIsLoadVector.java new file mode 100644 index 00000000000..bcf560ca09b --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestIsLoadVector.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.vectorapi; + +/* + * @test + * @bug 8333099 + * @summary We should check for is_LoadVector before checking for equality between vector types + * @run main/othervm -XX:CompileCommand=compileonly,compiler.vectorapi.TestIsLoadVector::test -Xcomp compiler.vectorapi.TestIsLoadVector + */ + +public class TestIsLoadVector { + static int[] iArrFld = new int[400]; + + static void test() { + int i13, i16 = 3; + short s = 50; + for (int i = 0; i < 4; i++) { + for (int i12 = 0; i12 < 8; ++i12) { + for (int i14 = 2; 82 > i14; i14++) { + s <<= 90; + do { + try { + i13 = 0; + } catch (ArithmeticException a_e) { + } + } while (++i16 < 2); + } + } + } + int i18 = 1; + while (++i18 < 41) { + iArrFld[i18] >>= s; + } + } + + public static void main(String[] strArr) { + for (int i = 0; i < 100; i++) { + test(); + } + } +} \ No newline at end of file diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java new file mode 100644 index 00000000000..88d1bbde1d4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java @@ -0,0 +1,1404 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.vectorapi; + +import compiler.lib.ir_framework.*; + +import jdk.test.lib.Asserts; +import jdk.incubator.vector.*; +import java.util.Arrays; +import java.nio.ByteOrder; + +/** + * @test + * @bug 8325520 + * @library /test/lib / + * @summary Don't allow folding of Load/Store vectors when using incompatible indices or masks + * @modules jdk.incubator.vector + * + * @run driver compiler.vectorapi.VectorGatherMaskFoldingTest + */ + +public class VectorGatherMaskFoldingTest { + // Species + private static final VectorSpecies L_SPECIES = LongVector.SPECIES_MAX; + private static final VectorSpecies I_SPECIES = IntVector.SPECIES_MAX; + private static final VectorSpecies F_SPECIES = FloatVector.SPECIES_MAX; + private static final VectorSpecies D_SPECIES = DoubleVector.SPECIES_MAX; + // Vectors + private static final LongVector longVector; + private static final LongVector longVector2; + private static final IntVector intVector; + private static final IntVector intVector2; + private static final DoubleVector doubleVector; + private static final DoubleVector doubleVector2; + private static final FloatVector floatVector; + private static final FloatVector floatVector2; + // Arrays + private static final long[] longArray = new long[L_SPECIES.length()]; + private static final long[] longArray2 = new long[L_SPECIES.length()]; + private static final int[] intArray = new int[I_SPECIES.length()]; + private static final int[] intArray2 = new int[I_SPECIES.length()]; + private static final double[] doubleArray = new double[D_SPECIES.length()]; + private static final double[] doubleArray2 = new double[D_SPECIES.length()]; + private static final float[] floatArray = new float[F_SPECIES.length()]; + private static final float[] floatArray2 = new float[F_SPECIES.length()]; + // Indices + private static final int[] longIndices = new int[L_SPECIES.length()]; + private static final int[] longIndices2 = new int[L_SPECIES.length()]; + private static final int[] duplicateLongIndices = new int[L_SPECIES.length()]; + private static final int[] intIndices = new int[I_SPECIES.length()]; + private static final int[] intIndices2 = new int[I_SPECIES.length()]; + private static final int[] duplicateIntIndices = new int[I_SPECIES.length()]; + private static final int[] doubleIndices = new int[D_SPECIES.length()]; + private static final int[] doubleIndices2 = new int[D_SPECIES.length()]; + private static final int[] duplicateDoubleIndices = new int[D_SPECIES.length()]; + private static final int[] floatIndices = new int[F_SPECIES.length()]; + private static final int[] floatIndices2 = new int[F_SPECIES.length()]; + private static final int[] duplicateFloatIndices = new int[F_SPECIES.length()]; + // Masks + private static final boolean[] longMask = new boolean[L_SPECIES.length()]; + private static final boolean[] longMask2 = new boolean[L_SPECIES.length()]; + private static final boolean[] intMask = new boolean[I_SPECIES.length()]; + private static final boolean[] intMask2 = new boolean[I_SPECIES.length()]; + private static final boolean[] doubleMask = new boolean[D_SPECIES.length()]; + private static final boolean[] doubleMask2 = new boolean[D_SPECIES.length()]; + private static final boolean[] floatMask = new boolean[F_SPECIES.length()]; + private static final boolean[] floatMask2 = new boolean[F_SPECIES.length()]; + private static final VectorMask longVectorMask; + private static final VectorMask longVectorMask2; + private static final VectorMask intVectorMask; + private static final VectorMask intVectorMask2; + private static final VectorMask doubleVectorMask; + private static final VectorMask doubleVectorMask2; + private static final VectorMask floatVectorMask; + private static final VectorMask floatVectorMask2; + + // Filling vectors/indices/masks + static { + for (int i = 0; i < L_SPECIES.length(); i++) { + longArray[i] = i + 1; + longArray2[i] = L_SPECIES.length() - i + 1; + longMask[i] = i % 2 == 0; + longMask2[i] = i >= L_SPECIES.length() / 2; + longIndices[i] = (i + L_SPECIES.length() / 2) % L_SPECIES.length(); + longIndices2[i] = (L_SPECIES.length() - i) % L_SPECIES.length(); + duplicateLongIndices[i] = longIndices[i] / 2; + } + longVector = LongVector.fromArray(L_SPECIES, longArray, 0); + longVector2 = LongVector.fromArray(L_SPECIES, longArray2, 0); + longVectorMask = VectorMask.fromArray(L_SPECIES, longMask, 0); + longVectorMask2 = VectorMask.fromArray(L_SPECIES, longMask2, 0); + for (int i = 0; i < I_SPECIES.length(); i++) { + intArray[i] = i + 1; + intArray2[i] = I_SPECIES.length() - i + 1; + intMask[i] = i % 2 == 0; + intMask2[i] = i >= I_SPECIES.length() / 2; + intIndices[i] = (i + I_SPECIES.length() / 2) % I_SPECIES.length(); + intIndices2[i] = (I_SPECIES.length() - i) % I_SPECIES.length(); + duplicateIntIndices[i] = intIndices[i] / 2; + } + intVector = IntVector.fromArray(I_SPECIES, intArray, 0); + intVector2 = IntVector.fromArray(I_SPECIES, intArray2, 0); + intVectorMask = VectorMask.fromArray(I_SPECIES, intMask, 0); + intVectorMask2 = VectorMask.fromArray(I_SPECIES, intMask2, 0); + for (int i = 0; i < D_SPECIES.length(); i++) { + doubleArray[i] = (double) i + 1.0; + doubleArray2[i] = (double) (D_SPECIES.length() - i) + 1.0; + doubleMask[i] = i % 2 == 0; + doubleMask2[i] = i >= D_SPECIES.length() / 2; + doubleIndices[i] = (i + D_SPECIES.length() / 2) % D_SPECIES.length(); + doubleIndices2[i] = (D_SPECIES.length() - i) % D_SPECIES.length(); + duplicateDoubleIndices[i] = doubleIndices[i] / 2; + } + doubleVector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + doubleVector2 = DoubleVector.fromArray(D_SPECIES, doubleArray2, 0); + doubleVectorMask = VectorMask.fromArray(D_SPECIES, doubleMask, 0); + doubleVectorMask2 = VectorMask.fromArray(D_SPECIES, doubleMask2, 0); + for (int i = 0; i < F_SPECIES.length(); i++) { + floatArray[i] = i + 1.0f; + floatArray2[i] = F_SPECIES.length() - i + 1.0f; + floatMask[i] = i % 2 == 0; + floatMask2[i] = i >= F_SPECIES.length() / 2; + floatIndices[i] = (i + F_SPECIES.length() / 2) % F_SPECIES.length(); + floatIndices2[i] = (F_SPECIES.length() - i) % F_SPECIES.length(); + duplicateFloatIndices[i] = floatIndices[i] / 2; + } + floatVector = FloatVector.fromArray(F_SPECIES, floatArray, 0); + floatVector2 = FloatVector.fromArray(F_SPECIES, floatArray2, 0); + floatVectorMask = VectorMask.fromArray(F_SPECIES, floatMask, 0); + floatVectorMask2 = VectorMask.fromArray(F_SPECIES, floatMask2, 0); + } + + // LOAD TESTS + + // LongVector tests + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherNotEqualArray() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray2, 0, longIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherNotEqualIndices() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices2, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneLongVectorLoadGather() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneLongVectorLoadMasked() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherEquals() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadMaskedEquals() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadMaskedNotEqualMask() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherMaskedEquals() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherMaskedNotEqualMask() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherMaskedNotEqualIndices() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices2, 0, longVectorMask); + Asserts.assertNotEquals(res, res2); + } + + + // IntVector tests + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherNotEqualArray() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray2, 0, intIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherNotEqualIndices() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices2, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneIntVectorLoadGather() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneIntVectorLoadMasked() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherEquals() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadMaskedEquals() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadMaskedNotEqualMask() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherMaskedEquals() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherMaskedNotEqualMask() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherMaskedNotEqualIndices() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices2, 0, intVectorMask); + Asserts.assertNotEquals(res, res2); + } + + + // DoubleVector tests + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherNotEqualArray() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray2, 0, doubleIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherNotEqualIndices() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices2, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_D, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadGather() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_D, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadMasked() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherEquals() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadMaskedEquals() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadMaskedNotEqualMask() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherMaskedEquals() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherMaskedNotEqualMask() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherMaskedNotEqualIndices() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices2, 0, doubleVectorMask); + Asserts.assertNotEquals(res, res2); + } + + + // FloatVector tests + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherNotEqualArray() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray2, 0, floatIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherNotEqualIndices() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices2, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_F, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneFloatVectorLoadGather() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_F, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneFloatVectorLoadMasked() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherEquals() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadMaskedEquals() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadMaskedNotEqualMask() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherMaskedEquals() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherMaskedNotEqualMask() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherMaskedNotEqualIndices() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices2, 0, floatVectorMask); + Asserts.assertNotEquals(res, res2); + } + + + // STORE TESTS + + // LongVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterNotEqualVector() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0); + longVector2.intoArray(res2, 0, longIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterNotEqualIndices() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0); + longVector.intoArray(res2, 0, longIndices2, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreScatter() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0); + longVector.intoArray(res2, 0, longIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreMasked() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0); + longVector.intoArray(res2, 0, longVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterEquals() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0); + longVector.intoArray(res2, 0, longIndices, 0); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreMaskedEquals() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longVectorMask); + longVector.intoArray(res2, 0, longVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreMaskedNotEqualMask() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longVectorMask); + longVector.intoArray(res2, 0, longVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterMaskedEquals() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0, longVectorMask); + longVector.intoArray(res2, 0, longIndices, 0, longVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterMaskedNotEqualMask() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0, longVectorMask); + longVector.intoArray(res2, 0, longIndices, 0, longVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterMaskedNotEqualIndices() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0, longVectorMask); + longVector.intoArray(res2, 0, longIndices2, 0, longVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + + // IntVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterNotEqualVector() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0); + intVector2.intoArray(res2, 0, intIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterNotEqualIndices() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0); + intVector.intoArray(res2, 0, intIndices2, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreScatter() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0); + intVector.intoArray(res2, 0, intIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreMasked() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0); + intVector.intoArray(res2, 0, intVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterEquals() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0); + intVector.intoArray(res2, 0, intIndices, 0); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreMaskedEquals() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intVectorMask); + intVector.intoArray(res2, 0, intVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreMaskedNotEqualMask() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intVectorMask); + intVector.intoArray(res2, 0, intVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterMaskedEquals() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0, intVectorMask); + intVector.intoArray(res2, 0, intIndices, 0, intVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterMaskedNotEqualMask() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0, intVectorMask); + intVector.intoArray(res2, 0, intIndices, 0, intVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterMaskedNotEqualIndices() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0, intVectorMask); + intVector.intoArray(res2, 0, intIndices2, 0, intVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + + // DoubleVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterNotEqualVector() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0); + doubleVector2.intoArray(res2, 0, doubleIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterNotEqualIndices() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0); + doubleVector.intoArray(res2, 0, doubleIndices2, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreScatter() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0); + doubleVector.intoArray(res2, 0, doubleIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreMasked() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0); + doubleVector.intoArray(res2, 0, doubleVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterEquals() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0); + doubleVector.intoArray(res2, 0, doubleIndices, 0); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreMaskedEquals() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreMaskedNotEqualMask() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterMaskedEquals() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleIndices, 0, doubleVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterMaskedNotEqualMask() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleIndices, 0, doubleVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterMaskedNotEqualIndices() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleIndices2, 0, doubleVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + + // FloatVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterNotEqualVector() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0); + floatVector2.intoArray(res2, 0, floatIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterNotEqualIndices() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0); + floatVector.intoArray(res2, 0, floatIndices2, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreScatter() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0); + floatVector.intoArray(res2, 0, floatIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreMasked() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0); + floatVector.intoArray(res2, 0, floatVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterEquals() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0); + floatVector.intoArray(res2, 0, floatIndices, 0); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreMaskedEquals() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreMaskedNotEqualMask() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterMaskedEquals() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatIndices, 0, floatVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterMaskedNotEqualMask() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatIndices, 0, floatVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterMaskedNotEqualIndices() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatIndices2, 0, floatVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + + // STORE - LOAD tests + + // LongVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreLoadGather() { + long[] array = new long[L_SPECIES.length()]; + longVector.intoArray(array, 0); + LongVector res = LongVector.fromArray(L_SPECIES, array, 0, longIndices, 0); + Asserts.assertNotEquals(res, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreScatterLoad() { + long[] array = new long[L_SPECIES.length()]; + longVector.intoArray(array, 0, longIndices, 0); + LongVector res = LongVector.fromArray(L_SPECIES, array, 0); + Asserts.assertNotEquals(res, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreLoadMasked() { + long[] array = new long[L_SPECIES.length()]; + longVector.intoArray(array, 0); + LongVector res = LongVector.fromArray(L_SPECIES, array, 0, longVectorMask); + Asserts.assertNotEquals(res, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreMaskedLoad() { + long[] array = new long[L_SPECIES.length()]; + longVector.intoArray(array, 0, longVectorMask); + LongVector res = LongVector.fromArray(L_SPECIES, array, 0); + Asserts.assertNotEquals(res, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testLongVectorLoadGatherStoreScatterDuplicateIndicesVector() { + long[] res = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, duplicateLongIndices, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, res, 0, duplicateLongIndices, 0); + Asserts.assertNotEquals(res2, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testLongVectorStoreLoadMaskedVector() { + long[] res = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, res, 0, longVectorMask); + Asserts.assertNotEquals(res2, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testStoreLoadLongVectorDifferentSpeciesVector() { + long[] res = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0); + LongVector res2 = LongVector.fromArray(LongVector.SPECIES_64, res, 0); + Asserts.assertNotEquals(res2, longVector); + } + + + // IntVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreLoadGather() { + int[] array = new int[I_SPECIES.length()]; + intVector.intoArray(array, 0); + IntVector res = IntVector.fromArray(I_SPECIES, array, 0, intIndices, 0); + Asserts.assertNotEquals(res, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreScatterLoad() { + int[] array = new int[I_SPECIES.length()]; + intVector.intoArray(array, 0, intIndices, 0); + IntVector res = IntVector.fromArray(I_SPECIES, array, 0); + Asserts.assertNotEquals(res, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreLoadMasked() { + int[] array = new int[I_SPECIES.length()]; + intVector.intoArray(array, 0); + IntVector res = IntVector.fromArray(I_SPECIES, array, 0, intVectorMask); + Asserts.assertNotEquals(res, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreMaskedLoad() { + int[] array = new int[I_SPECIES.length()]; + intVector.intoArray(array, 0, intVectorMask); + IntVector res = IntVector.fromArray(I_SPECIES, array, 0); + Asserts.assertNotEquals(res, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testIntVectorLoadGatherStoreScatterDuplicateIndicesVector() { + int[] res = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, duplicateIntIndices, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, res, 0, duplicateIntIndices, 0); + Asserts.assertNotEquals(res2, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testIntVectorStoreLoadMaskedVector() { + int[] res = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, res, 0, intVectorMask); + Asserts.assertNotEquals(res2, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testStoreLoadIntVectorDifferentSpeciesVector() { + int[] res = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0); + IntVector res2 = IntVector.fromArray(IntVector.SPECIES_64, res, 0); + Asserts.assertNotEquals(res2, intVector); + } + + + // DoubleVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreLoadGather() { + double[] array = new double[D_SPECIES.length()]; + doubleVector.intoArray(array, 0); + DoubleVector res = DoubleVector.fromArray(D_SPECIES, array, 0, doubleIndices, 0); + Asserts.assertNotEquals(res, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreScatterLoad() { + double[] array = new double[D_SPECIES.length()]; + doubleVector.intoArray(array, 0, doubleIndices, 0); + DoubleVector res = DoubleVector.fromArray(D_SPECIES, array, 0); + Asserts.assertNotEquals(res, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreLoadMasked() { + double[] array = new double[D_SPECIES.length()]; + doubleVector.intoArray(array, 0); + DoubleVector res = DoubleVector.fromArray(D_SPECIES, array, 0, doubleVectorMask); + Asserts.assertNotEquals(res, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreMaskedLoad() { + double[] array = new double[D_SPECIES.length()]; + doubleVector.intoArray(array, 0, doubleVectorMask); + DoubleVector res = DoubleVector.fromArray(D_SPECIES, array, 0); + Asserts.assertNotEquals(res, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testDoubleVectorLoadGatherStoreScatterDuplicateIndicesVector() { + double[] res = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, duplicateDoubleIndices, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, res, 0, duplicateDoubleIndices, 0); + Asserts.assertNotEquals(res2, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testDoubleVectorStoreLoadMaskedVector() { + double[] res = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, res, 0, doubleVectorMask); + Asserts.assertNotEquals(res2, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testStoreLoadDoubleVectorDifferentSpeciesVector() { + double[] res = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0); + DoubleVector res2 = DoubleVector.fromArray(DoubleVector.SPECIES_64, res, 0); + Asserts.assertNotEquals(res2, doubleVector); + } + + + // FloatVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreLoadGather() { + float[] array = new float[F_SPECIES.length()]; + floatVector.intoArray(array, 0); + FloatVector res = FloatVector.fromArray(F_SPECIES, array, 0, floatIndices, 0); + Asserts.assertNotEquals(res, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreScatterLoad() { + float[] array = new float[F_SPECIES.length()]; + floatVector.intoArray(array, 0, floatIndices, 0); + FloatVector res = FloatVector.fromArray(F_SPECIES, array, 0); + Asserts.assertNotEquals(res, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreLoadMasked() { + float[] array = new float[F_SPECIES.length()]; + floatVector.intoArray(array, 0); + FloatVector res = FloatVector.fromArray(F_SPECIES, array, 0, floatVectorMask); + Asserts.assertNotEquals(res, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreMaskedLoad() { + float[] array = new float[F_SPECIES.length()]; + floatVector.intoArray(array, 0, floatVectorMask); + FloatVector res = FloatVector.fromArray(F_SPECIES, array, 0); + Asserts.assertNotEquals(res, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testFloatVectorLoadGatherStoreScatterDuplicateIndicesVector() { + float[] res = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, duplicateFloatIndices, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, res, 0, duplicateFloatIndices, 0); + Asserts.assertNotEquals(res2, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testFloatVectorStoreLoadMaskedVector() { + float[] res = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, res, 0, floatVectorMask); + Asserts.assertNotEquals(res2, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testStoreLoadFloatVectorDifferentSpeciesVector() { + float[] res = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0); + FloatVector res2 = FloatVector.fromArray(FloatVector.SPECIES_64, res, 0); + Asserts.assertNotEquals(res2, floatVector); + } + + + // LOAD - STORE tests + + // LongVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorLoadGatherStore() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorLoadStoreScatter() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0); + vector.intoArray(res, 0, longIndices, 0); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorLoadMaskedStore() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorLoadStoreMasked() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0); + vector.intoArray(res, 0, longVectorMask); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testLongVectorStoreScatterLoadGatherDuplicateIndicesVector() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0, duplicateLongIndices, 0); + vector.intoArray(res, 0, duplicateLongIndices, 0); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testLongVectorLoadMaskedStoreVector() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + vector.intoArray(res, 0, longVectorMask); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + + // IntVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorLoadGatherStore() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorLoadStoreScatter() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0); + vector.intoArray(res, 0, intIndices, 0); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorLoadMaskedStore() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorLoadStoreMasked() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0); + vector.intoArray(res, 0, intVectorMask); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testIntVectorStoreScatterLoadGatherDuplicateIndicesVector() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0, duplicateIntIndices, 0); + vector.intoArray(res, 0, duplicateIntIndices, 0); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testIntVectorLoadMaskedStoreVector() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + vector.intoArray(res, 0, intVectorMask); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + + // DoubleVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadGatherStore() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadStoreScatter() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + vector.intoArray(res, 0, doubleIndices, 0); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadMaskedStore() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadStoreMasked() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + vector.intoArray(res, 0, doubleVectorMask); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testDoubleVectorStoreScatterLoadGatherDuplicateIndicesVector() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, duplicateDoubleIndices, 0); + vector.intoArray(res, 0, duplicateDoubleIndices, 0); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testDoubleVectorLoadMaskedStoreVector() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + vector.intoArray(res, 0, doubleVectorMask); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + + // FloatVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorLoadGatherStore() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorLoadStoreScatter() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0); + vector.intoArray(res, 0, floatIndices, 0); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorLoadMaskedStore() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorLoadStoreMasked() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0); + vector.intoArray(res, 0, floatVectorMask); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testFloatVectorStoreScatterLoadGatherDuplicateIndicesVector() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0, duplicateFloatIndices, 0); + vector.intoArray(res, 0, duplicateFloatIndices, 0); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testFloatVectorLoadMaskedStoreVector() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + vector.intoArray(res, 0, floatVectorMask); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(10000) + .addFlags("--add-modules=jdk.incubator.vector", "-XX:+IncrementalInlineForceCleanup") + .start(); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java index b0037973ad1..426dec67019 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Arm Limited. All rights reserved. + * Copyright (c) 2022, 2023, Arm Limited. All rights reserved. * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/test/hotspot/jtreg/compiler/vectorization/TestRoundVectFloat.java b/test/hotspot/jtreg/compiler/vectorization/TestRoundVectFloat.java index 78e8d7b55cc..beb28e1fe8c 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestRoundVectFloat.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestRoundVectFloat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * 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,13 +44,12 @@ public class TestRoundVectFloat { public static void main(String args[]) { TestFramework.runWithFlags("-XX:-TieredCompilation", - "-XX:UseAVX=1", "-XX:CompileThresholdScaling=0.3"); System.out.println("PASSED"); } @Test - @IR(applyIf = {"UseAVX", " > 1"}, counts = {"RoundVF" , " > 0 "}) + @IR(applyIf = {"UseAVX", " > 1"}, counts = {IRNode.ROUND_VF , " > 0 "}) public void test_round_float(int[] iout, float[] finp) { for (int i = 0; i < finp.length; i+=1) { iout[i] = Math.round(finp[i]); diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java index 74262142247..eea79ac4cd6 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8183390 8332905 * @summary Vectorization test on bug-prone shift operation * @library /test/lib / * @@ -48,6 +49,7 @@ public class ArrayShiftOpTest extends VectorizationTestRunner { private static final int SIZE = 543; + private static int size = 543; private int[] ints; private long[] longs; @@ -71,7 +73,7 @@ public ArrayShiftOpTest() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512f", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true"}, counts = {IRNode.STORE_VECTOR, ">0"}) @IR(applyIfCPUFeature = {"avx512f", "true"}, counts = {IRNode.ROTATE_RIGHT_V, ">0"}) @@ -84,7 +86,23 @@ public int[] intCombinedRotateShift() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512f", "true"}, + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx2", "true"}, + counts = {IRNode.STORE_VECTOR, ">0"}) + @IR(applyIfCPUFeature = {"avx512f", "true"}, + counts = {IRNode.ROTATE_RIGHT_V, ">0"}) + // Requires size to not be known at compile time, otherwise the shift + // can get constant folded with the (iv + const) pattern from the + // PopulateIndex. + public int[] intCombinedRotateShiftWithPopulateIndex() { + int[] res = new int[size]; + for (int i = 0; i < size; i++) { + res[i] = (i << 14) | (i >>> 18); + } + return res; + } + + @Test + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true"}, counts = {IRNode.STORE_VECTOR, ">0"}) @IR(applyIfCPUFeature = {"avx512f", "true"}, counts = {IRNode.ROTATE_RIGHT_V, ">0"}) diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java index 7956fa5f618..60d3c05dab6 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java @@ -143,9 +143,6 @@ public float[] convertIntToFloat() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}, - // The vectorization of some conversions may fail when `+AlignVector`. - // We can remove the condition after JDK-8303827. - applyIf = {"AlignVector", "false"}, counts = {IRNode.VECTOR_CAST_I2D, IRNode.VECTOR_SIZE + "min(max_int, max_double)", ">0"}) public double[] convertIntToDouble() { double[] res = new double[SIZE]; @@ -233,9 +230,6 @@ public int[] convertFloatToInt() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true"}, - // The vectorization of some conversions may fail when `+AlignVector`. - // We can remove the condition after JDK-8303827. - applyIf = {"AlignVector", "false"}, counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", ">0"}) public long[] convertFloatToLong() { long[] res = new long[SIZE]; @@ -317,9 +311,6 @@ public char[] convertDoubleToChar() { // ---------------- Convert Between F & D ---------------- @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}, - // The vectorization of some conversions may fail when `+AlignVector`. - // We can remove the condition after JDK-8303827. - applyIf = {"AlignVector", "false"}, counts = {IRNode.VECTOR_CAST_F2D, IRNode.VECTOR_SIZE + "min(max_float, max_double)", ">0"}) public double[] convertFloatToDouble() { double[] res = new double[SIZE]; diff --git a/test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java b/test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java index de6137f7503..8e9a6002251 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1HeapSizeFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @bug 8006088 * @summary Tests argument processing for initial and maximum heap size for the G1 collector * @key flag-sensitive - * @requires vm.gc.G1 & vm.opt.x.Xmx == null & vm.opt.x.Xms == null & vm.opt.MinHeapSize == null & vm.opt.MaxHeapSize == null & vm.opt.InitialHeapSize == null + * @requires vm.gc.G1 & vm.opt.MinHeapSize == null & vm.opt.MaxHeapSize == null & vm.opt.InitialHeapSize == null * @library /test/lib * @library / * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java b/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java index c8eaa0f46e3..066d3c03603 100644 --- a/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java +++ b/test/hotspot/jtreg/gc/arguments/TestHeapFreeRatio.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * @test TestHeapFreeRatio * @bug 8025661 * @summary Test parsing of -Xminf and -Xmaxf - * @requires vm.opt.x.Xminf == null & vm.opt.x.Xmaxf == null & vm.opt.MinHeapFreeRatio == null & vm.opt.MaxHeapFreeRatio == null + * @requires vm.opt.MinHeapFreeRatio == null & vm.opt.MaxHeapFreeRatio == null * @library /test/lib * @library / * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java b/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java index 5af005063c1..fd784861663 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java +++ b/test/hotspot/jtreg/gc/arguments/TestMaxHeapSizeTools.java @@ -71,42 +71,42 @@ public static void checkMinInitialErgonomics(String gcflag) throws Exception { long maxHeapSize = largeValue + (2 * 1024 * 1024); // -Xms is not set - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize }, values, -1, -1); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + smallValue }, values, smallValue, -1); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + largeValue }, values, largeValue, -1); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=0" }, values, -1, -1); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=" + smallValue }, values, -1, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=" + largeValue }, values, -1, largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=0" }, values, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize }, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + smallValue }, smallValue, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + largeValue }, largeValue, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=0" }, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=" + smallValue }, -1, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=" + largeValue }, -1, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:InitialHeapSize=0" }, -1, -1); // Some extra checks when both are set. - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + smallValue, "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + smallValue, "-XX:InitialHeapSize=" + largeValue }, values, smallValue, largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + largeValue, "-XX:InitialHeapSize=" + largeValue }, values, largeValue, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + smallValue, "-XX:InitialHeapSize=" + smallValue }, smallValue, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + smallValue, "-XX:InitialHeapSize=" + largeValue }, smallValue, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-XX:MinHeapSize=" + largeValue, "-XX:InitialHeapSize=" + largeValue }, largeValue, largeValue); // -Xms is set to zero - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0" }, values, -1, -1); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + smallValue }, values, smallValue, -1); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + largeValue }, values, largeValue, -1); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=0" }, values, -1, -1); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=" + smallValue }, values, -1, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=" + largeValue }, values, -1, largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=0" }, values, -1, -1); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + smallValue, "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + smallValue, "-XX:InitialHeapSize=" + largeValue }, values, smallValue, largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + largeValue, "-XX:InitialHeapSize=" + largeValue }, values, largeValue, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0" }, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + smallValue }, smallValue, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + largeValue }, largeValue, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=0" }, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=" + smallValue }, -1, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=" + largeValue }, -1, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:InitialHeapSize=0" }, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + smallValue, "-XX:InitialHeapSize=" + smallValue }, smallValue, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + smallValue, "-XX:InitialHeapSize=" + largeValue }, smallValue, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms0", "-XX:MinHeapSize=" + largeValue, "-XX:InitialHeapSize=" + largeValue }, largeValue, largeValue); // -Xms is set to small value - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue }, values, -1, -1); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:MinHeapSize=" + smallValue }, values, smallValue, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:MinHeapSize=0" }, values, -1, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=" + smallValue }, values, smallValue, smallValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=" + largeValue }, values, smallValue, largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=0" }, values, smallValue, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue }, -1, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:MinHeapSize=" + smallValue }, smallValue, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:MinHeapSize=0" }, -1, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=" + smallValue }, smallValue, smallValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=" + largeValue }, smallValue, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + smallValue, "-XX:InitialHeapSize=0" }, smallValue, -1); // -Xms is set to large value - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue }, values, largeValue, largeValue); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue, "-XX:InitialHeapSize=0" }, values, largeValue, -1); - checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue, "-XX:MinHeapSize=0" }, values, -1, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue }, largeValue, largeValue); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue, "-XX:InitialHeapSize=0" }, largeValue, -1); + checkErgonomics(new String[] { gcflag, "-Xmx" + maxHeapSize, "-Xms" + largeValue, "-XX:MinHeapSize=0" }, -1, largeValue); } private static long align_up(long value, long alignment) { @@ -244,7 +244,7 @@ private static void getMinInitialMaxHeap(String[] args, MinInitialMaxValues val) * Verify whether the VM automatically synchronizes minimum and initial heap size if only * one is given for the GC specified. */ - public static void checkErgonomics(String[] args, long[] newoldsize, + public static void checkErgonomics(String[] args, long expectedMin, long expectedInitial) throws Exception { MinInitialMaxValues v = new MinInitialMaxValues(); diff --git a/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java b/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java index ff6c3127640..3f741ab1440 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java +++ b/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @summary Make sure that MaxNewSize always has a useful value after argument * processing. * @key flag-sensitive - * @requires vm.gc.Serial & vm.opt.MaxNewSize == null & vm.opt.NewRatio == null & vm.opt.NewSize == null & vm.opt.OldSize == null & vm.opt.x.Xms == null & vm.opt.x.Xmx == null + * @requires vm.gc.Serial & vm.opt.MaxNewSize == null & vm.opt.NewRatio == null & vm.opt.NewSize == null & vm.opt.OldSize == null * @library /test/lib * @library / * @modules java.base/jdk.internal.misc @@ -44,7 +44,7 @@ * @summary Make sure that MaxNewSize always has a useful value after argument * processing. * @key flag-sensitive - * @requires vm.gc.Parallel & vm.opt.MaxNewSize == null & vm.opt.NewRatio == null & vm.opt.NewSize == null & vm.opt.OldSize == null & vm.opt.x.Xms == null & vm.opt.x.Xmx == null + * @requires vm.gc.Parallel & vm.opt.MaxNewSize == null & vm.opt.NewRatio == null & vm.opt.NewSize == null & vm.opt.OldSize == null * @library /test/lib * @library / * @modules java.base/jdk.internal.misc @@ -59,7 +59,7 @@ * @summary Make sure that MaxNewSize always has a useful value after argument * processing. * @key flag-sensitive - * @requires vm.gc.G1 & vm.opt.MaxNewSize == null & vm.opt.NewRatio == null & vm.opt.NewSize == null & vm.opt.OldSize == null & vm.opt.x.Xms == null & vm.opt.x.Xmx == null + * @requires vm.gc.G1 & vm.opt.MaxNewSize == null & vm.opt.NewRatio == null & vm.opt.NewSize == null & vm.opt.OldSize == null * @library /test/lib * @library / * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelHeapSizeFlags.java b/test/hotspot/jtreg/gc/arguments/TestParallelHeapSizeFlags.java index 8e73abb9134..61f10fb4dcf 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelHeapSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelHeapSizeFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @summary Tests argument processing for initial and maximum heap size for the * parallel collectors. * @key flag-sensitive - * @requires vm.gc.Parallel & vm.opt.x.Xmx == null & vm.opt.x.Xms == null & vm.opt.MinHeapSize == null & vm.opt.MaxHeapSize == null & vm.opt.InitialHeapSize == null + * @requires vm.gc.Parallel & vm.opt.MinHeapSize == null & vm.opt.MaxHeapSize == null & vm.opt.InitialHeapSize == null * @library /test/lib * @library / * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/gc/arguments/TestSerialHeapSizeFlags.java b/test/hotspot/jtreg/gc/arguments/TestSerialHeapSizeFlags.java index b46b1ccb268..68905c49b9e 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSerialHeapSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestSerialHeapSizeFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @bug 8006088 * @summary Tests argument processing for initial and maximum heap size for the Serial collector * @key flag-sensitive - * @requires vm.gc.Serial & vm.opt.x.Xmx == null & vm.opt.x.Xms == null & vm.opt.MinHeapSize == null & vm.opt.MaxHeapSize == null & vm.opt.InitialHeapSize == null + * @requires vm.gc.Serial & vm.opt.MinHeapSize == null & vm.opt.MaxHeapSize == null & vm.opt.InitialHeapSize == null * @library /test/lib * @library / * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/gc/parallel/TestAlwaysPreTouchBehavior.java b/test/hotspot/jtreg/gc/parallel/TestAlwaysPreTouchBehavior.java index 12c03661e0e..3a5b2b557cc 100644 --- a/test/hotspot/jtreg/gc/parallel/TestAlwaysPreTouchBehavior.java +++ b/test/hotspot/jtreg/gc/parallel/TestAlwaysPreTouchBehavior.java @@ -31,7 +31,7 @@ * @requires os.family == "linux" * @requires os.maxMemory > 2G * @library /test/lib - * @run main/othervm -Xmx1g -Xms1g -XX:+UseParallelGC -XX:+AlwaysPreTouch gc.parallel.TestAlwaysPreTouchBehavior + * @run main/othervm -Xmx1g -Xms1g -XX:+UseParallelGC -XX:+AlwaysPreTouch -XX:+UnlockDiagnosticVMOptions -XX:-UseMadvPopulateWrite gc.parallel.TestAlwaysPreTouchBehavior */ import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; @@ -77,4 +77,3 @@ public static void main(String [] args) { Asserts.assertGreaterThanOrEqual(rss, committedMemory, "RSS of this process(" + rss + "kb) should be bigger than or equal to committed heap mem(" + committedMemory + "kb)"); } } - diff --git a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTools.java b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTools.java index 8b8fea1f2e3..2a6652eb06e 100644 --- a/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTools.java +++ b/test/hotspot/jtreg/gc/stringdedup/TestStringDeduplicationTools.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,8 @@ import java.lang.reflect.*; import java.lang.management.*; import java.util.*; +import java.util.stream.Collectors; + import javax.management.*; import javax.management.openmbean.*; import jdk.test.lib.process.ProcessTools; @@ -85,6 +87,32 @@ private static Object getValue(String string) { } } + /** + * Get system load. + * + *
+ *
load() ~= 1
fully loaded system, all cores are used 100%
+ *
load() < 1
some cpu resources are available
+ *
load() > 1
system is overloaded
+ *
+ * + * @return the load of the system or Optional.empty() if the load can not be determined. + */ + private static Optional systemLoad() { + OperatingSystemMXBean bean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class); + double average = bean.getSystemLoadAverage() / bean.getAvailableProcessors(); + return (average < 0) + ? Optional.empty() + : Optional.of(average); + } + + private static String minMax(List> l) { + DoubleSummaryStatistics minmax = l.stream().flatMap(Optional::stream).collect(Collectors.summarizingDouble(d -> d)); + return minmax.getCount() != 0 + ? "min: " + minmax.getMin() + ", max: " + minmax.getMax() + : "could not gather load statistics from system"; + } + private static void doFullGc(int numberOfTimes) { List> newStrings = new ArrayList>(); for (int i = 0; i < numberOfTimes; i++) { @@ -179,13 +207,15 @@ private static void forceDeduplication(int ageThreshold, String gcType) { } } - private static boolean waitForDeduplication(String s1, String s2) { + private static void waitForDeduplication(String s1, String s2) { boolean first = true; int timeout = 10000; // 10sec in ms int iterationWait = 100; // 100ms + List> loadHistory = new ArrayList<>(); for (int attempts = 0; attempts < (timeout / iterationWait); attempts++) { + loadHistory.add(systemLoad()); if (getValue(s1) == getValue(s2)) { - return true; + return; } if (first) { System.out.println("Waiting for deduplication..."); @@ -194,10 +224,10 @@ private static boolean waitForDeduplication(String s1, String s2) { try { Thread.sleep(iterationWait); } catch (Exception e) { - throw new RuntimeException(e); + throw new RuntimeException("Deduplication has not occurred: Thread.sleep() threw", e); } } - return false; + throw new RuntimeException("Deduplication has not occurred, load history: " + minMax(loadHistory)); } private static String generateString(int id) { @@ -240,7 +270,9 @@ private static ArrayList createStrings(int total, int unique) { */ private static void verifyStrings(ArrayList list, int uniqueExpected) { boolean passed = false; + List> loadHistory = new ArrayList<>(); for (int attempts = 0; attempts < 10; attempts++) { + loadHistory.add(systemLoad()); // Check number of deduplicated strings ArrayList unique = new ArrayList(uniqueExpected); for (String string: list) { @@ -277,7 +309,7 @@ private static void verifyStrings(ArrayList list, int uniqueExpected) { } } if (!passed) { - throw new RuntimeException("String verification failed"); + throw new RuntimeException("String verification failed, load history: " + minMax(loadHistory)); } } @@ -361,9 +393,7 @@ public static void main(String[] args) { // and be inserted into the deduplication hashtable. forceDeduplication(ageThreshold, FullGC); - if (!waitForDeduplication(dupString1, baseString)) { - throw new RuntimeException("Deduplication has not occurred"); - } + waitForDeduplication(dupString1, baseString); // Create a new duplicate of baseString StringBuilder sb2 = new StringBuilder(baseString); @@ -398,9 +428,7 @@ public static void main(String[] args) { forceDeduplication(ageThreshold, FullGC); - if (!waitForDeduplication(dupString3, internedString)) { - throw new RuntimeException("Deduplication has not occurred for string 3"); - } + waitForDeduplication(dupString3, internedString); if (afterInternedValue != getValue(dupString2)) { throw new RuntimeException("Interned string value changed"); diff --git a/test/hotspot/jtreg/gc/testlibrary/Helpers.java b/test/hotspot/jtreg/gc/testlibrary/Helpers.java index 03d67e44455..a0c28ff25f7 100644 --- a/test/hotspot/jtreg/gc/testlibrary/Helpers.java +++ b/test/hotspot/jtreg/gc/testlibrary/Helpers.java @@ -88,7 +88,7 @@ public static int detectByteArrayAllocationOverhead() { * @param className class name * @param root root directory - where .java and .class files will be put * @param source class source - * @throws IOException if cannot write file to specified directory + * @throws Exception if cannot write file to specified directory */ public static void compileClass(String className, Path root, String source) throws Exception { Path sourceFile = root.resolve(className + ".java"); diff --git a/test/hotspot/jtreg/gc/x/TestGarbageCollectorMXBean.java b/test/hotspot/jtreg/gc/x/TestGarbageCollectorMXBean.java index 0324567b196..193b93ee2d0 100644 --- a/test/hotspot/jtreg/gc/x/TestGarbageCollectorMXBean.java +++ b/test/hotspot/jtreg/gc/x/TestGarbageCollectorMXBean.java @@ -28,6 +28,7 @@ * @requires vm.gc.ZSinglegen * @summary Test ZGC garbage collector MXBean * @modules java.management + * @requires vm.compMode != "Xcomp" * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xms256M -Xmx512M -Xlog:gc gc.x.TestGarbageCollectorMXBean 256 512 * @run main/othervm -XX:+UseZGC -XX:-ZGenerational -Xms512M -Xmx512M -Xlog:gc gc.x.TestGarbageCollectorMXBean 512 512 */ diff --git a/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java b/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java index 97c7b4b26af..b3ecc28ff65 100644 --- a/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java +++ b/test/hotspot/jtreg/gc/z/TestGarbageCollectorMXBean.java @@ -28,6 +28,7 @@ * @requires vm.gc.ZGenerational * @summary Test ZGC garbage collector MXBean * @modules java.management + * @requires vm.compMode != "Xcomp" * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xms256M -Xmx512M -Xlog:gc gc.z.TestGarbageCollectorMXBean 256 512 * @run main/othervm -XX:+UseZGC -XX:+ZGenerational -Xms512M -Xmx512M -Xlog:gc gc.z.TestGarbageCollectorMXBean 512 512 */ diff --git a/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java b/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java index a10f4193234..b12eff0cf84 100644 --- a/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java +++ b/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.concurrent.CyclicBarrier; @@ -89,14 +90,17 @@ public static void main(String[] args) throws Exception { // should show up with fully - or almost fully - committed thread stacks. } else { - - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + ArrayList vmArgs = new ArrayList<>(); + Collections.addAll(vmArgs, "-XX:+UnlockDiagnosticVMOptions", "-Xmx100M", "-XX:+AlwaysPreTouchStacks", - "-XX:NativeMemoryTracking=summary", "-XX:+PrintNMTStatistics", - "TestAlwaysPreTouchStacks", - "test"); + "-XX:NativeMemoryTracking=summary", "-XX:+PrintNMTStatistics"); + if (System.getProperty("os.name").contains("Linux")) { + vmArgs.add("-XX:-UseMadvPopulateWrite"); + } + Collections.addAll(vmArgs, "TestAlwaysPreTouchStacks", "test"); + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(vmArgs); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.reportDiagnosticSummary(); diff --git a/test/hotspot/jtreg/runtime/Thread/TestThreadDumpClassInitMonitor.java b/test/hotspot/jtreg/runtime/Thread/TestThreadDumpClassInitMonitor.java index 0154f43244e..6260088fa33 100644 --- a/test/hotspot/jtreg/runtime/Thread/TestThreadDumpClassInitMonitor.java +++ b/test/hotspot/jtreg/runtime/Thread/TestThreadDumpClassInitMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,8 +60,7 @@ public class TestThreadDumpClassInitMonitor { */ final static String TEST_THREAD = "TestThread"; final static String TEST_THREAD_ENTRY = "\"" + TEST_THREAD; - // final static String IN_OBJECT_WAIT = "in Object.wait()"; - final static String IN_CONVAR_WAIT = "waiting on condition"; + final static String IN_OBJECT_WAIT = "in Object.wait()"; final static String THREAD_STATE = "java.lang.Thread.State: RUNNABLE"; final static String THREAD_INFO = "Thread:"; // the details are not important final static String JAVATHREAD_STATE = "JavaThread state: _thread_blocked"; @@ -140,7 +139,7 @@ public static void main(String[] args) throws Throwable { continue; } foundLines++; - if (!line.contains(IN_CONVAR_WAIT)) { + if (!line.contains(IN_OBJECT_WAIT)) { throw new Error("Unexpected initial stack line: " + line); } continue; diff --git a/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java b/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java index 183b1c3afcf..b0d66ffe902 100644 --- a/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java +++ b/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java @@ -31,42 +31,37 @@ * @bug 8306583 */ - import jdk.test.lib.cds.CDSTestUtils; - import jdk.test.lib.process.OutputAnalyzer; - import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; - public class TestCDSVMCrash { +public class TestCDSVMCrash { - public static void main(String[] args) throws Exception { - if (args.length == 1) { - // This should guarantee to throw: - // java.lang.OutOfMemoryError: Requested array size exceeds VM limit - try { - Object[] oa = new Object[Integer.MAX_VALUE]; - throw new Error("OOME not triggered"); - } catch (OutOfMemoryError err) { - throw new Error("OOME didn't abort JVM!"); - } - } - // else this is the main test - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+CrashOnOutOfMemoryError", - "-XX:-CreateCoredumpOnCrash", "-Xmx128m", "-Xshare:on", TestCDSVMCrash.class.getName(),"throwOOME"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - // executeAndLog should throw an exception in the VM crashed - try { + public static void main(String[] args) throws Exception { + if (args.length == 1) { + // This should guarantee to throw: + // java.lang.OutOfMemoryError: Requested array size exceeds VM limit + try { + Object[] oa = new Object[Integer.MAX_VALUE]; + throw new Error("OOME not triggered"); + } catch (OutOfMemoryError err) { + throw new Error("OOME didn't abort JVM!"); + } + } + // else this is the main test + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+CrashOnOutOfMemoryError", + "-XX:-CreateCoredumpOnCrash", "-Xmx128m", + "-Xshare:on", TestCDSVMCrash.class.getName(), + "throwOOME"); + // executeAndLog should throw an exception in the VM crashed + try { CDSTestUtils.executeAndLog(pb, "cds_vm_crash"); throw new Error("Expected VM to crash"); - } catch(RuntimeException e) { + } catch(RuntimeException e) { if (!e.getMessage().equals("Hotspot crashed")) { - throw new Error("Expected message: Hotspot crashed"); + throw new Error("Expected message: Hotspot crashed"); } - } - int exitValue = output.getExitValue(); - if (0 == exitValue) { - //expecting a non zero value - throw new Error("Expected to get non zero exit value"); - } - output.shouldContain("A fatal error has been detected by the Java Runtime Environment"); + } System.out.println("PASSED"); - } - } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java index 152e10ac47a..3f759d13a4c 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,9 +115,11 @@ static void test(boolean dumpWithParallel, boolean execWithParallel, boolean use out.shouldContain(HELLO); } else { String pattern = "((Too small maximum heap)" + - "|(GC triggered before VM initialization completed)" + - "|(java.lang.OutOfMemoryError: Java heap space))"; + "|(GC triggered before VM initialization completed)" + + "|(java.lang.OutOfMemoryError: Java heap space)" + + "|(Initial heap size set to a larger value than the maximum heap size))"; out.shouldMatch(pattern); + out.shouldNotHaveFatalError(); } n++; } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java index f82f1a02b59..f5975569447 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @test * @bug 8214781 8293187 * @summary Test for the -XX:ArchiveHeapTestClass flag - * @requires vm.cds.write.archived.java.heap + * @requires vm.debug == true & vm.cds.write.archived.java.heap * @modules java.base/sun.invoke.util java.logging * @library /test/jdk/lib/testlibrary /test/lib * /test/hotspot/jtreg/runtime/cds/appcds @@ -61,11 +61,7 @@ public class ArchiveHeapTestClass { static final String ARCHIVE_TEST_FIELD_NAME = "archivedObjects"; public static void main(String[] args) throws Exception { - if (Platform.isDebugBuild()) { - testDebugBuild(); - } else { - testProductBuild(); - } + testDebugBuild(); } static OutputAnalyzer dumpHelloOnly(String... extraOpts) throws Exception { @@ -169,13 +165,6 @@ static void testDebugBuild() throws Exception { mustSucceed(output); } } - - static void testProductBuild() throws Exception { - OutputAnalyzer output; - - output = dumpHelloOnly("-XX:-IgnoreUnrecognizedVMOptions", "-XX:ArchiveHeapTestClass=NoSuchClass"); - mustFail(output, "VM option 'ArchiveHeapTestClass' is develop and is available only in debug version of VM."); - } } class CDSTestClassA { diff --git a/test/hotspot/jtreg/runtime/cds/serviceability/ReplaceCriticalClassesForSubgraphs.java b/test/hotspot/jtreg/runtime/cds/serviceability/ReplaceCriticalClassesForSubgraphs.java index 1a267665dd6..f7d50fd7fe6 100644 --- a/test/hotspot/jtreg/runtime/cds/serviceability/ReplaceCriticalClassesForSubgraphs.java +++ b/test/hotspot/jtreg/runtime/cds/serviceability/ReplaceCriticalClassesForSubgraphs.java @@ -27,6 +27,7 @@ * @summary Tests how CDS works when critical library classes are replaced with JVMTI ClassFileLoadHook * @library /test/lib * @requires vm.cds.write.archived.java.heap + * @requires !vm.jvmci.enabled * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox * @run main/othervm/native ReplaceCriticalClassesForSubgraphs diff --git a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java new file mode 100644 index 00000000000..47cb5613171 --- /dev/null +++ b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java @@ -0,0 +1,95 @@ +/* + * 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 jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/* + * @test + * @summary Tests that recursive locking doesn't cause excessive native memory usage + * @library /test/lib + * @run driver TestRecursiveMonitorChurn + */ +public class TestRecursiveMonitorChurn { + static class Monitor { + public static volatile int i, j; + synchronized void doSomething() { + i++; + doSomethingElse(); + } + synchronized void doSomethingElse() { + j++; + } + } + + public static volatile Monitor monitor; + public static void main(String[] args) throws IOException { + if (args.length == 1 && args[0].equals("test")) { + // The actual test, in a forked JVM. + for (int i = 0; i < 100000; i++) { + monitor = new Monitor(); + monitor.doSomething(); + } + System.out.println("i + j = " + (Monitor.i + Monitor.j)); + } else { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-Xmx100M", "-XX:AsyncDeflationInterval=0", "-XX:GuaranteedAsyncDeflationInterval=0", + "-XX:NativeMemoryTracking=summary", "-XX:+PrintNMTStatistics", + "TestRecursiveMonitorChurn", + "test"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.reportDiagnosticSummary(); + + output.shouldHaveExitValue(0); + + // We want to see, in the final NMT printout, a committed object monitor size that is reasonably low. + // Like this: + // - Object Monitors (reserved=208, committed=208) + // (malloc=208 #1) (at peak) + // + // Without recursive locking support, this would look more like this: + // - Object Monitors (reserved=20800624, committed=20800624) + // (malloc=20800624 #100003) (at peak) + + Pattern pat = Pattern.compile("- *Object Monitors.*reserved=(\\d+), committed=(\\d+).*"); + for (String line : output.asLines()) { + Matcher m = pat.matcher(line); + if (m.matches()) { + long reserved = Long.parseLong(m.group(1)); + long committed = Long.parseLong(m.group(2)); + System.out.println(">>>>> " + line + ": " + reserved + " - " + committed); + if (committed > 1000) { + throw new RuntimeException("Allocated too many monitors"); + } + return; + } + } + throw new RuntimeException("Did not find expected NMT output"); + } + } +} diff --git a/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.java b/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.java index 133d5e65112..f0b6ff4c241 100644 --- a/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.java +++ b/test/hotspot/jtreg/runtime/logging/ClassLoadUnloadTest.java @@ -46,8 +46,6 @@ import jdk.test.lib.classloader.ClassUnloadCommon; public class ClassLoadUnloadTest { - private static OutputAnalyzer out; - private static ProcessBuilder pb; private static class ClassUnloadTestMain { public static void main(String... args) throws Exception { String className = "test.Empty"; @@ -58,65 +56,62 @@ public static void main(String... args) throws Exception { } } - static void checkFor(String... outputStrings) throws Exception { - out = new OutputAnalyzer(pb.start()); + static void checkFor(OutputAnalyzer output, String... outputStrings) throws Exception { for (String s: outputStrings) { - out.shouldContain(s); + output.shouldContain(s); } - out.shouldHaveExitValue(0); } - static void checkAbsent(String... outputStrings) throws Exception { - out = new OutputAnalyzer(pb.start()); + static void checkAbsent(OutputAnalyzer output, String... outputStrings) throws Exception { for (String s: outputStrings) { - out.shouldNotContain(s); + output.shouldNotContain(s); } - out.shouldHaveExitValue(0); } // Use the same command-line heap size setting as ../ClassUnload/UnloadTest.java - static ProcessBuilder exec(String... args) throws Exception { + static OutputAnalyzer exec(String... args) throws Exception { List argsList = new ArrayList<>(); Collections.addAll(argsList, args); - Collections.addAll(argsList, "-Xmn8m"); - Collections.addAll(argsList, "-Xbootclasspath/a:."); - Collections.addAll(argsList, "-XX:+UnlockDiagnosticVMOptions"); - Collections.addAll(argsList, "-XX:+WhiteBoxAPI"); - Collections.addAll(argsList, "-XX:+ClassUnloading"); - Collections.addAll(argsList, ClassUnloadTestMain.class.getName()); - return ProcessTools.createLimitedTestJavaProcessBuilder(argsList); + Collections.addAll(argsList, "-Xmn8m", "-Xbootclasspath/a:.", "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", "-XX:+ClassUnloading", ClassUnloadTestMain.class.getName()); + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(argsList); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + return output; } public static void main(String... args) throws Exception { + OutputAnalyzer output; + // -Xlog:class+unload=info - pb = exec("-Xlog:class+unload=info"); - checkFor("[class,unload]", "unloading class"); + output = exec("-Xlog:class+unload=info"); + checkFor(output, "[class,unload]", "unloading class"); // -Xlog:class+unload=off - pb = exec("-Xlog:class+unload=off"); - checkAbsent("[class,unload]"); + output = exec("-Xlog:class+unload=off"); + checkAbsent(output,"[class,unload]"); // -Xlog:class+load=info - pb = exec("-Xlog:class+load=info"); - checkFor("[class,load]", "java.lang.Object", "source:"); + output = exec("-Xlog:class+load=info"); + checkFor(output,"[class,load]", "java.lang.Object", "source:"); // -Xlog:class+load=debug - pb = exec("-Xlog:class+load=debug"); - checkFor("[class,load]", "java.lang.Object", "source:", "klass:", "super:", "loader:", "bytes:"); + output = exec("-Xlog:class+load=debug"); + checkFor(output,"[class,load]", "java.lang.Object", "source:", "klass:", "super:", "loader:", "bytes:"); // -Xlog:class+load=off - pb = exec("-Xlog:class+load=off"); - checkAbsent("[class,load]"); + output = exec("-Xlog:class+load=off"); + checkAbsent(output,"[class,load]"); // -verbose:class - pb = exec("-verbose:class"); - checkFor("[class,load]", "java.lang.Object", "source:"); - checkFor("[class,unload]", "unloading class"); + output = exec("-verbose:class"); + checkFor(output,"[class,load]", "java.lang.Object", "source:"); + checkFor(output,"[class,unload]", "unloading class"); // -Xlog:class+loader+data=trace - pb = exec("-Xlog:class+loader+data=trace"); - checkFor("[class,loader,data]", "create loader data"); + output = exec("-Xlog:class+loader+data=trace"); + checkFor(output, "[class,loader,data]", "create loader data"); } } diff --git a/test/hotspot/jtreg/runtime/os/HugePageConfiguration.java b/test/hotspot/jtreg/runtime/os/HugePageConfiguration.java index f475af4c2de..14cb88fb679 100644 --- a/test/hotspot/jtreg/runtime/os/HugePageConfiguration.java +++ b/test/hotspot/jtreg/runtime/os/HugePageConfiguration.java @@ -84,6 +84,20 @@ public long getThpPageSize() { return _thpPageSize; } + // Returns the THP page size (if exposed by the kernel) or a guessed THP page size. + // Mimics HugePages::thp_pagesize_fallback() method in hotspot (must be kept in sync with it). + public long getThpPageSizeOrFallback() { + long pageSize = getThpPageSize(); + if (pageSize != 0) { + return pageSize; + } + pageSize = getStaticDefaultHugePageSize(); + if (pageSize != 0) { + return Math.min(pageSize, 16 * 1024 * 1024); + } + return 2 * 1024 * 1024; + } + // Returns true if the THP support is enabled public boolean supportsTHP() { return _thpMode == THPMode.always || _thpMode == THPMode.madvise; diff --git a/test/hotspot/jtreg/runtime/os/TestHugePageDecisionsAtVMStartup.java b/test/hotspot/jtreg/runtime/os/TestHugePageDecisionsAtVMStartup.java index 340c1370738..18242578d6d 100644 --- a/test/hotspot/jtreg/runtime/os/TestHugePageDecisionsAtVMStartup.java +++ b/test/hotspot/jtreg/runtime/os/TestHugePageDecisionsAtVMStartup.java @@ -125,7 +125,8 @@ static void testOutput(boolean useLP, boolean useTHP, OutputAnalyzer out, HugePa out.shouldContain("[info][pagesize] UseLargePages=1, UseTransparentHugePages=0"); out.shouldContain("[info][pagesize] Large page support enabled"); } else if (useLP && useTHP && configuration.supportsTHP()) { - String thpPageSizeString = buildSizeString(configuration.getThpPageSize()); + long thpPageSize = configuration.getThpPageSizeOrFallback(); + String thpPageSizeString = buildSizeString(thpPageSize); // We expect to see exactly two "Usable page sizes" : the system page size and the THP page size. The system // page size differs, but its always in KB). out.shouldContain("[info][pagesize] UseLargePages=1, UseTransparentHugePages=1"); diff --git a/test/hotspot/jtreg/runtime/reflect/ComponentTypeFieldTest.java b/test/hotspot/jtreg/runtime/reflect/ComponentTypeFieldTest.java new file mode 100644 index 00000000000..6296a7f970e --- /dev/null +++ b/test/hotspot/jtreg/runtime/reflect/ComponentTypeFieldTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8337622 + * @summary (reflect) java.lang.Class componentType field not found. + * @library /test/lib + * @modules java.base/java.lang:open + * @run main ComponentTypeFieldTest + */ + +import java.lang.reflect.Field; +import static jdk.test.lib.Asserts.*; + +public class ComponentTypeFieldTest { + + public static void main(String[] args) throws Exception { + Field f = Class.class.getDeclaredField("componentType"); + f.setAccessible(true); + Object val = f.get(Runnable.class); + assertTrue(val == null); + System.out.println("val is " + val); + + Object arrayVal = f.get(Integer[].class); + System.out.println("val is " + arrayVal); + String arrayValString = arrayVal.toString(); + assertTrue(arrayValString.equals("class java.lang.Integer")); + } +} diff --git a/test/hotspot/jtreg/runtime/whitebox/TestWBDeflateIdleMonitors.java b/test/hotspot/jtreg/runtime/whitebox/TestWBDeflateIdleMonitors.java index e88bc025e8c..9fc4fdcaef5 100644 --- a/test/hotspot/jtreg/runtime/whitebox/TestWBDeflateIdleMonitors.java +++ b/test/hotspot/jtreg/runtime/whitebox/TestWBDeflateIdleMonitors.java @@ -61,12 +61,11 @@ public static class InflateMonitorsTest { static WhiteBox wb = WhiteBox.getWhiteBox(); public static Object obj; - public static void main(String args[]) { + public static void main(String args[]) throws Exception { obj = new Object(); synchronized (obj) { - // HotSpot implementation detail: asking for the hash code - // when the object is locked causes monitor inflation. - if (obj.hashCode() == 0xBAD) System.out.println("!"); + // The current implementation of notify-wait requires inflation. + obj.wait(1); Asserts.assertEQ(wb.isMonitorInflated(obj), true, "Monitor should be inflated."); } diff --git a/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitorTest.cpp b/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitorTest.cpp index f672a143144..a4920688603 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitorTest.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitorTest.cpp @@ -515,7 +515,9 @@ static void event_storage_augment_storage(EventStorage* storage) { ObjectTrace** new_objects = reinterpret_cast(malloc(new_max * sizeof(*new_objects))); int current_count = storage->live_object_count; - memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects)); + if (storage->live_objects != nullptr) { + memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects)); + } free(storage->live_objects); storage->live_objects = new_objects; storage->live_object_size = new_max; diff --git a/test/hotspot/jtreg/serviceability/sa/LingeredAppWithLock.java b/test/hotspot/jtreg/serviceability/sa/LingeredAppWithLock.java index 4140a3e3381..4319d576590 100644 --- a/test/hotspot/jtreg/serviceability/sa/LingeredAppWithLock.java +++ b/test/hotspot/jtreg/serviceability/sa/LingeredAppWithLock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,6 +25,7 @@ public class LingeredAppWithLock extends LingeredApp { + private static Object lockObj = new Object(); public static void lockMethod(Object lock) { synchronized (lock) { @@ -36,16 +37,28 @@ public static void lockMethod(Object lock) { } } + public static void waitMethod() { + synchronized (lockObj) { + try { + lockObj.wait(300000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + public static void main(String args[]) { Thread classLock1 = new Thread(() -> lockMethod(LingeredAppWithLock.class)); Thread classLock2 = new Thread(() -> lockMethod(LingeredAppWithLock.class)); Thread objectLock = new Thread(() -> lockMethod(classLock1)); Thread primitiveLock = new Thread(() -> lockMethod(int.class)); + Thread objectWait = new Thread(() -> waitMethod()); classLock1.start(); classLock2.start(); objectLock.start(); primitiveLock.start(); + objectWait.start(); // Wait until all threads have reached their blocked or timed wait state while ((classLock1.getState() != Thread.State.BLOCKED && @@ -53,7 +66,8 @@ public static void main(String args[]) { (classLock2.getState() != Thread.State.BLOCKED && classLock2.getState() != Thread.State.TIMED_WAITING) || (objectLock.getState() != Thread.State.TIMED_WAITING) || - (primitiveLock.getState() != Thread.State.TIMED_WAITING)) { + (primitiveLock.getState() != Thread.State.TIMED_WAITING) || + (objectWait.getState() != Thread.State.TIMED_WAITING)) { try { Thread.sleep(100); } catch (InterruptedException ex) { diff --git a/test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java b/test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java index cac6dac44a0..266b14167ef 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java +++ b/test/hotspot/jtreg/serviceability/sa/TestClhsdbJstackLock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,6 +31,7 @@ /** * @test + * @bug 8185796 8335743 * @requires vm.hasSA * @library /test/lib * @run main/othervm TestClhsdbJstackLock @@ -57,7 +58,8 @@ public static void main (String... args) throws Exception { "^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Class for LingeredAppWithLock\\)$", "^\\s+- waiting to lock <0x[0-9a-f]+> \\(a java\\.lang\\.Class for LingeredAppWithLock\\)$", "^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Thread\\)$", - "^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Class for int\\)$")); + "^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Class for int\\)$", + "^\\s+- waiting on (<0x[0-9a-f]+> \\(a java\\.lang\\.Object\\)|)$")); unExpStrMap.put("jstack", List.of( "missing reason for ")); test.run(app.getPid(), cmds, expStrMap, unExpStrMap); diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java index 02a2a07f250..d3c7f611031 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackLock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -29,6 +29,7 @@ /** * @test + * @bug 8185796 8335743 * @requires vm.hasSA * @library /test/lib * @run driver TestJhsdbJstackLock @@ -64,6 +65,7 @@ public static void main (String... args) throws Exception { out.shouldMatch("^\\s+- waiting to lock <0x[0-9a-f]+> \\(a java\\.lang\\.Class for LingeredAppWithLock\\)$"); out.shouldMatch("^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Thread\\)$"); out.shouldMatch("^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Class for int\\)$"); + out.shouldMatch("^\\s+- waiting on (<0x[0-9a-f]+> \\(a java\\.lang\\.Object\\)|)$"); out.stderrShouldBeEmptyIgnoreDeprecatedWarnings(); diff --git a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java index 5b08541bf0f..1a37a8bb059 100644 --- a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java +++ b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java @@ -38,6 +38,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; +import java.util.Random; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -266,7 +267,7 @@ private Pair getLastClass(Path errFile) { private String[] cmd(long classStart, long classStop) { String phase = phaseName(classStart); Path file = Paths.get(phase + ".cmd"); - var rng = Utils.getRandomInstance(); + Random rng = Utils.getRandomInstance(); ArrayList Args = new ArrayList(Arrays.asList( "-Xbatch", @@ -302,7 +303,7 @@ private String[] cmd(long classStart, long classStop) { "-XX:+StressIGVN", "-XX:+StressCCP", // StressSeed is uint - "-XX:StressSeed=" + Math.abs(rng.nextInt()))); + "-XX:StressSeed=" + rng.nextInt(Integer.MAX_VALUE))); for (String arg : CTW_EXTRA_ARGS.split(",")) { Args.add(arg); diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/CheckedTestExample.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/CheckedTestExample.java index 206b7d9d185..b2a0b40c582 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/CheckedTestExample.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/CheckedTestExample.java @@ -74,7 +74,7 @@ public static void main(String[] args) { } @Test - @Arguments(Argument.DEFAULT) // As with normal tests, you need to tell the framework what the argument is. + @Arguments(values = Argument.DEFAULT) // As with normal tests, you need to tell the framework what the argument is. @Warmup(100) // As with normal tests, you can specify the warmup iterations. public int test(int x) { return 42; diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/BaseTestExample.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/NormalTestExample.java similarity index 93% rename from test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/BaseTestExample.java rename to test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/NormalTestExample.java index f06fcb9e55d..06dda1641ed 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/BaseTestExample.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/NormalTestExample.java @@ -30,7 +30,7 @@ * @test * @summary Example test to use the new test framework. * @library /test/lib / - * @run driver ir_framework.examples.BaseTestExample + * @run driver ir_framework.examples.NormalTestExample */ /** @@ -58,11 +58,11 @@ * @see Warmup * @see TestFramework */ -public class BaseTestExample { +public class NormalTestExample { int iFld; public static void main(String[] args) { - TestFramework.run(); // equivalent to TestFramework.run(BaseTestExample.class) + TestFramework.run(); // equivalent to TestFramework.run(NormalTestExample.class) } // Test without arguments. @@ -74,14 +74,14 @@ public void mostBasicTest() { // Test with arguments. Use Argument class to choose a value. // Object arguments need to have an associated default constructor in its class. @Test - @Arguments({Argument.DEFAULT, Argument.MAX}) + @Arguments(values = {Argument.DEFAULT, Argument.MAX}) public void basicTestWithArguments(int x, long y) { iFld = x; } // @Warmup needs to be positive or zero. In case of zero, the method is directly compiled (simulated -Xcomp). @Test - @Arguments({Argument.DEFAULT, Argument.MAX}) + @Arguments(values = {Argument.DEFAULT, Argument.MAX}) @Warmup(100) public void basicTestWithDifferentWarmup(int x, long y) { iFld = x; diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/SetupExample.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/SetupExample.java new file mode 100644 index 00000000000..0de711fdc6e --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/examples/SetupExample.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package ir_framework.examples; + +import compiler.lib.ir_framework.*; +import compiler.lib.ir_framework.SetupInfo; + +import jdk.test.lib.Utils; +import java.util.Random; + +/* + * @test + * @summary Example test to use setup method (provide arguments and set fields). + * @library /test/lib / + * @run driver ir_framework.examples.SetupExample + */ + +/** + * This file shows some examples of how to use a setup method, annotated with {@link Setup}, and referenced by + * a test method with @Arguments(setup = "setupMethodName"). + * + * @see Setup + * @see Arguments + * @see Test + */ +public class SetupExample { + private static final Random RANDOM = Utils.getRandomInstance(); + + int iFld1, iFld2; + + public static void main(String[] args) { + TestFramework.run(); + } + + // ----------------- Random but Linked -------------- + @Setup + static Object[] setupLinkedII() { + int r = RANDOM.nextInt(); + return new Object[]{ r, r + 42 }; + } + + @Test + @Arguments(setup = "setupLinkedII") + static int testSetupLinkedII(int a, int b) { + return b - a; + } + + @Check(test = "testSetupLinkedII") + static void checkSetupLinkedII(int res) { + if (res != 42) { + throw new RuntimeException("wrong result " + res); + } + } + + // ----------------- Random Arrays -------------- + static int[] generateI(int len) { + int[] a = new int[len]; + for (int i = 0; i < len; i++) { + a[i] = RANDOM.nextInt(); + } + return a; + } + + @Setup + static Object[] setupRandomArrayII() { + // Random length, so that AutoVectorization pre/main/post and drain loops are tested + int len = RANDOM.nextInt(20_000); + int[] a = generateI(len); + int[] b = generateI(len); + return new Object[] { a, b }; + } + + @Test + @Arguments(setup = "setupRandomArrayII") + static Object[] testAdd(int[] a, int[] b) { + int[] c = new int[a.length]; + for (int i = 0; i < a.length; i++) { + c[i] = a[i] + b[i]; + } + return new Object[] { a, b, c }; + } + + @Check(test = "testAdd") + static void checkAdd(Object[] res) { + int[] a = (int[])res[0]; + int[] b = (int[])res[1]; + int[] c = (int[])res[2]; + for (int i = 0; i < a.length; i++) { + if (c[i] != a[i] + b[i]) { + throw new RuntimeException("wrong values: " + a[i] + " " + b[i] + " " + c[i]); + } + } + } + + // ----------------- Setup Fields --------------- + @Setup + void setupFields() { + int r = RANDOM.nextInt(); + iFld1 = r; + iFld2 = r + 42; + } + + @Test + @Arguments(setup = "setupFields") + int testSetupFields() { + return iFld2 - iFld1; + } + + @Check(test = "testSetupFields") + static void checkSetupFields(int res) { + if (res != 42) { + throw new RuntimeException("wrong result " + res); + } + } + + // ----------------- Deterministic Values ------- + @Setup + Object[] setupDeterministic(SetupInfo info) { + // This value increments with every invocation of the setup method: 0, 1, 2, ... + int cnt = info.invocationCounter(); + + // Return true with low frequency. If we did this randomly, we can get unlucky + // and never return true. So doing it deterministically can be helpful when we + // want "low frequency" but a guaranteed "true" at some point. + return new Object[]{ cnt % 1_000 }; + } + + @Test + @Arguments(setup = "setupDeterministic") + @IR(counts = {IRNode.STORE_OF_FIELD, "iFld1", "1", + IRNode.STORE_OF_FIELD, "iFld2", "1"}) + void testLowProbabilityBranchDeterministic(int x) { + if (x == 7) { + // unlikely branch -> guaranteed taken -> in profile -> not trapped -> in IR + iFld1 = 42; + } else { + // likely branch + iFld2 = 77; + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestAccessModifiers.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestAccessModifiers.java index 47bc9741b60..ff609ab68bd 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestAccessModifiers.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestAccessModifiers.java @@ -45,7 +45,7 @@ public void test() { } @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void test2(int x) { } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java index 99bf338e072..0ca33e4409c 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java @@ -56,6 +56,7 @@ public static void main(String[] args) { expectTestFormatException(BadWarmup.class); expectTestFormatException(BadBaseTests.class); expectTestFormatException(BadRunTests.class); + expectTestFormatException(BadSetupTest.class); expectTestFormatException(BadCheckTest.class); expectTestFormatException(BadIRAnnotationBeforeFlagVM.class); expectTestFormatException(BadIRAnnotations.class); @@ -205,57 +206,57 @@ public void noArgAnnotation2(int a) {} public void checkNoArgAnnotation2() {} @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void argNumberMismatch(int a, int b) {} @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void argNumberMismatch2() {} @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) public void notBoolean(boolean a) {} @Test - @Arguments(Argument.NUMBER_MINUS_42) + @Arguments(values = Argument.NUMBER_MINUS_42) public void notBoolean2(boolean a) {} @Test - @Arguments(Argument.TRUE) + @Arguments(values = Argument.TRUE) public void notNumber(int a) {} @Test - @Arguments(Argument.FALSE) + @Arguments(values = Argument.FALSE) public void notNumber2(int a) {} @Test - @Arguments(Argument.BOOLEAN_TOGGLE_FIRST_TRUE) + @Arguments(values = Argument.BOOLEAN_TOGGLE_FIRST_TRUE) public void notNumber3(int a) {} @Test - @Arguments(Argument.BOOLEAN_TOGGLE_FIRST_FALSE) + @Arguments(values = Argument.BOOLEAN_TOGGLE_FIRST_FALSE) public void notNumber4(int a) {} @Test - @Arguments({Argument.BOOLEAN_TOGGLE_FIRST_FALSE, Argument.TRUE}) + @Arguments(values = {Argument.BOOLEAN_TOGGLE_FIRST_FALSE, Argument.TRUE}) public void notNumber5(boolean a, int b) {} @FailCount(2) @Test - @Arguments({Argument.BOOLEAN_TOGGLE_FIRST_FALSE, Argument.NUMBER_42}) + @Arguments(values = {Argument.BOOLEAN_TOGGLE_FIRST_FALSE, Argument.NUMBER_42}) public void notNumber6(int a, boolean b) {} @FailCount(2) @Test - @Arguments({Argument.MIN, Argument.MAX}) + @Arguments(values = {Argument.MIN, Argument.MAX}) public void notNumber7(boolean a, boolean b) {} @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void missingDefaultConstructor(ClassNoDefaultConstructor a) {} @Test - @Arguments(Argument.TRUE) + @Arguments(values = Argument.TRUE) public void wrongArgumentNumberWithRun(Object o1, Object o2) { } @@ -265,7 +266,7 @@ public void forRun() { } @Test - @Arguments(Argument.TRUE) + @Arguments(values = Argument.TRUE) public void wrongArgumentNumberWithCheck(Object o1, Object o2) { } @@ -282,11 +283,11 @@ class BadOverloadedMethod { public void sameName() {} @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void sameName(boolean a) {} @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void sameName(double a) {} } @@ -488,21 +489,21 @@ public void runNoCompLevelStandalone() {} class BadBaseTests { @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) @FailCount(3) // No default constructor + parameter + return public TestInfo cannotUseTestInfoAsParameterOrReturn(TestInfo info) { return null; } @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) @FailCount(3) // No default constructor + parameter + return public RunInfo cannotUseRunInfoAsParameterOrReturn(RunInfo info) { return null; } @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) @FailCount(3) // No default constructor + parameter + return public AbstractInfo cannotUseAbstractInfoAsParameterOrReturn(AbstractInfo info) { return null; @@ -531,7 +532,7 @@ public void share2() {} public void noTestExists() {} @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void argTest(int x) {} @FailCount(0) // Combined with argTest() @@ -578,7 +579,7 @@ public void invalidShareCheckRun2() {} @Test public void testInvalidRunWithArgAnnotation() {} - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) @Run(test = "testInvalidRunWithArgAnnotation") public void invalidRunWithArgAnnotation(RunInfo info) {} @@ -623,6 +624,74 @@ public void runInvalidReuse1() {} public void runInvalidReuse2() {} } +class BadSetupTest { + // ----------- Bad Combinations of Annotations ----------------- + @Setup + @Test + public Object[] badSetupTestAnnotation() { + return new Object[]{1, 2, 3}; + } + + @NoFail + @Test + public void testForBadSetupCheckAnnotation() {} + + @Setup + @Check(test = "testForBadSetupCheckAnnotation") + public void badSetupCheckAnnotation() {} + + @Setup + @Arguments(values = {Argument.NUMBER_42, Argument.NUMBER_42}) + public void badSetupArgumentsAnnotation(int a, int b) {} + + @NoFail + @Test + public void testForBadSetupRunAnnotation() {} + + @Setup + @Run(test = "testForBadSetupRunAnnotation") + public void badSetupRunAnnotation() {} + + // ----------- Useless but ok: Setup Without Test Method ----- + @NoFail + @Setup + public void setupWithNoTest() {} + + // ----------- Bad: Test where Setup Method does not exist --- + @Test + @Arguments(setup = "nonExistingMethod") + public void testWithNonExistingMethod() {} + + // ----------- Bad Arguments Annotation ---------------------- + @NoFail + @Setup + public Object[] setupForTestSetupAndValues() { + return new Object[]{1, 2}; + } + + @Test + @Arguments(setup = "setupForTestSetupAndValues", + values = {Argument.NUMBER_42, Argument.NUMBER_42}) + public void testSetupAndValues(int a, int b) {} + + // ----------- Overloaded Setup Method ---------------------- + @NoFail + @Setup + Object[] setupOverloaded() { + return new Object[]{3, 2, 1}; + } + + @Setup + Object[] setupOverloaded(SetupInfo info) { + return new Object[]{1, 2, 3}; + } + + @NoFail + @Test + @Arguments(setup = "setupOverloaded") + void testOverloaded(int a, int b, int c) {} +} + class BadCheckTest { @Check(test = "checkForCheck2") public void checkForCheck() {} @@ -702,7 +771,7 @@ public void shareSameTestTwice2() {} @Test public void testInvalidRunWithArgAnnotation() {} - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) @Check(test = "testInvalidRunWithArgAnnotation") public void invalidRunWithArgAnnotation(TestInfo info) {} } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBasics.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBasics.java index 9c1cdbb20b9..c8479349131 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBasics.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBasics.java @@ -133,7 +133,7 @@ public int returnValueTest() { // Base test, with arguments, directly invoked. // Specify the argument values with @Arguments @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void byteDefaultArgument(byte x) { executed[4]++; if (x != 0) { @@ -142,7 +142,7 @@ public void byteDefaultArgument(byte x) { } @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void shortDefaultArgument(short x) { executed[5]++; if (x != 0) { @@ -151,7 +151,7 @@ public void shortDefaultArgument(short x) { } @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void intDefaultArgument(int x) { executed[6]++; if (x != 0) { @@ -160,7 +160,7 @@ public void intDefaultArgument(int x) { } @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void longDefaultArgument(long x) { executed[7]++; if (x != 0L) { @@ -169,7 +169,7 @@ public void longDefaultArgument(long x) { } @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void floatDefaultArgument(float x) { executed[8]++; if (x != 0.0f) { @@ -178,7 +178,7 @@ public void floatDefaultArgument(float x) { } @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void doubleDefaultArgument(double x) { executed[9]++; if (x != 0.0f) { @@ -187,7 +187,7 @@ public void doubleDefaultArgument(double x) { } @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void charDefaultArgument(char x) { executed[10]++; if (x != '\u0000') { @@ -196,7 +196,7 @@ public void charDefaultArgument(char x) { } @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void booleanDefaultArgument(boolean x) { executed[11]++; if (x) { @@ -205,7 +205,7 @@ public void booleanDefaultArgument(boolean x) { } @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void stringObjectDefaultArgument(String x) { executed[12]++; if (x == null || x.length() != 0) { @@ -214,7 +214,7 @@ public void stringObjectDefaultArgument(String x) { } @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) public void defaultObjectDefaultArgument(DefaultObject x) { executed[13]++; if (x == null || x.i != 4) { @@ -223,7 +223,7 @@ public void defaultObjectDefaultArgument(DefaultObject x) { } @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) public void byte42(byte x) { executed[14]++; if (x != 42) { @@ -232,7 +232,7 @@ public void byte42(byte x) { } @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) public void short42(short x) { executed[15]++; if (x != 42) { @@ -241,7 +241,7 @@ public void short42(short x) { } @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) public void int42(int x) { executed[16]++; if (x != 42) { @@ -250,7 +250,7 @@ public void int42(int x) { } @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) public void long42(long x) { executed[17]++; if (x != 42) { @@ -259,7 +259,7 @@ public void long42(long x) { } @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) public void float42(float x) { executed[18]++; if (x != 42.0) { @@ -268,7 +268,7 @@ public void float42(float x) { } @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) public void double42(double x) { executed[19]++; if (x != 42.0) { @@ -277,7 +277,7 @@ public void double42(double x) { } @Test - @Arguments(Argument.FALSE) + @Arguments(values = Argument.FALSE) public void booleanFalse(boolean x) { executed[20]++; if (x) { @@ -286,7 +286,7 @@ public void booleanFalse(boolean x) { } @Test - @Arguments(Argument.TRUE) + @Arguments(values = Argument.TRUE) public void booleanTrue(boolean x) { executed[21]++; if (!x) { @@ -295,37 +295,37 @@ public void booleanTrue(boolean x) { } @Test - @Arguments(Argument.RANDOM_ONCE) + @Arguments(values = Argument.RANDOM_ONCE) public void randomByte(byte x) { executed[22]++; } @Test - @Arguments(Argument.RANDOM_ONCE) + @Arguments(values = Argument.RANDOM_ONCE) public void randomShort(short x) { executed[23]++; } @Test - @Arguments(Argument.RANDOM_ONCE) + @Arguments(values = Argument.RANDOM_ONCE) public void randomInt(int x) { executed[24]++; } @Test - @Arguments(Argument.RANDOM_ONCE) + @Arguments(values = Argument.RANDOM_ONCE) public void randomLong(long x) { executed[25]++; } @Test - @Arguments(Argument.RANDOM_ONCE) + @Arguments(values = Argument.RANDOM_ONCE) public void randomFloat(float x) { executed[26]++; } @Test - @Arguments(Argument.RANDOM_ONCE) + @Arguments(values = Argument.RANDOM_ONCE) public void randomDouble(double x) { executed[27]++; } @@ -336,13 +336,13 @@ public void randomNotExecutedTest(double x) { } @Test - @Arguments(Argument.RANDOM_ONCE) + @Arguments(values = Argument.RANDOM_ONCE) public void randomBoolean(boolean x) { executed[28]++; } @Test - @Arguments(Argument.BOOLEAN_TOGGLE_FIRST_FALSE) + @Arguments(values = Argument.BOOLEAN_TOGGLE_FIRST_FALSE) public void booleanToggleFirstFalse(boolean x) { if (executed[29] == 0) { // First invocation @@ -357,56 +357,56 @@ public void booleanToggleFirstFalse(boolean x) { } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) public void randomEachByte(byte x) { checkNonFloatingRandomNumber(x, executed[30]); executed[30]++; } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) public void randomEachShort(short x) { checkNonFloatingRandomNumber(x, executed[31]); executed[31]++; } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) public void randomEachInt(int x) { checkNonFloatingRandomNumber(x, executed[32]); executed[32]++; } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) public void randomEachLong(long x) { checkNonFloatingRandomNumber(x, executed[33]); executed[33]++; } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) public void randomEachChar(char x) { checkNonFloatingRandomNumber(x, executed[34]); executed[34]++; } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) public void randomEachFloat(float x) { checkFloatingRandomNumber(x, executed[35]); executed[35]++; } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) public void randomEachDouble(double x) { checkFloatingRandomNumber(x, executed[36]); executed[36]++; } @Test - @Arguments(Argument.RANDOM_EACH) + @Arguments(values = Argument.RANDOM_EACH) public void randomEachBoolean(boolean x) { checkRandomBoolean(x, executed[37]); executed[37]++; @@ -459,7 +459,7 @@ private void checkRandomBoolean(boolean x, int invocationCount) { @Test - @Arguments(Argument.NUMBER_MINUS_42) + @Arguments(values = Argument.NUMBER_MINUS_42) public void byteMinus42(byte x) { executed[38]++; if (x != -42) { @@ -468,7 +468,7 @@ public void byteMinus42(byte x) { } @Test - @Arguments(Argument.NUMBER_MINUS_42) + @Arguments(values = Argument.NUMBER_MINUS_42) public void shortMinus42(short x) { executed[39]++; if (x != -42) { @@ -477,7 +477,7 @@ public void shortMinus42(short x) { } @Test - @Arguments(Argument.NUMBER_MINUS_42) + @Arguments(values = Argument.NUMBER_MINUS_42) public void intMinus42(int x) { executed[40]++; if (x != -42) { @@ -486,7 +486,7 @@ public void intMinus42(int x) { } @Test - @Arguments(Argument.NUMBER_MINUS_42) + @Arguments(values = Argument.NUMBER_MINUS_42) public void longMinus42(long x) { executed[41]++; if (x != -42) { @@ -495,7 +495,7 @@ public void longMinus42(long x) { } @Test - @Arguments(Argument.NUMBER_MINUS_42) + @Arguments(values = Argument.NUMBER_MINUS_42) public void floatMinus42(float x) { executed[42]++; if (x != -42.0) { @@ -504,7 +504,7 @@ public void floatMinus42(float x) { } @Test - @Arguments(Argument.NUMBER_MINUS_42) + @Arguments(values = Argument.NUMBER_MINUS_42) public void doubleMinus42(double x) { executed[43]++; if (x != -42.0) { @@ -513,7 +513,7 @@ public void doubleMinus42(double x) { } @Test - @Arguments(Argument.MIN) + @Arguments(values = Argument.MIN) public void byteMin(byte x) { executed[79]++; if (x != Byte.MIN_VALUE) { @@ -522,7 +522,7 @@ public void byteMin(byte x) { } @Test - @Arguments(Argument.MIN) + @Arguments(values = Argument.MIN) public void charMin(char x) { executed[80]++; if (x != Character.MIN_VALUE) { @@ -531,7 +531,7 @@ public void charMin(char x) { } @Test - @Arguments(Argument.MIN) + @Arguments(values = Argument.MIN) public void shortMin(short x) { executed[81]++; if (x != Short.MIN_VALUE) { @@ -540,7 +540,7 @@ public void shortMin(short x) { } @Test - @Arguments(Argument.MIN) + @Arguments(values = Argument.MIN) public void intMin(int x) { executed[82]++; if (x != Integer.MIN_VALUE) { @@ -549,7 +549,7 @@ public void intMin(int x) { } @Test - @Arguments(Argument.MIN) + @Arguments(values = Argument.MIN) public void longMin(long x) { executed[83]++; if (x != Long.MIN_VALUE) { @@ -558,7 +558,7 @@ public void longMin(long x) { } @Test - @Arguments(Argument.MIN) + @Arguments(values = Argument.MIN) public void floatMin(float x) { executed[84]++; if (x != Float.MIN_VALUE) { @@ -567,7 +567,7 @@ public void floatMin(float x) { } @Test - @Arguments(Argument.MIN) + @Arguments(values = Argument.MIN) public void doubleMin(double x) { executed[85]++; if (x != Double.MIN_VALUE) { @@ -576,7 +576,7 @@ public void doubleMin(double x) { } @Test - @Arguments(Argument.MAX) + @Arguments(values = Argument.MAX) public void byteMax(byte x) { executed[86]++; if (x != Byte.MAX_VALUE) { @@ -585,7 +585,7 @@ public void byteMax(byte x) { } @Test - @Arguments(Argument.MAX) + @Arguments(values = Argument.MAX) public void charMax(char x) { executed[87]++; if (x != Character.MAX_VALUE) { @@ -594,7 +594,7 @@ public void charMax(char x) { } @Test - @Arguments(Argument.MAX) + @Arguments(values = Argument.MAX) public void shortMax(short x) { executed[88]++; if (x != Short.MAX_VALUE) { @@ -603,7 +603,7 @@ public void shortMax(short x) { } @Test - @Arguments(Argument.MAX) + @Arguments(values = Argument.MAX) public void intMax(int x) { executed[89]++; if (x != Integer.MAX_VALUE) { @@ -612,7 +612,7 @@ public void intMax(int x) { } @Test - @Arguments(Argument.MAX) + @Arguments(values = Argument.MAX) public void longMax(long x) { executed[90]++; if (x != Long.MAX_VALUE) { @@ -621,7 +621,7 @@ public void longMax(long x) { } @Test - @Arguments(Argument.MAX) + @Arguments(values = Argument.MAX) public void floatMax(float x) { executed[91]++; if (x != Float.MAX_VALUE) { @@ -630,7 +630,7 @@ public void floatMax(float x) { } @Test - @Arguments(Argument.MAX) + @Arguments(values = Argument.MAX) public void doubleMax(double x) { executed[78]++; if (x != Double.MAX_VALUE) { @@ -639,7 +639,7 @@ public void doubleMax(double x) { } @Test - @Arguments({Argument.DEFAULT, Argument.DEFAULT}) + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) public void twoArgsDefault1(byte x, short y) { executed[44]++; if (x != 0 || y != 0) { @@ -648,7 +648,7 @@ public void twoArgsDefault1(byte x, short y) { } @Test - @Arguments({Argument.DEFAULT, Argument.DEFAULT}) + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) public void twoArgsDefault2(int x, short y) { executed[45]++; if (x != 0 || y != 0) { @@ -657,7 +657,7 @@ public void twoArgsDefault2(int x, short y) { } @Test - @Arguments({Argument.DEFAULT, Argument.DEFAULT}) + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) public void twoArgsDefault3(short x, long y) { executed[46]++; if (x != 0 || y != 0) { @@ -666,7 +666,7 @@ public void twoArgsDefault3(short x, long y) { } @Test - @Arguments({Argument.DEFAULT, Argument.DEFAULT}) + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) public void twoArgsDefault4(float x, boolean y) { executed[47]++; if (x != 0.0 || y) { @@ -675,7 +675,7 @@ public void twoArgsDefault4(float x, boolean y) { } @Test - @Arguments({Argument.DEFAULT, Argument.DEFAULT}) + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) public void twoArgsDefault5(boolean x, char y) { executed[48]++; if (x || y != '\u0000') { @@ -684,7 +684,7 @@ public void twoArgsDefault5(boolean x, char y) { } @Test - @Arguments({Argument.DEFAULT, Argument.DEFAULT}) + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) public void twoArgsDefault6(char x, byte y) { executed[49]++; if (x != '\u0000' || y != 0) { @@ -693,13 +693,13 @@ public void twoArgsDefault6(char x, byte y) { } @Test - @Arguments({Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) + @Arguments(values = {Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) public void twoArgsRandomOnce(char x, byte y) { executed[50]++; } @Test - @Arguments({Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, + @Arguments(values = {Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) @@ -711,7 +711,7 @@ public void checkRandomOnceDifferentArgs(int a, int b, int c, int d, int e, int } @Test - @Arguments({Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, + @Arguments(values = {Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_ONCE}) @@ -720,7 +720,7 @@ public void checkMixedRandoms1(byte a, short b, int c, long d, char e, boolean f } @Test - @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH, + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH, Argument.RANDOM_EACH, Argument.RANDOM_EACH, Argument.RANDOM_EACH, Argument.RANDOM_EACH, Argument.RANDOM_EACH, Argument.RANDOM_EACH}) @@ -729,7 +729,7 @@ public void checkMixedRandoms2(byte a, short b, int c, long d, char e, boolean f } @Test - @Arguments({Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, + @Arguments(values = {Argument.RANDOM_ONCE, Argument.RANDOM_ONCE, Argument.RANDOM_EACH, Argument.RANDOM_EACH, Argument.RANDOM_ONCE, Argument.RANDOM_EACH, Argument.RANDOM_EACH, Argument.RANDOM_ONCE}) @@ -738,7 +738,7 @@ public void checkMixedRandoms3(byte a, short b, int c, long d, char e, boolean f } @Test - @Arguments({Argument.NUMBER_42, Argument.NUMBER_42, + @Arguments(values = {Argument.NUMBER_42, Argument.NUMBER_42, Argument.NUMBER_42, Argument.NUMBER_42, Argument.NUMBER_42, Argument.NUMBER_42}) public void check42Mix1(byte a, short b, int c, long d, float e, double f) { @@ -749,7 +749,7 @@ public void check42Mix1(byte a, short b, int c, long d, float e, double f) { } @Test - @Arguments({Argument.NUMBER_MINUS_42, Argument.NUMBER_MINUS_42, + @Arguments(values = {Argument.NUMBER_MINUS_42, Argument.NUMBER_MINUS_42, Argument.NUMBER_MINUS_42, Argument.NUMBER_MINUS_42, Argument.NUMBER_MINUS_42, Argument.NUMBER_MINUS_42}) public void check42Mix2(byte a, short b, int c, long d, float e, double f) { @@ -760,7 +760,7 @@ public void check42Mix2(byte a, short b, int c, long d, float e, double f) { } @Test - @Arguments({Argument.NUMBER_MINUS_42, Argument.NUMBER_42, + @Arguments(values = {Argument.NUMBER_MINUS_42, Argument.NUMBER_42, Argument.NUMBER_MINUS_42, Argument.NUMBER_MINUS_42, Argument.NUMBER_42, Argument.NUMBER_MINUS_42}) public void check42Mix3(byte a, short b, int c, long d, float e, double f) { @@ -772,7 +772,7 @@ public void check42Mix3(byte a, short b, int c, long d, float e, double f) { @Test - @Arguments(Argument.BOOLEAN_TOGGLE_FIRST_TRUE) + @Arguments(values = Argument.BOOLEAN_TOGGLE_FIRST_TRUE) public void booleanToggleFirstTrue(boolean x) { if (executed[58] == 0) { // First invocation @@ -787,7 +787,7 @@ public void booleanToggleFirstTrue(boolean x) { } @Test - @Arguments({Argument.BOOLEAN_TOGGLE_FIRST_FALSE, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) + @Arguments(values = {Argument.BOOLEAN_TOGGLE_FIRST_FALSE, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) public void checkTwoToggles(boolean b1, boolean b2) { if (executed[59] == 0) { // First invocation @@ -804,7 +804,7 @@ public void checkTwoToggles(boolean b1, boolean b2) { } @Test - @Arguments({Argument.BOOLEAN_TOGGLE_FIRST_FALSE, Argument.FALSE, + @Arguments(values = {Argument.BOOLEAN_TOGGLE_FIRST_FALSE, Argument.FALSE, Argument.TRUE, Argument.BOOLEAN_TOGGLE_FIRST_TRUE}) public void booleanMix(boolean b1, boolean b2, boolean b3, boolean b4) { if (executed[60] == 0) { @@ -853,7 +853,7 @@ public void checkTestCheckReturn(int returnValue) { } @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) public short testCheckWithArgs(short x) { executed[94]++; return x; diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java index acb9fad25f3..ff0aeae8e30 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java @@ -96,7 +96,7 @@ public void sameName(int retValue) { } @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) @IR(failOn = IRNode.LOAD) @IR(counts = {IRNode.STORE_I, "0"}) public int testGood3(int x) { @@ -139,7 +139,7 @@ public void sameName(int retValue) { } @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) public int testBad3(int x) { return x; } @@ -153,7 +153,7 @@ public void checkTestBad3(int retValue) { } @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) @IR(failOn = IRNode.LOAD) @IR(counts = {IRNode.STORE_I, "1"}) public int testBad4(int x) { @@ -168,7 +168,7 @@ public void sameName(int retValue, TestInfo info) { } @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) public int testBad5(int x) { return x; } @@ -210,7 +210,7 @@ public void sameName(int retValue) { } @Test - @Arguments(Argument.NUMBER_42) + @Arguments(values = Argument.NUMBER_42) @IR(failOn = IRNode.LOAD) @IR(counts = {IRNode.STORE_I, "1"}) public int testBad4(int x) { diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java index 4794a9c8127..0fd262bd13a 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java @@ -413,7 +413,7 @@ private static void findIrIds(String output, String method, int... numbers) { class AndOr1 { @Test - @Arguments(Argument.DEFAULT) + @Arguments(values = Argument.DEFAULT) @IR(applyIfAnd = {"UsePerfData", "true", "TLABRefillWasteFraction", "50", "UseTLAB", "true"}, failOn = {IRNode.CALL}) public void test1(int i) { dontInline(); @@ -1110,7 +1110,7 @@ public Object nullAssert() { } @Test - @Arguments(Argument.TRUE) + @Arguments(values = Argument.TRUE) @IR(failOn = IRNode.TRAP) // fails @IR(failOn = IRNode.UNSTABLE_IF_TRAP) // fails @IR(failOn = {IRNode.PREDICATE_TRAP, diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPlatformChecks.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPlatformChecks.java new file mode 100644 index 00000000000..586ecdeb4f4 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPlatformChecks.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * 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 ir_framework.tests; + +import compiler.lib.ir_framework.*; +import compiler.lib.ir_framework.driver.irmatching.IRViolationException; + +/* + * @test 8280120 + * @summary Add attribute to IR to enable/disable IR matching based on the architecture + * @library /test/lib / + * @run driver ir_framework.tests.TestPlatformChecks + */ + +public class TestPlatformChecks { + private static final int SIZE = 1000; + private static int[] a = new int[SIZE]; + private static int[] b = new int[SIZE]; + private static int[] res = new int[SIZE]; + + public static void setup() { + for (int i = 0; i < SIZE; i++) { + a[i] = i; + b[i] = i; + } + } + + public static void main(String[] args) { + setup(); + TestFramework.run(); + } + + @Test + @IR(counts = {IRNode.ADD_VI, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"sse4.1", "true"}) + public static void test1() { + for (int i = 0; i < SIZE; i++) { + res[i] = a[i] + b[i]; + } + } + + // IR rule is enforced if all the platform constraints hold + @Test + @IR(counts = {IRNode.ADD_VI, "> 0"}, + applyIfPlatformAnd = {"x64", "true", "linux", "true"}, + applyIfCPUFeatureAnd = {"sse4.1", "true", "avx2", "true"}) + public static void test2() { + for (int i = 0; i < SIZE; i++) { + res[i] = a[i] + b[i]; + } + } + + // IR rule is enforced if any of the platform constraints hold + @Test + @IR(counts = {IRNode.ADD_VI, "> 0"}, + applyIfPlatformOr = {"linux", "true", "mac", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "avx2", "true"}) + public static void test3() { + for (int i = 0; i < SIZE; i++) { + res[i] = a[i] + b[i]; + } + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPreconditions.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPreconditions.java index ff986c87a5e..e1ba2380513 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPreconditions.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPreconditions.java @@ -56,6 +56,73 @@ public static void testApplyIfCPUFeatureOnly() {} @IR(applyIfCPUFeatureAnd = {"asimd", "true", "sse", "true"}, applyIf = {"LoopMaxUnroll", "= 8"}, counts = {IRNode.LOOP, ">= 1000"}) - public static void testApplyBoth() {} + public static void testApplyBoth1() {} + + // The IR check should not be applied on aarch64, because the "applyIfAnd" + // condition returns false as the VM is run with LoopMaxUnroll=8. + // Note that precondition `applyIfCPUFeature` will be evaluated first with + // early return. Hence the IR check should not be applied on non-aarch64 + // systems, and no exception is thrown because we are not checking the value + // of the unsupported "UseSVE" flag on non-aarch64 systems. + @Test + @IR(applyIfCPUFeature = {"asimd", "true"}, + applyIfAnd = {"UseSVE", "= 0", "LoopMaxUnroll", "= 0"}, + counts = {IRNode.LOOP, ">= 1000"}) + public static void testApplyBoth2() {} + + // The IR check should not be applied on x86, because the "applyIfAnd" + // condition returns false as the VM is run with LoopMaxUnroll=8. + // Note that precondition `applyIfCPUFeature` will be evaluated first with + // early return. Hence the IR check should not be applied on non-avx systems, + // and no exception is thrown because we are not checking the value of the + // unsupported "UseAVX" flag on non-avx systems. + @Test + @IR(applyIfCPUFeature = {"avx", "true"}, + applyIfAnd = {"UseAVX", "= 2", "LoopMaxUnroll", "= 0"}, + counts = {IRNode.LOOP, ">= 1000"}) + public static void testApplyBoth3() {} + + // The IR check should not be applied, since OS can not be both linux and mac. + @Test + @IR(applyIfPlatformAnd = {"linux", "true", "mac", "true"}, + counts = {IRNode.LOOP, ">= 1000"}) + public static void testApplyBothOs() {} + + // The IR check should not be applied, since we can't have both 32-bit and 64-bit data model. + @Test + @IR(applyIfPlatformAnd = {"32-bit", "true", "64-bit", "true"}, + counts = {IRNode.LOOP, ">= 1000"}) + public static void testApplyBothDataModel() {} + + // The IR check should not be applied, since the arch can't be both x64 and aarch64. + @Test + @IR(applyIfPlatformAnd = {"x64", "true", "aarch64", "true"}, + counts = {IRNode.LOOP, ">= 1000"}) + public static void testApplyBothArch() {} + + // Platform versions of testApplyBoth2/3. + @Test + @IR(applyIfPlatform = {"aarch64", "true"}, + applyIfAnd = {"UseSVE", "= 0", "LoopMaxUnroll", "= 0"}, + counts = {IRNode.LOOP, ">= 1000"}) + public static void testApplyPlatformSVE() {} + + @Test + @IR(applyIfPlatform = {"x64", "true"}, + applyIfAnd = {"UseAVX", "= 2", "LoopMaxUnroll", "= 0"}, + counts = {IRNode.LOOP, ">= 1000"}) + public static void testApplyPlatformAVX() {} + + @Test + @IR(applyIfPlatformAnd = {"x64", "true", "linux", "true"}, + applyIfAnd = {"UseAVX", "= 2", "LoopMaxUnroll", "= 0"}, + counts = {IRNode.LOOP, ">= 1000"}) + public static void testApplyPlatformAVXAnd() {} + + @Test + @IR(applyIfPlatformOr = {"x64", "true", "x86", "true"}, + applyIfAnd = {"UseSSE", "= 4", "LoopMaxUnroll", "= 0"}, + counts = {IRNode.LOOP, ">= 1000"}) + public static void testApplyPlatformSSEOr() {} } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestSetupTests.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestSetupTests.java new file mode 100644 index 00000000000..782a773515a --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestSetupTests.java @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package ir_framework.tests; + +import compiler.lib.ir_framework.*; +import compiler.lib.ir_framework.driver.TestVMException; +import compiler.lib.ir_framework.shared.TestRunException; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import java.util.Random; + +/* + * @test + * @bug 8324641 + * @requires vm.debug == true & vm.compMode != "Xint" & vm.compiler2.enabled & vm.flagless + * @summary Test different custom run tests. + * @library /test/lib /testlibrary_tests / + * @run driver ir_framework.tests.TestSetupTests + */ + +public class TestSetupTests { + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos); + PrintStream oldOut = System.out; + System.setOut(ps); + + // Positive tests in TestSetupTests class + TestFramework.run(); + + // Positive tests in TestSetupTestsWithFields class + TestFramework.run(TestSetupTestsWithFields.class); + + // Positive tests in TestSetupTestsSetupInfo class + TestFramework.run(TestSetupTestsSetupInfo.class); + + // Positive tests with expected exceptions + try { + TestFramework.run(TestSetupTestsWithExpectedExceptions.class); + Asserts.fail("Should have thrown exception"); + } catch (TestVMException e) { + System.setOut(oldOut); + Asserts.assertTrue(e.getExceptionInfo().contains("testTooManyArgs")); + Asserts.assertTrue(e.getExceptionInfo().contains("IllegalArgumentException: wrong number of arguments: 3 expected: 1")); + Asserts.assertTrue(e.getExceptionInfo().contains("testTooFewArgs")); + Asserts.assertTrue(e.getExceptionInfo().contains("IllegalArgumentException: wrong number of arguments: 2 expected: 3")); + + Asserts.assertTrue(e.getExceptionInfo().contains("testTooManyArgs2")); + Asserts.assertTrue(e.getExceptionInfo().contains("IllegalArgumentException: wrong number of arguments: 3 expected: 0")); + Asserts.assertTrue(e.getExceptionInfo().contains("testTooFewArgs2")); + Asserts.assertTrue(e.getExceptionInfo().contains("IllegalArgumentException: wrong number of arguments: 0 expected: 3")); + + Asserts.assertTrue(e.getExceptionInfo().contains("setupTestBadSetupArgsTooMany")); + Asserts.assertTrue(e.getExceptionInfo().contains("wrong number of arguments: 0 expected: 2")); + Asserts.assertTrue(e.getExceptionInfo().contains("setupTestBadSetupArgsWrongType")); + Asserts.assertTrue(e.getExceptionInfo().contains("argument type mismatch")); + + Asserts.assertTrue(e.getExceptionInfo().contains("setupReturnIntArray")); + Asserts.assertTrue(e.getExceptionInfo().contains("class [I cannot be cast to class [Ljava.lang.Object;")); + Asserts.assertTrue(e.getExceptionInfo().contains("setupReturnInt")); + Asserts.assertTrue(e.getExceptionInfo().contains("class java.lang.Integer cannot be cast to class [Ljava.lang.Object;")); + + Asserts.assertTrue(e.getExceptionInfo().contains("testSetupWrongArgumentType")); + Asserts.assertTrue(e.getExceptionInfo().contains("argument type mismatch")); + + Asserts.assertTrue(e.getExceptionInfo().contains("testSetupNull")); + Asserts.assertTrue(e.getExceptionInfo().contains("wrong number of arguments: 0 expected: 1")); + Asserts.assertTrue(e.getExceptionInfo().contains("Arguments: ")); + + Asserts.assertTrue(e.getExceptionInfo().contains("setupThrowInSetup")); + Asserts.assertTrue(e.getExceptionInfo().contains("BadCheckedTestException: expected setup")); + Asserts.assertTrue(e.getExceptionInfo().contains("testThrowInTest")); + Asserts.assertTrue(e.getExceptionInfo().contains("BadCheckedTestException: expected test")); + Asserts.assertTrue(e.getExceptionInfo().contains("checkThrowInCheck")); + Asserts.assertTrue(e.getExceptionInfo().contains("BadCheckedTestException: expected check")); + + // Check number of total failures: + Asserts.assertEQ(e.getExceptionInfo().split("argument type mismatch").length - 1, 2); + Asserts.assertEQ(e.getExceptionInfo().split("There was an error while invoking setup").length - 1, 5); + Asserts.assertEQ(e.getExceptionInfo().split("There was an error while invoking @Test").length - 1, 7); + Asserts.assertEQ(e.getExceptionInfo().split("There was an error while invoking @Check").length - 1, 1); + Asserts.assertEQ(e.getExceptionInfo().split("BadCheckedTestException").length - 1, 3); + Asserts.assertTrue(e.getExceptionInfo().contains("Test Failures (13)")); + } + } + + // ---------- Setup Nothing --------------- + @Setup + public void setupVoid() {} + + @Test + @Arguments(setup = "setupVoid") + public void testSetupVoid() {} + + @Setup + public Object[] setupEmpty() { + return new Object[]{}; + } + + @Test + @Arguments(setup = "setupEmpty") + public void testSetupEmpty() {} + + // ---------- Setup Arrays --------------- + @Setup + static Object[] setupArrayII(SetupInfo info) { + int[] a = new int[1_000]; + int[] b = new int[1_000]; + int x = info.invocationCounter(); + for (int i = 0; i < a.length; i++) { a[i] = x + i; } + for (int i = 0; i < a.length; i++) { b[i] = x - i; } + return new Object[]{a, b}; + } + + @Test + @Arguments(setup = "setupArrayII") + static void testSetupArrayII(int[] a, int[] b) { + for (int i = 0; i < a.length; i++) { + int y = a[i] - b[i]; + if (y != 2 * i) { + throw new RuntimeException("bad values for i=" + i + " a[i]=" + a[i] + " b[i]=" + b[i]); + } + } + } + + // ---------- Setup "linked" random values --------------- + @Setup + static Object[] setupLinkedII() { + int r = RANDOM.nextInt(); + return new Object[]{ r, r + 42}; + } + + @Test + @Arguments(setup = "setupLinkedII") + static int testSetupLinkedII(int a, int b) { + return b - a; + } + + @Check(test = "testSetupLinkedII") + static void checkSetupLinkedII(int res) { + if (res != 42) { throw new RuntimeException("wrong result " + res); } + } +} + +class TestSetupTestsWithFields { + int iFld1, iFld2, iFld3; + + @Setup + Object[] setupTest1(SetupInfo info) { + iFld1 = info.invocationCounter() + 1; + iFld2 = info.invocationCounter() + 2; + iFld3 = info.invocationCounter() + 3; + return new Object[]{info.invocationCounter()}; // -> argument x in test + } + + @Test + @Arguments(setup = "setupTest1") + int test1(int x) { + if (iFld1 != x + 1) { throw new RuntimeException("iFld1 wrong value: " + iFld1 + " != " + (x + 1)); } + if (iFld2 != x + 2) { throw new RuntimeException("iFld2 wrong value: " + iFld2 + " != " + (x + 2)); } + if (iFld3 != x + 3) { throw new RuntimeException("iFld3 wrong value: " + iFld3 + " != " + (x + 3)); } + iFld1++; + iFld2++; + iFld3++; + return x + 5; // -> argument y in check + } + + @Check(test = "test1") + void checkTest1(int y) { + if (iFld1 != y - 3) { throw new RuntimeException("iFld1 wrong value: " + iFld1 + " != " + (y - 3)); } + if (iFld2 != y - 2) { throw new RuntimeException("iFld2 wrong value: " + iFld2 + " != " + (y - 2)); } + if (iFld3 != y - 1) { throw new RuntimeException("iFld3 wrong value: " + iFld3 + " != " + (y - 1)); } + } +} + +class TestSetupTestsSetupInfo { + static int lastCnt = -1; + + @Setup + Object[] setupTest1(SetupInfo info) { + int cnt = info.invocationCounter(); + // Check that we increment every time + if (cnt - 1 != lastCnt) { + throw new RuntimeException("SetupInfo invocationCounter does not increment correctly: " + + cnt + ", vs last: " + lastCnt); + } + lastCnt = cnt; + return new Object[]{1, 2}; + } + + @Test + @Arguments(setup = "setupTest1") + void test1(int a, int b) {} +} + +class TestSetupTestsWithExpectedExceptions { + // ----------------- wrong number of arguments ------------------ + @Setup + public Object[] setupTooManyArgs() { + return new Object[]{1, 2, 3}; + } + + @Test + @Arguments(setup = "setupTooManyArgs") + public void testTooManyArgs(int a) {} + + @Setup + public Object[] setupTooFewArgs() { + return new Object[]{1, 2}; + } + + @Test + @Arguments(setup = "setupTooFewArgs") + public void testTooFewArgs(int a, int b, int c) {} + + @Setup + public Object[] setupTooManyArgs2() { + return new Object[]{1, 2, 3}; + } + + @Test + @Arguments(setup = "setupTooManyArgs2") + public void testTooManyArgs2() {} + + @Setup + public Object[] setupTooFewArgs2() { + return new Object[]{}; + } + + @Test + @Arguments(setup = "setupTooFewArgs2") + public void testTooFewArgs2(int a, int b, int c) {} + + // ----------------- wrong arguments for setup ------------------ + @Setup + public Object[] setupTestBadSetupArgsTooMany(SetupInfo setupInfo, int bad) { + return new Object[]{1, 2}; + } + + @Test + @Arguments(setup = "setupTestBadSetupArgsTooMany") + public void testBadSetupArgsTooMany(int a, int b) {} + + @Setup + public Object[] setupTestBadSetupArgsWrongType(int bad) { + return new Object[]{1, 2}; + } + + @Test + @Arguments(setup = "setupTestBadSetupArgsWrongType") + public void testBadSetupArgsWrongType(int a, int b) {} + + // ----------------- setup wrong return type ------------------ + @Setup + public int[] setupReturnIntArray() { + return new int[]{1, 2, 3}; + } + + @Test + @Arguments(setup = "setupReturnIntArray") + public void testSetupReturnIntArray(int a, int b, int c) {} + + @Setup + public int setupReturnInt(SetupInfo setupInfo) { + return setupInfo.invocationCounter(); + } + + @Test + @Arguments(setup = "setupReturnInt") + public void testSetupReturnInt(int a) {} + + // ----------------- setup provides wrong argument types ------ + @Setup + public Object[] setupWrongArgumentType(SetupInfo setupInfo) { + return new Object[]{(int)1, (long)2}; + } + + @Test + @Arguments(setup = "setupWrongArgumentType") + public void testSetupWrongArgumentType(long a, int b) {} + + // ----------------- setup returns null ------ + @Setup + public Object[] setupNull() { + return null; + } + + @Test + @Arguments(setup = "setupNull") + public void testSetupNull(Object x) {} + + // ----------------- Throw in Setup ----------- + @Setup + public Object[] setupThrowInSetup() { + throw new BadCheckedTestException("expected setup"); + } + + @Test + @Arguments(setup = "setupThrowInSetup") + public void testThrowInSetup() { + throw new RuntimeException("should have thrown in setup"); + } + + // ----------------- Throw in Test ----------- + @Setup + public Object[] setupThrowInTest(SetupInfo info) { + return new Object[]{ info.invocationCounter() }; + } + + @Test + @Arguments(setup = "setupThrowInTest") + public int testThrowInTest(int x) { + throw new BadCheckedTestException("expected test"); + } + + @Check(test = "testThrowInTest") + public void checkThrowInTest(int x) { + throw new RuntimeException("should have thrown in test"); + } + + // ----------------- Throw in Check ----------- + @Setup + public Object[] setupThrowInCheck(SetupInfo info) { + return new Object[]{ info.invocationCounter() }; + } + + @Test + @Arguments(setup = "setupThrowInCheck") + public int testThrowInCheck(int x) { + return x + 1; + } + + @Check(test = "testThrowInCheck") + public void checkThrowInCheck(int x) { + throw new BadCheckedTestException("expected check"); + } +} + +class BadCheckedTestException extends RuntimeException { + BadCheckedTestException(String s) { + super(s); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/TEST.properties b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java index f325231c660..4d93785e5c6 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit * -Xlog:gc* * gc.gctests.LargeObjects.large001.large001 diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TEST.properties b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java index f25bfe66763..c425f7c7ca3 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -60,7 +60,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TEST.properties b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java index 6b0b60149b6..948a82b599e 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -64,7 +64,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TEST.properties b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java index bfa5ecad348..f23446184dd 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -64,7 +64,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TEST.properties b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java index b8b0d59732c..ad898fcfb56 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -64,7 +64,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_0_1/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_0_1/TestDescription.java index 077ad3d9c4e..12768372d50 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_0_1/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_0_1/TestDescription.java @@ -33,6 +33,7 @@ * @requires vm.gc != null | !vm.opt.final.ClassUnloadingWithConcurrentMark * @requires vm.gc != "G1" | !vm.opt.final.ClassUnloadingWithConcurrentMark * @requires vm.gc != "Z" + * @requires vm.compMode != "Xcomp" * @library /vmTestbase /test/lib * @run main/othervm * -Xmx1g diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_10_20/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_10_20/TestDescription.java index badfb3a6b0a..a630ece929c 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_10_20/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_10_20/TestDescription.java @@ -33,6 +33,7 @@ * @requires vm.gc != null | !vm.opt.final.ClassUnloadingWithConcurrentMark * @requires vm.gc != "G1" | !vm.opt.final.ClassUnloadingWithConcurrentMark * @requires vm.gc != "Z" + * @requires vm.compMode != "Xcomp" * @library /vmTestbase /test/lib * @run main/othervm * -Xmx1g diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_70_80/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_70_80/TestDescription.java index 48a65368141..1fcf766b2eb 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_70_80/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_70_80/TestDescription.java @@ -33,6 +33,7 @@ * @requires vm.gc != null | !vm.opt.final.ClassUnloadingWithConcurrentMark * @requires vm.gc != "G1" | !vm.opt.final.ClassUnloadingWithConcurrentMark * @requires vm.gc != "Z" + * @requires vm.compMode != "Xcomp" * @library /vmTestbase /test/lib * @run main/othervm * -Xmx1g diff --git a/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_99_100/TestDescription.java b/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_99_100/TestDescription.java index 6f3467e996a..d2025c8dc0e 100644 --- a/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_99_100/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/metaspace/gc/watermark_99_100/TestDescription.java @@ -33,6 +33,7 @@ * @requires vm.gc != null | !vm.opt.final.ClassUnloadingWithConcurrentMark * @requires vm.gc != "G1" | !vm.opt.final.ClassUnloadingWithConcurrentMark * @requires vm.gc != "Z" + * @requires vm.compMode != "Xcomp" * @library /vmTestbase /test/lib * @run main/othervm * -Xmx1g diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007.java index 79f4fc16ca9..91ef81c00c8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,15 @@ package nsk.jvmti.GetClassFields; import java.io.PrintStream; +import java.io.InputStream; +import java.util.List; +import java.util.ArrayList; + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + public class getclfld007 { @@ -40,7 +49,7 @@ public class getclfld007 { } } - native static void check(int i, Class cls); + native static void check(Class cls, String[] expectedFields); native static int getRes(); public static void main(String args[]) { @@ -52,22 +61,64 @@ public static void main(String args[]) { public static int run(String args[], PrintStream out) { try { - check(0, Class.forName(InnerClass1.class.getName())); - check(1, Class.forName(InnerInterface.class.getName())); - check(2, Class.forName(InnerClass2.class.getName())); - check(3, Class.forName(OuterClass1.class.getName())); - check(4, Class.forName(OuterClass2.class.getName())); - check(5, Class.forName(OuterClass3.class.getName())); - check(6, Class.forName(OuterInterface1.class.getName())); - check(7, Class.forName(OuterInterface2.class.getName())); - check(8, Class.forName(OuterClass4.class.getName())); - check(9, Class.forName(OuterClass5.class.getName())); - } catch (ClassNotFoundException e) { + check(Class.forName(InnerClass1.class.getName())); + check(Class.forName(InnerInterface.class.getName())); + check(Class.forName(InnerClass2.class.getName())); + check(Class.forName(OuterClass1.class.getName())); + check(Class.forName(OuterClass2.class.getName())); + check(Class.forName(OuterClass3.class.getName())); + check(Class.forName(OuterInterface1.class.getName())); + check(Class.forName(OuterInterface2.class.getName())); + check(Class.forName(OuterClass4.class.getName())); + check(Class.forName(OuterClass5.class.getName())); + } catch (Exception e) { throw new RuntimeException(e); } return getRes(); } + + static void check(Class cls) throws Exception { + FieldExplorer explorer = new FieldExplorer(cls); + List fields = explorer.get(); + check(cls, fields.toArray(new String[0])); + } + + // helper class to get list of the class fields + // in the order they appear in the class file + static class FieldExplorer extends ClassVisitor { + private final Class cls; + private List fieldNameAndSig = new ArrayList<>(); + private FieldExplorer(Class cls) { + super(Opcodes.ASM7); + this.cls = cls; + } + + @Override + public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { + System.out.println(" field '" + name + "', type = " + descriptor); + fieldNameAndSig.add(name); + fieldNameAndSig.add(descriptor); + return super.visitField(access, name, descriptor, signature, value); + } + + private InputStream getClassBytes() throws Exception { + String clsName = cls.getName(); + String clsPath = clsName.replace('.', '/') + ".class"; + return cls.getClassLoader().getResourceAsStream(clsPath); + } + + // each field is represented by 2 Strings in the list: name and type descriptor + public List get() throws Exception { + System.out.println("Class " + cls.getName()); + try (InputStream classBytes = getClassBytes()) { + ClassReader classReader = new ClassReader(classBytes); + classReader.accept(this, 0); + } + return fieldNameAndSig; + } + } + static class InnerClass1 { String fld_1; void meth(String s) { @@ -119,8 +170,13 @@ public int meth_i2() { } } +// class with multiple fields to verify correctness of the field order class OuterClass5 extends OuterClass4 { int fld_i1 = 1; + String fld_s1 = "str"; + int fld_i2 = 2; + String fld_s2 = "str2"; + public int meth_i1() { return 1; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/TestDescription.java index 4df311688bd..80f5d6f580d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * 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,9 +31,9 @@ * DESCRIPTION * The test exercises JVMTI function * GetClassFields(clazz, fieldCountPtr, fieldsPtr). - * The test checks if the function returns the expected list of fields. - * That is the field list contains only directly declared (not inherited) - * fields. + * The test checks if the function returns the expected list of fields: + * - the list contains only directly declared (not inherited) fields; + * - fields are returned in the order they occur in the class file. * COMMENTS * Ported from JVMDI. * Test fixed due to test bug: @@ -45,6 +45,7 @@ * * @library /vmTestbase * /test/lib + * @modules java.base/jdk.internal.org.objectweb.asm * @run main/othervm/native -agentlib:getclfld007 nsk.jvmti.GetClassFields.getclfld007 */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp index 597c34787c6..93da371fd54 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * 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,69 +33,25 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -typedef struct { - const char *name; - const char *sig; -} fld_info; - -typedef struct { - const char *name; - jint fcount; - fld_info *flds; -} class_info; - static jvmtiEnv *jvmti = NULL; static jint result = PASSED; -static jboolean printdump = JNI_FALSE; - -static fld_info f0[] = { - { "fld_1", "Ljava/lang/String;" } -}; - -static fld_info f1[] = { - { "fld_n1", "I" } -}; - -static fld_info f2[] = { - { "fld_n2", "I" } -}; - -static fld_info f4[] = { - { "fld_o2", "I" } -}; - -static fld_info f5[] = { - { "fld_o3", "I" } -}; - -static fld_info f6[] = { - { "fld_i1", "I" } -}; - -static fld_info f7[] = { - { "fld_i2", "I" } -}; - -static fld_info f8[] = { - { "fld_i2", "I" } -}; - -static fld_info f9[] = { - { "fld_i1", "I" } -}; - -static class_info classes[] = { - { "InnerClass1", 1, f0 }, - { "InnerInterface", 1, f1 }, - { "InnerClass2", 1, f2 }, - { "OuterClass1", 0, NULL }, - { "OuterClass2", 1, f4 }, - { "OuterClass3", 1, f5 }, - { "OuterInterface1", 1, f6 }, - { "OuterInterface2", 1, f7 }, - { "OuterClass4", 1, f8 }, - { "OuterClass5", 1, f9 } -}; + + +// compares 'value' with jobject_arr[index] +static bool equals_str(JNIEnv *env, const char *value, jobjectArray jobject_arr, jint index) { + jstring jstr = (jstring)env->GetObjectArrayElement(jobject_arr, index); + const char* utf = env->GetStringUTFChars(jstr, NULL); + bool res = false; + if (utf != NULL) { + res = strcmp(value, utf) == 0; + env->ReleaseStringUTFChars(jstr, utf); + } else { + printf("GetStringUTFChars failed\n"); + result = STATUS_FAILED; + } + env->DeleteLocalRef(jstr); + return res; +} #ifdef STATIC_BUILD JNIEXPORT jint JNICALL Agent_OnLoad_getclfld007(JavaVM *jvm, char *options, void *reserved) { @@ -111,10 +67,6 @@ JNIEXPORT jint JNI_OnLoad_getclfld007(JavaVM *jvm, char *options, void *reserved jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { jint res; - if (options != NULL && strcmp(options, "printdump") == 0) { - printdump = JNI_TRUE; - } - res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); if (res != JNI_OK || jvmti == NULL) { printf("Wrong result of a valid call to GetEnv!\n"); @@ -125,61 +77,62 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { } JNIEXPORT void JNICALL -Java_nsk_jvmti_GetClassFields_getclfld007_check(JNIEnv *env, jclass cls, jint i, jclass clazz) { +Java_nsk_jvmti_GetClassFields_getclfld007_check(JNIEnv *env, jclass cls, jclass clazz, jobjectArray fieldArr) { jvmtiError err; jint fcount; jfieldID *fields; - char *name, *sig, *generic; + char *name, *sig; int j; if (jvmti == NULL) { printf("JVMTI client was not properly loaded!\n"); + fflush(0); result = STATUS_FAILED; return; } - if (printdump == JNI_TRUE) { - printf(">>> %s:\n", classes[i].name); - } + // fieldArr contains 2 elements for each field + jint field_count = env->GetArrayLength(fieldArr) / 2; err = jvmti->GetClassFields(clazz, &fcount, &fields); if (err != JVMTI_ERROR_NONE) { - printf("(GetClassFields#%d) unexpected error: %s (%d)\n", - i, TranslateError(err), err); + printf("GetClassFields unexpected error: %s (%d)\n", + TranslateError(err), err); + fflush(0); result = STATUS_FAILED; return; } - if (fcount != classes[i].fcount) { - printf("(%d) wrong number of fields: %d, expected: %d\n", - i, fcount, classes[i].fcount); + if (fcount != field_count) { + printf("wrong number of fields: %d, expected: %d\n", + fcount, field_count); result = STATUS_FAILED; } for (j = 0; j < fcount; j++) { if (fields[j] == NULL) { - printf("(%d:%d) fieldID = null\n", i, j); - } else { - err = jvmti->GetFieldName(clazz, fields[j], - &name, &sig, &generic); - if (err != JVMTI_ERROR_NONE) { - printf("(GetFieldName#%d:%d) unexpected error: %s (%d)\n", - i, j, TranslateError(err), err); - } else { - if (printdump == JNI_TRUE) { - printf(">>> [%d]: %s, sig = \"%s\"\n", j, name, sig); - } - if ((j < classes[i].fcount) && - (name == NULL || sig == NULL || - strcmp(name, classes[i].flds[j].name) != 0 || - strcmp(sig, classes[i].flds[j].sig) != 0)) { - printf("(%d:%d) wrong field: \"%s%s\"", i, j, name, sig); - printf(", expected: \"%s%s\"\n", - classes[i].flds[j].name, classes[i].flds[j].sig); - result = STATUS_FAILED; - } - } + printf("(%d) fieldID = null\n", j); + result = STATUS_FAILED; + continue; + } + err = jvmti->GetFieldName(clazz, fields[j], &name, &sig, NULL); + if (err != JVMTI_ERROR_NONE) { + printf("(GetFieldName#%d) unexpected error: %s (%d)\n", + j, TranslateError(err), err); + result = STATUS_FAILED; + continue; + } + printf(">>> [%d]: %s, sig = \"%s\"\n", j, name, sig); + if ((j < field_count) && + (name == NULL || sig == NULL || + !equals_str(env, name, fieldArr, j * 2) || + !equals_str(env, sig, fieldArr, j * 2 + 1))) { + printf("(%d) wrong field: \"%s%s\"", j, name, sig); + result = STATUS_FAILED; } + jvmti->Deallocate((unsigned char *)name); + jvmti->Deallocate((unsigned char *)sig); } + fflush(0); } JNIEXPORT int JNICALL diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/functions/rawmonitor/rawmonitor.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/functions/rawmonitor/rawmonitor.cpp index b7df38f8ecc..330c5551eed 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/functions/rawmonitor/rawmonitor.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/functions/rawmonitor/rawmonitor.cpp @@ -1,5 +1,4 @@ /* -s * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java index 6bdc5266fc4..a57f93fd934 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java @@ -80,15 +80,15 @@ public class Log extends FinalizableObject { /** * Is log-mode verbose? - * Default value is false. + * Always enabled. */ - private boolean verbose = false; + private final boolean verbose = true; /** * Should log messages prefixed with timestamps? - * Default value is false. + * Always enabled. */ - private boolean timestamp = false; + private final boolean timestamp = true; /** * Names for trace levels @@ -211,7 +211,6 @@ public Log(PrintStream stream) { */ public Log(PrintStream stream, boolean verbose) { this(stream); - this.verbose = verbose; } /** @@ -222,7 +221,6 @@ public Log(PrintStream stream, boolean verbose) { public Log(PrintStream stream, ArgumentParser argsParser) { this(stream, argsParser.verbose()); traceLevel = argsParser.getTraceLevel(); - timestamp = argsParser.isTimestamp(); } ///////////////////////////////////////////////////////////////// @@ -266,10 +264,9 @@ public void enableVerboseOnError(boolean enable) { * Enable or disable verbose mode for printing messages. */ public void enableVerbose(boolean enable) { - if (!verbose) { - flushLogBuffer(); + if (!enable) { + throw new RuntimeException("The non-verbose logging is not supported."); } - verbose = enable; } public int getTraceLevel() { @@ -471,7 +468,6 @@ private void logExceptionForFailureAnalysis(String msg) { protected synchronized void logTo(PrintStream stream) { cleanup(); // flush older log stream out = stream; - verbose = true; } ///////////////////////////////////////////////////////////////// diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/jvmti_tools.cpp b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/jvmti_tools.cpp index 444e5c55d1f..d98d9fa0f3a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/jvmti_tools.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/jvmti_tools.cpp @@ -146,7 +146,9 @@ static int add_option(const char opt[], int opt_len, const char val[], int val_l } else { strncpy(name, opt, opt_len); name[opt_len] = '\0'; - strncpy(value, val, val_len); + if (val != nullptr) { + strncpy(value, val, val_len); + } value[val_len] = '\0'; if (!check_option(dashed_opt, name, value)) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/TEST.properties deleted file mode 100644 index 8b51b2a9115..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/stack/TEST.properties +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -exclusiveAccess.dirs=. diff --git a/test/jdk/ProblemList-Virtual.txt b/test/jdk/ProblemList-Virtual.txt index 6461c3b4a61..5260a832796 100644 --- a/test/jdk/ProblemList-Virtual.txt +++ b/test/jdk/ProblemList-Virtual.txt @@ -29,9 +29,6 @@ com/sun/jdi/EATests.java#id0 8264699 generic- com/sun/jdi/ExceptionEvents.java 8278470 generic-all com/sun/jdi/RedefineCrossStart.java 8278470 generic-all -com/sun/jdi/cds/CDSBreakpointTest.java 8307778 generic-all -com/sun/jdi/cds/CDSDeleteAllBkptsTest.java 8307778 generic-all -com/sun/jdi/cds/CDSFieldWatchpoints.java 8307778 generic-all sun/tools/jcmd/JcmdOutputEncodingTest.java 8308033 generic-all sun/tools/jstack/BasicJStackTest.java 8308033 generic-all diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 59d9ab3b218..798d2a0d926 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -455,6 +455,7 @@ 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/Window/GetScreenLocation/GetScreenLocationTest.java 8225787 linux-x64 java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java 8266243 macosx-aarch64 @@ -480,7 +481,6 @@ java/awt/Choice/SelectNewItemTest/SelectNewItemTest.java 8324782 macosx-all # jdk_lang -java/lang/ProcessHandle/InfoTest.java 8211847 aix-ppc64 java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java 8151492 generic-all java/lang/invoke/LFCaching/LFGarbageCollectedTest.java 8078602 generic-all java/lang/invoke/lambda/LambdaFileEncodingSerialization.java 8249079 linux-all @@ -548,8 +548,6 @@ java/net/MulticastSocket/SetLoopbackMode.java 7122846,8308807 java/net/MulticastSocket/SetOutgoingIf.java 8308807 aix-ppc64 java/net/MulticastSocket/Test.java 7145658,8308807 macosx-all,aix-ppc64 -java/net/ServerSocket/AcceptInheritHandle.java 8211854 aix-ppc64 - java/net/Socket/asyncClose/Race.java 8317801 aix-ppc64 ############################################################################ @@ -566,6 +564,7 @@ java/nio/channels/DatagramChannel/ManySourcesAndTargets.java 8264385 macosx-a java/nio/channels/DatagramChannel/Unref.java 8233437 generic-all java/nio/channels/DatagramChannel/AfterDisconnect.java 8308807 aix-ppc64 +java/nio/file/Files/probeContentType/Basic.java 8320943 windows-all ############################################################################ @@ -618,6 +617,8 @@ sun/security/provider/PolicyParser/PrincipalExpansionError.java 8039280 generic- sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8316183 linux-ppc64le +security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java#teliasonerarootcav1 8333640 generic-all + ############################################################################ # jdk_sound @@ -643,6 +644,7 @@ javax/sound/sampled/Clip/ClipIsRunningAfterStop.java 8307574 linux-x64 javax/swing/plaf/basic/BasicTextUI/8001470/bug8001470.java 8233177 linux-all,windows-all +javax/swing/JFrame/MaximizeWindowTest.java 8321289 linux-all javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedTranslucentPerPixelTranslucentGradient.java 8233582 linux-all javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedPerPixelTranslucentGradient.java 8233582 linux-all javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentSwing.java 8194128 macosx-all @@ -653,6 +655,7 @@ javax/swing/JTree/DnD/LastNodeLowerHalfDrop.java 8159131 linux-all javax/swing/JTree/4633594/JTreeFocusTest.java 7105441 macosx-all javax/swing/AbstractButton/6711682/bug6711682.java 8060765 windows-all,macosx-all javax/swing/JFileChooser/6396844/TwentyThousandTest.java 8198003 generic-all +javax/swing/JFileChooser/8194044/FileSystemRootTest.java 8327236 windows-all javax/swing/JPopupMenu/6800513/bug6800513.java 7184956 macosx-all javax/swing/JTabbedPane/8007563/Test8007563.java 8051591 generic-all javax/swing/JTabbedPane/4624207/bug4624207.java 8064922 macosx-all @@ -669,7 +672,6 @@ java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java 8274106 m javax/swing/JFrame/8175301/ScaledFrameBackgroundTest.java 8274106 macosx-aarch64 java/awt/Mouse/EnterExitEvents/DragWindowTest.java 8298823 macosx-all -java/awt/Focus/NonFocusableWindowTest/NonfocusableOwnerTest.java 8280392 windows-x64 java/awt/Mixing/AWT_Mixing/OpaqueOverlapping.java 8294264 windows-x64 java/awt/Mixing/AWT_Mixing/ViewportOverlapping.java 8253184,8295813 windows-x64 @@ -690,6 +692,7 @@ sanity/client/SwingSet/src/EditorPaneDemoTest.java 8212240 linux-x64 # This test fails on macOS 14 javax/swing/plaf/synth/7158712/bug7158712.java 8324782 macosx-all +javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java 8316151 macosx-all ############################################################################ @@ -791,7 +794,7 @@ java/awt/print/Dialog/RestoreActiveWindowTest/RestoreActiveWindowTest.java 81854 java/awt/TrayIcon/DblClickActionEventTest/DblClickActionEventTest.html 8203867 macosx-all java/awt/Frame/FrameStateTest/FrameStateTest.html 8203920 macosx-all,linux-all java/awt/print/PrinterJob/ScaledText/ScaledText.java 8231226 macosx-all -java/awt/font/TextLayout/TestJustification.html 8250791 macosx-all +java/awt/font/TextLayout/TestJustification.java 8250791 macosx-all java/awt/TrayIcon/DragEventSource/DragEventSource.java 8252242 macosx-all java/awt/FileDialog/DefaultFocusOwner/DefaultFocusOwner.java 7187728 macosx-all,linux-all java/awt/FileDialog/RegexpFilterTest/RegexpFilterTest.html 7187728 macosx-all,linux-all diff --git a/test/jdk/TEST.ROOT b/test/jdk/TEST.ROOT index b59f90f12c4..25ef8250e4d 100644 --- a/test/jdk/TEST.ROOT +++ b/test/jdk/TEST.ROOT @@ -9,17 +9,41 @@ # should be taken to handle test failures of intermittent or # randomness tests. # -# A "headful" test requires a graphical environment to meaningfully -# run. Tests that are not headful are "headless". -# A test flagged with key sound needs audio devices on the system, this -# may be accompanied by the headful keyword since audio device access +# A test flagged with cgroups uses cgroups. +# +# Notes on "client" keywords : headful sound printer multimon +# =========================================================== +# +# These keywords are there to help with test selection so that +# tests that need a particular resource can be selected to run on a system +# with that resource. Conversely "!somekeyword" can be used to exclude tests +# on a system without such a resource. +# Caution: If you are always excluding tests using any of these keywords then you +# are likely missing many important tests. +# +# "headful". A "headful" test requires a graphical environment to meaningfully run. +# This does not have to mean a physical host, since a VM can be configured as headful. +# Tests that are not headful are "headless". +# Note: all manual tests are assumed to be headful and do not need the keyword. +# +# "printer". Not all tests of printing APIs require a printer, but many do. +# So a "printer" test requires a printer to be installed to do anything meaningful. +# Tests may not fail if there is none, instead just silently return. +# But they also may legitimately throw an Exception depending on the test. +# Also printer tests are not necessarily headful, but some are, and some are automated. +# +# "sound". Similarly, not all sound tests require audio devices, but many do. +# A test flagged with key "sound" needs audio devices on the system. +# Also they are not necessarily "headful", since they don't require a display etc. +# But sometimes they may be accompanied by the headful keyword, since sound # is often linked to access to desktop resources and headful systems are # also more likely to have audio devices (ie meaning both input and output) -# A test flagged with key "printer" requires a printer to succeed, else -# throws a PrinterException or the like. -# A test flagged with cgroups uses cgroups. +# +# "multimon" should be used in conjunction with headful and is used to identify +# tests which require two displays connected. -keys=2d dnd headful sound i18n intermittent printer randomness jfr cgroups +keys=headful sound printer multimon \ + i18n intermittent randomness jfr cgroups # Tests that must run in othervm mode othervm.dirs=java/awt java/beans javax/accessibility javax/imageio javax/sound javax/swing javax/print \ @@ -73,6 +97,7 @@ requires.properties= \ vm.hasSA \ vm.hasJFR \ vm.jvmci \ + vm.jvmci.enabled \ vm.jvmti \ docker.support \ release.implementor \ diff --git a/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java b/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java index 27b72b5cf7c..22c5c89b57b 100644 --- a/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java +++ b/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,9 @@ * @bug 8297878 * @summary Key Encapsulation Mechanism API * @library /test/lib + * @build java.base/com.sun.crypto.provider.EvenKEMImpl * @modules java.base/com.sun.crypto.provider + * @run main/othervm Compliance */ import jdk.test.lib.Asserts; import jdk.test.lib.Utils; @@ -45,18 +47,19 @@ import com.sun.crypto.provider.DHKEM; +import static com.sun.crypto.provider.EvenKEMImpl.isEven; + public class Compliance { public static void main(String[] args) throws Exception { basic(); conform(); determined(); - try { - Security.insertProviderAt(new ProviderImpl(), 1); - delayed(); - } finally { - Security.removeProvider("XP"); - } + // Patch an alternate DHKEM in SunEC which is ahead of SunJCE + // in security provider listing. + Security.getProvider("SunEC") + .put("KEM.DHKEM", "com.sun.crypto.provider.EvenKEMImpl"); + delayed(); } // Encapsulated conformance checks @@ -220,34 +223,6 @@ static byte[] calcDetermined(long seed) throws Exception { return enc2; } - public static class ProviderImpl extends Provider { - ProviderImpl() { - super("XP", "1", "XP"); - put("KEM.DHKEM", "Compliance$KEMImpl"); - } - } - - static boolean isEven(Key k) { - return Arrays.hashCode(k.getEncoded()) % 2 == 0; - } - - public static class KEMImpl extends DHKEM { - - @Override - public EncapsulatorSpi engineNewEncapsulator(PublicKey pk, AlgorithmParameterSpec spec, SecureRandom secureRandom) - throws InvalidAlgorithmParameterException, InvalidKeyException { - if (!isEven(pk)) throw new InvalidKeyException("Only accept even keys"); - return super.engineNewEncapsulator(pk, spec, secureRandom); - } - - @Override - public DecapsulatorSpi engineNewDecapsulator(PrivateKey sk, AlgorithmParameterSpec spec) - throws InvalidAlgorithmParameterException, InvalidKeyException { - if (!isEven(sk)) throw new InvalidKeyException("Only accept even keys"); - return super.engineNewDecapsulator(sk, spec); - } - } - // Ensure delayed provider selection static void delayed() throws Exception { KeyPairGenerator g = KeyPairGenerator.getInstance("X25519"); @@ -266,7 +241,7 @@ static void delayed() throws Exception { KEM.Encapsulator eodd = kem.newEncapsulator(odd); KEM.Encapsulator eeven = kem.newEncapsulator(even); Asserts.assertEQ(eodd.providerName(), "SunJCE"); - Asserts.assertEQ(eeven.providerName(), "XP"); + Asserts.assertEQ(eeven.providerName(), "SunEC"); } static ECPublicKey badECKey() { diff --git a/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java b/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java new file mode 100644 index 00000000000..dc478c25954 --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.crypto.provider; + +import java.security.*; +import java.security.spec.*; +import java.util.Arrays; + +// The alternate DHKEM implementation used by the Compliance.java test. +public class EvenKEMImpl extends DHKEM { + + public static boolean isEven(Key k) { + return Arrays.hashCode(k.getEncoded()) % 2 == 0; + } + + @Override + public EncapsulatorSpi engineNewEncapsulator( + PublicKey pk, AlgorithmParameterSpec spec, SecureRandom secureRandom) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (!isEven(pk)) throw new InvalidKeyException("Only accept even keys"); + return super.engineNewEncapsulator(pk, spec, secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator( + PrivateKey sk, AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (!isEven(sk)) throw new InvalidKeyException("Only accept even keys"); + return super.engineNewDecapsulator(sk, spec); + } +} diff --git a/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java b/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java new file mode 100644 index 00000000000..deffffc0fa8 --- /dev/null +++ b/test/jdk/com/sun/jdi/BreakpointOnClassPrepare.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8333542 + * @summary Missed breakpoint due to JVM not blocking other threads while + * delivering a ClassPrepareEvent. + * + * @run build TestScaffold VMConnection TargetListener TargetAdapter + * @run compile -g BreakpointOnClassPrepare.java + * @run driver BreakpointOnClassPrepare SUSPEND_NONE + * @run driver BreakpointOnClassPrepare SUSPEND_EVENT_THREAD + * @run driver BreakpointOnClassPrepare SUSPEND_ALL + */ + +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; + +import java.util.*; + +// The debuggee spawns 50 threads that call LoadedClass.foo(). The debugger enables +// ClassPrepareEvent for LoadedClass, and sets a breakpoint on LoadedClass.foo() when +// the ClassPrepareEvent arrives. The debugger expects 50 breakpoints to be hit. +// This verifies that the thread that causes the generation of the ClassPrepareEvent +// has properly blocked all other threads from executing LoadedClass.foo() until the +// ClassPrepareEvent has been delivered. + +class LoadedClass { + static void foo(int k) { + System.out.println("HIT = " + k); // set breakpoint here + } +} + +class BreakpointOnClassPrepareTarg { + public static void main(String[] args) throws InterruptedException { + System.out.println("Start"); + Thread threads[] = new Thread[BreakpointOnClassPrepare.NUM_BREAKPOINTS]; + for (int i = 0; i < BreakpointOnClassPrepare.NUM_BREAKPOINTS; i++) { + int k = i; + Thread t = DebuggeeWrapper.newThread(() -> { + System.out.println("k = " + k); + LoadedClass.foo(k); + }); + threads[i] = t; + t.setDaemon(true); + t.setName("MyThread-" + k); + t.start(); + } + + for (int i = 0; i < BreakpointOnClassPrepare.NUM_BREAKPOINTS; i++) { + try { + Thread t = threads[i]; + t.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + System.out.println("Finish"); + } +} + + /********** test program **********/ + +public class BreakpointOnClassPrepare extends TestScaffold { + ClassType targetClass; + ThreadReference mainThread; + + BreakpointOnClassPrepare(String args[]) { + super(args); + } + + public static void main(String[] args) throws Exception { + new BreakpointOnClassPrepare(args).startTests(); + } + + /********** event handlers **********/ + + static final int NUM_BREAKPOINTS = 50; + int bkptCount; + BreakpointRequest bkptRequest; + + public void breakpointReached(BreakpointEvent event) { + bkptCount++; + String threadInfo; + try { + threadInfo = event.thread().toString(); + } catch (ObjectCollectedException e) { + // It's possible the Thread already terminated and was collected + // if the SUSPEND_NONE policy was used. + threadInfo = "(thread collected)"; + } + System.out.println("Got BreakpointEvent: " + bkptCount + " for thread " + threadInfo); + } + + public void vmDisconnected(VMDisconnectEvent event) { + println("Got VMDisconnectEvent"); + } + + /********** test core **********/ + + protected void runTests() throws Exception { + /* Determine which suspend policy to use. */ + int policy; + if (args.length != 1) { + throw new RuntimeException("Invalid number of args: " + args.length); + } + String policyString = args[0]; + if (policyString.equals("SUSPEND_NONE")) { + policy = EventRequest.SUSPEND_NONE; + } else if (policyString.equals("SUSPEND_ALL")) { + policy = EventRequest.SUSPEND_ALL; + } else if (policyString.equals("SUSPEND_EVENT_THREAD")) { + policy = EventRequest.SUSPEND_EVENT_THREAD; + } else { + throw new RuntimeException("Invalid suspend policy: " + policyString); + } + + /* Stop when the target is loaded. */ + BreakpointEvent bpe = startToMain("BreakpointOnClassPrepareTarg"); + + /* Stop when "LoadedClass" is loaded. */ + EventRequestManager erm = vm().eventRequestManager(); + ClassPrepareEvent cpe = resumeToPrepareOf("LoadedClass"); + println("Got ClassPrepareEvent: " + cpe); + + /* Set a breakpoint for each time LoadedClass.foo() is called. */ + ClassType loadedClass = (ClassType)cpe.referenceType() ; + Location loc1 = findMethodLocation(loadedClass, "foo", "(I)V", 1); + bkptRequest = erm.createBreakpointRequest(loc1); + bkptRequest.setSuspendPolicy(policy); + bkptRequest.enable(); + + listenUntilVMDisconnect(); + + if (!testFailed && bkptCount == NUM_BREAKPOINTS) { + println("BreakpointOnClassPrepare: passed"); + } else { + throw new Exception("BreakpointOnClassPrepare: failed. bkptCount == " + bkptCount); + } + } +} diff --git a/test/jdk/com/sun/jdi/JdwpAllowTest.java b/test/jdk/com/sun/jdi/JdwpAllowTest.java index a5c756f8790..c23b0a2ff8c 100644 --- a/test/jdk/com/sun/jdi/JdwpAllowTest.java +++ b/test/jdk/com/sun/jdi/JdwpAllowTest.java @@ -57,7 +57,7 @@ public static int handshake(int port) throws IOException { res = s.getInputStream().read(buffer); } catch (SocketException ex) { - ex.printStackTrace(); + ex.printStackTrace(System.out); // pass } finally { if (s != null) { @@ -98,7 +98,7 @@ private static int detectPort(LingeredApp app) { public static void positiveTest(String testName, String allowOpt) throws InterruptedException, IOException { - System.err.println("\nStarting " + testName); + System.out.println("\nStarting " + testName); String[] cmd = prepareCmd(allowOpt); LingeredApp a = LingeredApp.startApp(cmd); @@ -111,12 +111,12 @@ public static void positiveTest(String testName, String allowOpt) if (res < 0) { throw new RuntimeException(testName + " FAILED"); } - System.err.println(testName + " PASSED"); + System.out.println(testName + " PASSED"); } public static void negativeTest(String testName, String allowOpt) throws InterruptedException, IOException { - System.err.println("\nStarting " + testName); + System.out.println("\nStarting " + testName); String[] cmd = prepareCmd(allowOpt); LingeredApp a = LingeredApp.startApp(cmd); @@ -127,24 +127,24 @@ public static void negativeTest(String testName, String allowOpt) a.stopApp(); } if (res > 0) { - System.err.println(testName + ": res=" + res); + System.out.println(testName + ": res=" + res); throw new RuntimeException(testName + " FAILED"); } - System.err.println(testName + ": returned a negative code as expected: " + res); - System.err.println(testName + " PASSED"); + System.out.println(testName + ": returned a negative code as expected: " + res); + System.out.println(testName + " PASSED"); } public static void badAllowOptionTest(String testName, String allowOpt) throws InterruptedException, IOException { - System.err.println("\nStarting " + testName); + System.out.println("\nStarting " + testName); String[] cmd = prepareCmd(allowOpt); LingeredApp a; try { a = LingeredApp.startApp(cmd); } catch (IOException ex) { - System.err.println(testName + ": caught expected IOException"); - System.err.println(testName + " PASSED"); + System.out.println(testName + ": caught expected IOException"); + System.out.println(testName + " PASSED"); return; } // LingeredApp.startApp is expected to fail, but if not, terminate the app @@ -154,7 +154,7 @@ public static void badAllowOptionTest(String testName, String allowOpt) /* * Generate allow address by changing random bit in the local address - * and calculate 2 masks (prefix length) - one is matches original local address + * and calculate 2 masks (prefix length) - one matches original local address * and another doesn't. */ private static class MaskTest { @@ -167,8 +167,16 @@ public MaskTest(InetAddress addr) throws Exception { localAddress = addr.getHostAddress(); byte[] bytes = addr.getAddress(); Random r = new Random(); - // prefix length must be >= 1, so bitToChange must be >= 2 - int bitToChange = r.nextInt(bytes.length * 8 - 3) + 2; + // Prefix length is 1..32 for IPv4, 1..128 for IPv6. + // bitToChange is zero-based and must be >0 (for 0 "good" prefix length would be 0). + // Corner cases (for 127.0.0.1): + // bitToChange == 1 => allow address = 0.0.0.0 + // - "good" allow mask is "0.0.0.0/1"; + // - "bad" allow mask is "0.0.0.0/2"; + // bitToChange == 31 => allow address = 127.0.0.0 + // - "good" allow mask is "127.0.0.0/31"; + // - "bad" allow mask is "127.0.0.0/32". + int bitToChange = r.nextInt(bytes.length * 8 - 2) + 1; setBit(bytes, bitToChange, !getBit(bytes, bitToChange)); // clear rest of the bits for mask address for (int i = bitToChange + 1; i < bytes.length * 8; i++) { @@ -176,8 +184,8 @@ public MaskTest(InetAddress addr) throws Exception { } allowAddress = InetAddress.getByAddress(bytes).getHostAddress(); - prefixLengthBad = bitToChange; - prefixLengthGood = bitToChange - 1; + prefixLengthGood = bitToChange; + prefixLengthBad = bitToChange + 1; } private static boolean getBit(byte[] bytes, int pos) { @@ -203,7 +211,7 @@ private static void init() throws Exception { throw new RuntimeException("No addresses is returned for 'localhost'"); } localAddr = addrs[0].getHostAddress(); - System.err.println("localhost address: " + localAddr); + System.out.println("localhost address: " + localAddr); for (int i = 0; i < addrs.length; i++) { maskTests.add(new MaskTest(addrs[i])); @@ -243,11 +251,11 @@ public static void main(String[] args) throws Exception { localAddr = test.localAddress; positiveTest("PositiveMaskTest(" + test.localAddress + ")", test.allowAddress + "/" + test.prefixLengthGood); - positiveTest("NegativeMaskTest(" + test.localAddress + ")", + negativeTest("NegativeMaskTest(" + test.localAddress + ")", test.allowAddress + "/" + test.prefixLengthBad); } - System.err.println("\nTest PASSED"); + System.out.println("\nTest PASSED"); } } diff --git a/test/jdk/com/sun/jdi/cds/CDSJDITest.java b/test/jdk/com/sun/jdi/cds/CDSJDITest.java index 0ec201d7035..3bb6ec6ebdf 100644 --- a/test/jdk/com/sun/jdi/cds/CDSJDITest.java +++ b/test/jdk/com/sun/jdi/cds/CDSJDITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ public static void runTest(String testname, String[] jarClasses) throws Exceptio // pass them to the subprocess it will create for the debuggee. This // is how the -javaopts are passed to the debuggee. See // VMConnection.getDebuggeeVMOptions(). - getPropOpt("test.classes"), + getPropOpt("test.class.path"), getPropOpt("test.java.opts"), getPropOpt("test.vm.opts"), // Pass -showversion to the JDI test just so we get a bit of trace output. diff --git a/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java b/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java index b3c7b064b30..83e37f0b475 100644 --- a/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java +++ b/test/jdk/com/sun/management/ThreadMXBean/ThreadCpuTimeArray.java @@ -29,6 +29,7 @@ * getThreadUserTime(long[]). * @author Paul Hohensee * @requires vm.compMode != "Xcomp" + * @run main/othervm ThreadCpuTimeArray */ import java.lang.management.*; diff --git a/test/jdk/java/awt/Choice/ChoicePopupLocation/ChoicePopupLocation.java b/test/jdk/java/awt/Choice/ChoicePopupLocation/ChoicePopupLocation.java index 229b0492f24..49c146c408b 100644 --- a/test/jdk/java/awt/Choice/ChoicePopupLocation/ChoicePopupLocation.java +++ b/test/jdk/java/awt/Choice/ChoicePopupLocation/ChoicePopupLocation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -113,6 +113,8 @@ private static void openPopup(final Choice choice) throws Exception { robot.setAutoDelay(100); robot.setAutoWaitForIdle(true); robot.waitForIdle(); + robot.delay(500); + Point pt = choice.getLocationOnScreen(); robot.mouseMove(pt.x + choice.getWidth() / 2, pt.y + choice.getHeight() / 2); diff --git a/test/jdk/java/awt/Choice/NonFocusablePopupMenuTest.java b/test/jdk/java/awt/Choice/NonFocusablePopupMenuTest.java new file mode 100644 index 00000000000..a22d61caa47 --- /dev/null +++ b/test/jdk/java/awt/Choice/NonFocusablePopupMenuTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6519005 + * @summary regression: Selection the item on the choice don't work properly in vista ultimate. + * @key headful + * @run main NonFocusablePopupMenuTest + */ + +import java.awt.AWTException; +import java.awt.Choice; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.lang.reflect.InvocationTargetException; + +public class NonFocusablePopupMenuTest extends Frame { + Choice choice; + volatile Point pos; + volatile Dimension size; + volatile int selection1, selection2; + + public void performTest() throws AWTException, + InterruptedException, InvocationTargetException { + Robot robot = new Robot(); + robot.setAutoDelay(100); + EventQueue.invokeAndWait(() -> { + choice = new Choice(); + choice.add("111"); + choice.add("222"); + choice.add("333"); + choice.add("444"); + choice.setFocusable(false); + this.add(choice); + this.setLayout(new FlowLayout()); + setSize (200, 200); + setLocationRelativeTo(null); + setVisible(true); + }); + robot.waitForIdle(); + EventQueue.invokeAndWait(() -> { + pos = choice.getLocationOnScreen(); + size = choice.getSize(); + selection1 = choice.getSelectedIndex(); + }); + robot.mouseMove(pos.x + size.width / 2, pos.y + size.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(500); + robot.mouseMove(pos.x + size.width / 2, pos.y + size.height * 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + EventQueue.invokeAndWait(() -> { + selection2 = choice.getSelectedIndex(); + setVisible(false); + dispose(); + }); + if (selection1 == selection2) { + throw new RuntimeException("Can not change choice selection with the mouse click"); + } + } + + public static void main(String[] args) throws AWTException, + InterruptedException, InvocationTargetException { + NonFocusablePopupMenuTest me = new NonFocusablePopupMenuTest(); + me.performTest(); + } +} \ No newline at end of file diff --git a/test/jdk/java/awt/Choice/NonFocusablePopupMenuTest/NonFocusablePopupMenuTest.html b/test/jdk/java/awt/Choice/NonFocusablePopupMenuTest/NonFocusablePopupMenuTest.html deleted file mode 100644 index 37015ec09c0..00000000000 --- a/test/jdk/java/awt/Choice/NonFocusablePopupMenuTest/NonFocusablePopupMenuTest.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - SetFontTest - - - -

SetFontTest
Bug ID: 5010944

- -

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

- - - - diff --git a/test/jdk/java/awt/Choice/NonFocusablePopupMenuTest/NonFocusablePopupMenuTest.java b/test/jdk/java/awt/Choice/NonFocusablePopupMenuTest/NonFocusablePopupMenuTest.java deleted file mode 100644 index 4a10184e0d6..00000000000 --- a/test/jdk/java/awt/Choice/NonFocusablePopupMenuTest/NonFocusablePopupMenuTest.java +++ /dev/null @@ -1,214 +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. - */ - -/* - test - @bug 6519005 - @summary regression: Selection the item on the choice don't work properly in vista ultimate. - @author Dmitry Cherepanov area=awt.choice - @run applet/manual=yesno NonFocusablePopupMenuTest.html -*/ - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.*; - -public class NonFocusablePopupMenuTest extends Applet -{ - public void init() - { - Choice choice = new Choice(); - choice.add("111"); - choice.add("222"); - choice.add("333"); - choice.add("444"); - choice.setFocusable(false); - - this.add(choice); - - this.setLayout (new FlowLayout ()); - - String[] instructions = - { - "1) The applet contains a non-focusable choice, ", - "2) Click on the choice by mouse, try to change the selection of the choice, ", - "3) If it's not possible to change the selection and popup menu is always open ", - " even if you click by mouse on any item of the choice, the test failed, ", - "4) Otherwise, the test passed. " - }; - Sysout.createDialogWithInstructions( instructions ); - - }//End init() - - public void start () - { - - setSize (200,200); - setVisible(true); - validate(); - - }// start() -} - -/* Place other classes related to the test after this line */ - - - - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff --git a/test/jdk/java/awt/Choice/PopupPosTest/PopupPosTest.java b/test/jdk/java/awt/Choice/PopupPosTest/PopupPosTest.java index 73b94b5d150..b7a5cdea072 100644 --- a/test/jdk/java/awt/Choice/PopupPosTest/PopupPosTest.java +++ b/test/jdk/java/awt/Choice/PopupPosTest/PopupPosTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,8 +30,18 @@ @run main PopupPosTest */ -import java.awt.*; -import java.awt.event.*; +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.event.InputEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; public class PopupPosTest { @@ -66,6 +76,7 @@ public TestFrame() { robot = new Robot(); robot.setAutoDelay(50); robot.waitForIdle(); + robot.delay(500); // fix for 6175418. When we take "choice.getHeight()/2" // divider 2 is not sufficiently big to hit into the // small box Choice. We should use bigger divider to get @@ -108,9 +119,9 @@ public void itemStateChanged(ItemEvent ie) { public void mouseMoveAndPressOnChoice(int x, int y){ openChoice(); robot.mouseMove(x, y); - robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.delay(30); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.waitForIdle(); //should close choice after each test stage closeChoice(); @@ -121,9 +132,9 @@ public void openChoice(){ Point pt = choice.getLocationOnScreen(); robot.mouseMove(pt.x + choice.getWidth() - choice.getHeight()/4, pt.y + choice.getHeight()/2); - robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.delay(30); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.waitForIdle(); } public void closeChoice(){ diff --git a/test/jdk/java/awt/Dialog/NestedDialogs/Modal/NestedModalDialogTest.java b/test/jdk/java/awt/Dialog/NestedDialogs/Modal/NestedModalDialogTest.java index f5d85d8a2ad..c7ec4d66000 100644 --- a/test/jdk/java/awt/Dialog/NestedDialogs/Modal/NestedModalDialogTest.java +++ b/test/jdk/java/awt/Dialog/NestedDialogs/Modal/NestedModalDialogTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,12 +54,11 @@ import java.awt.event.KeyEvent; public class NestedModalDialogTest { - private static Frame frame; + private static StartFrame frame; private static IntermediateDialog interDiag; private static TextDialog txtDiag; // Global variables so the robot thread can locate things. - private static Button[] robot_button = new Button[2]; private static TextField robot_text = null; private static Robot robot = null; @@ -78,6 +77,9 @@ private static void blockTillDisplayed(Component comp) { } private static void clickOnComp(Component comp) { + robot.waitForIdle(); + robot.delay(1000); + Rectangle bounds = new Rectangle(comp.getLocationOnScreen(), comp.getSize()); robot.mouseMove(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2); robot.waitForIdle(); @@ -94,11 +96,11 @@ public void testModalDialogs() throws Exception { // launch first frame with firstButton frame = new StartFrame(); blockTillDisplayed(frame); - clickOnComp(robot_button[0]); + clickOnComp(frame.button); // Dialog must be created and onscreen before we proceed. blockTillDisplayed(interDiag); - clickOnComp(robot_button[1]); + clickOnComp(interDiag.button); // Again, the Dialog must be created and onscreen before we proceed. blockTillDisplayed(robot_text); @@ -144,6 +146,8 @@ public void testModalDialogs() throws Exception { */ class StartFrame extends Frame { + public volatile Button button; + /** * Constructs a new instance. */ @@ -168,7 +172,7 @@ public void actionPerformed(ActionEvent e) { pan.add(but); add(pan); setVisible(true); - robot_button[0] = but; + button = but; } } @@ -177,6 +181,7 @@ public void actionPerformed(ActionEvent e) { class IntermediateDialog extends Dialog { Dialog m_parent; + public volatile Button button; public IntermediateDialog(Frame parent) { super(parent, "Intermediate Modal", true /*Modal*/); @@ -193,9 +198,7 @@ public void actionPerformed(ActionEvent e) { pan.add(but); add(pan); pack(); - - // The robot needs to know about us, so set global - robot_button[1] = but; + button = but; } } @@ -215,12 +218,12 @@ public TextDialog(Dialog parent) { } } - public static void main(String[] args) throws RuntimeException, Exception { + public static void main(String[] args) throws Exception { try { new NestedModalDialogTest().testModalDialogs(); } catch (Exception e) { throw new RuntimeException("NestedModalDialogTest object creation " - + "failed"); + + "failed", e); } } } diff --git a/test/jdk/java/awt/Focus/6981400/Test1.java b/test/jdk/java/awt/Focus/6981400/Test1.java index 730e10804fa..ab60129ba94 100644 --- a/test/jdk/java/awt/Focus/6981400/Test1.java +++ b/test/jdk/java/awt/Focus/6981400/Test1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,8 @@ * @bug 6981400 * @summary Tabbing between textfiled do not work properly when ALT+TAB * @author anton.tarasov - * @library ../../regtesthelpers - * @build Util + * @library /java/awt/regtesthelpers /test/lib + * @build Util jdk.test.lib.Platform * @run main Test1 */ @@ -41,12 +41,28 @@ // The FOCUS_LOST/FOCUS_GAINED events order in the original frame is tracked and should be: // b0 -> b1 -> b2 -> b3. -import java.awt.*; -import java.awt.event.*; +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.event.AWTEventListener; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import javax.swing.*; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +import jdk.test.lib.Platform; import test.java.awt.regtesthelpers.Util; public class Test1 { @@ -72,7 +88,7 @@ public class Test1 { static boolean tracking; - public static void main(String[] args) { + public static void main(String[] args) throws Exception { Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() { public void eventDispatched(AWTEvent e) { System.out.println(e); @@ -81,6 +97,7 @@ public void eventDispatched(AWTEvent e) { try { robot = new Robot(); + robot.setAutoDelay(50); } catch (AWTException ex) { throw new RuntimeException("Error: can't create Robot"); } @@ -90,13 +107,13 @@ public void eventDispatched(AWTEvent e) { f0.add(f0b2); f0.add(f0b3); f0.setLayout(new FlowLayout()); - f0.setBounds(0, 100, 400, 200); + f0.setBounds(100, 100, 400, 200); f1.add(f1b0); - f1.setBounds(0, 400, 400, 200); + f1.setBounds(100, 400, 400, 200); f2.add(f2b0); - f2.setBounds(0, 400, 400, 200); + f2.setBounds(100, 400, 400, 200); f0b0.addFocusListener(new FocusAdapter() { @Override @@ -115,6 +132,7 @@ public void focusLost(FocusEvent e) { f0.setVisible(true); Util.waitForIdle(robot); + robot.delay(500); if (!f0b0.isFocusOwner()) { Util.clickOnComp(f0b0, robot); @@ -152,28 +170,29 @@ public void focusLost(FocusEvent e) { System.out.println("\nTest passed."); } - public static void test(Component compToClick) { + public static void test(Component compToClick) throws Exception { tracking = true; robot.keyPress(KeyEvent.VK_TAB); - robot.delay(50); robot.keyRelease(KeyEvent.VK_TAB); - robot.delay(50); + robot.waitForIdle(); robot.keyPress(KeyEvent.VK_TAB); - robot.delay(50); robot.keyRelease(KeyEvent.VK_TAB); - robot.delay(50); + robot.waitForIdle(); robot.keyPress(KeyEvent.VK_TAB); - robot.delay(50); robot.keyRelease(KeyEvent.VK_TAB); + robot.waitForIdle(); - robot.delay(50); Util.clickOnComp(compToClick, robot); - robot.delay(50); - Util.clickOnTitle(f0, robot); + robot.waitForIdle(); + SwingUtilities.invokeAndWait(f0::toFront); + + if (!Platform.isOnWayland()) { + Util.clickOnTitle(f0, robot); + } Util.waitForIdle(robot); diff --git a/test/jdk/java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java b/test/jdk/java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java index 1e5b2789208..35c6b5cdee6 100644 --- a/test/jdk/java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java +++ b/test/jdk/java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,13 +26,27 @@ @key headful @bug 6314575 @summary Tests that previosly focused owned window doesn't steal focus when an owner's component requests focus. - @library ../../regtesthelpers - @build Util + @library /java/awt/regtesthelpers /test/lib + @build Util jdk.test.lib.Platform @run main ActualFocusedWindowBlockingTest */ -import java.awt.*; -import java.awt.event.*; +import java.awt.AWTEvent; +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.KeyboardFocusManager; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.AWTEventListener; +import java.awt.event.FocusEvent; +import java.awt.event.WindowEvent; + +import jdk.test.lib.Platform; import test.java.awt.regtesthelpers.Util; public class ActualFocusedWindowBlockingTest { @@ -44,7 +58,7 @@ public class ActualFocusedWindowBlockingTest { Button wButton = new Button("window button") {public String toString() {return "Window_Button";}}; Button aButton = new Button("auxiliary button") {public String toString() {return "Auxiliary_Button";}}; - public static void main(String[] args) { + public static void main(String[] args) throws Exception { ActualFocusedWindowBlockingTest app = new ActualFocusedWindowBlockingTest(); app.init(); app.start(); @@ -68,7 +82,7 @@ public void eventDispatched(AWTEvent e) { tuneAndShowWindows(new Window[] {owner, win, frame}); } - public void start() { + public void start() throws Exception { System.out.println("\nTest started:\n"); // Test 1. @@ -99,7 +113,12 @@ public void start() { clickOnCheckFocus(fButton); clickOnCheckFocus(aButton); - Util.clickOnTitle(owner, robot); + EventQueue.invokeAndWait(owner::toFront); + + if (!Platform.isOnWayland()) { + Util.clickOnTitle(owner, robot); + } + if (!testFocused(fButton)) { throw new TestFailedException("The owner's component [" + fButton + "] couldn't be focused as the most recent focus owner"); } @@ -117,11 +136,15 @@ void tuneAndShowWindows(Window[] arr) { y += 200; Util.waitForIdle(robot); } + robot.delay(500); } - void clickOnCheckFocus(Component c) { + void clickOnCheckFocus(Component c) throws Exception { if (c instanceof Frame) { - Util.clickOnTitle((Frame)c, robot); + EventQueue.invokeAndWait(() -> ((Frame) c).toFront()); + if (!Platform.isOnWayland()) { + Util.clickOnTitle((Frame) c, robot); + } } else { Util.clickOnComp(c, robot); } diff --git a/test/jdk/java/awt/Focus/ModalDialogInFocusEventTest.java b/test/jdk/java/awt/Focus/ModalDialogInFocusEventTest.java index d4f0d65f071..4c659819c3c 100644 --- a/test/jdk/java/awt/Focus/ModalDialogInFocusEventTest.java +++ b/test/jdk/java/awt/Focus/ModalDialogInFocusEventTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,11 +22,11 @@ */ /* - test + @test + @key headful @bug 4531693 4636269 4681908 4688142 4691646 4721470 @summary Showing modal dialog during dispatching SequencedEvent - @key headful - @run main AutomaticAppletTest + @run main ModalDialogInFocusEventTest */ import java.awt.AWTEvent; @@ -68,6 +68,8 @@ public class ModalDialogInFocusEventTest static final int MAX_STAGE_NUM = stages.length; static final Object stageMonitor = new Object(); + static boolean isOnWayland; + Robot robot = null; Frame frame; Frame oppositeFrame; @@ -209,18 +211,21 @@ public void windowLostFocus(WindowEvent e) { void clickOnFrameTitle(Frame frame) throws InterruptedException, InvocationTargetException { - System.out.println("click on title of " + frame.getName()); - int[] point = new int[2]; - EventQueue.invokeAndWait(() -> { - Point location = frame.getLocationOnScreen(); - Insets insets = frame.getInsets(); - int width = frame.getWidth(); - point[0] = location.x + width / 2; - point[1] = location.y + insets.top / 2; - }); - robot.mouseMove(point[0], point[1]); - robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); - robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + EventQueue.invokeAndWait(frame::toFront); + if (!isOnWayland) { + System.out.println("click on title of " + frame.getName()); + int[] point = new int[2]; + EventQueue.invokeAndWait(() -> { + Point location = frame.getLocationOnScreen(); + Insets insets = frame.getInsets(); + int width = frame.getWidth(); + point[0] = location.x + width / 2; + point[1] = location.y + insets.top / 2; + }); + robot.mouseMove(point[0], point[1]); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } EventQueue.invokeAndWait(frame::requestFocusInWindow); } @@ -344,6 +349,7 @@ public void focusLost(FocusEvent e) { public static void main(String[] args) throws InterruptedException, InvocationTargetException { + isOnWayland = System.getenv("WAYLAND_DISPLAY") != null; ModalDialogInFocusEventTest test = new ModalDialogInFocusEventTest(); test.start(); } diff --git a/test/jdk/java/awt/Focus/NonFocusableBlockedOwnerTest/NonFocusableBlockedOwnerTest.java b/test/jdk/java/awt/Focus/NonFocusableBlockedOwnerTest/NonFocusableBlockedOwnerTest.java index abf8d57cecd..6d5c9a274e9 100644 --- a/test/jdk/java/awt/Focus/NonFocusableBlockedOwnerTest/NonFocusableBlockedOwnerTest.java +++ b/test/jdk/java/awt/Focus/NonFocusableBlockedOwnerTest/NonFocusableBlockedOwnerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,6 +79,7 @@ public void run() { } waitTillShown(dialog); + robot.delay(500); clickOn(button); if (frame == KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow()) { throw new RuntimeException("Test failed!"); diff --git a/test/jdk/java/awt/Focus/NonFocusableWindowTest/NonfocusableOwnerTest.java b/test/jdk/java/awt/Focus/NonFocusableWindowTest/NonfocusableOwnerTest.java index cfabc697f85..7b552424f8d 100644 --- a/test/jdk/java/awt/Focus/NonFocusableWindowTest/NonfocusableOwnerTest.java +++ b/test/jdk/java/awt/Focus/NonFocusableWindowTest/NonfocusableOwnerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,20 +21,29 @@ * questions. */ -/* - @test - @key headful - @bug 6182359 - @summary Tests that Window having non-focusable owner can't be a focus owner. - @library ../../regtesthelpers - @build Util - @run main NonfocusableOwnerTest -*/ - -import java.awt.*; -import java.awt.event.*; import test.java.awt.regtesthelpers.Util; +import java.awt.AWTEvent; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.KeyboardFocusManager; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.AWTEventListener; +import java.awt.event.FocusEvent; +import java.awt.event.WindowEvent; + +/* + ( @test + * @key headful + * @bug 6182359 + * @summary Tests that Window having non-focusable owner can't be a focus owner. + * @library ../../regtesthelpers + * @build Util + * @run main NonfocusableOwnerTest + */ public class NonfocusableOwnerTest { Robot robot = Util.createRobot(); Frame frame; @@ -55,7 +64,7 @@ public void eventDispatched(AWTEvent e) { } }, FocusEvent.FOCUS_EVENT_MASK | WindowEvent.WINDOW_FOCUS_EVENT_MASK | WindowEvent.WINDOW_EVENT_MASK); - frame = new Frame("Frame"); + frame = new Frame("NonfocusableOwnerTest"); frame.setName("Frame-owner"); frame.setBounds(100, 0, 100, 100); dialog = new Dialog(frame, "Dialog"); @@ -92,9 +101,11 @@ void test1(Window owner, Window child) { owner.setFocusableWindowState(false); owner.setVisible(true); + robot.waitForIdle(); child.add(button); child.setVisible(true); + robot.waitForIdle(); Util.waitTillShown(child); @@ -111,12 +122,15 @@ void test2(Window owner, Window child1, Window child2) { owner.setFocusableWindowState(false); owner.setVisible(true); + robot.waitForIdle(); child1.setFocusableWindowState(true); child1.setVisible(true); + robot.waitForIdle(); child2.add(button); child2.setVisible(true); + robot.waitForIdle(); Util.waitTillShown(child2); @@ -134,13 +148,16 @@ void test3(Window owner, Window child1, Window child2) { owner.setFocusableWindowState(true); owner.setVisible(true); + robot.waitForIdle(); child1.setFocusableWindowState(false); child1.setVisible(true); + robot.waitForIdle(); child2.setFocusableWindowState(true); child2.add(button); child2.setVisible(true); + robot.waitForIdle(); Util.waitTillShown(child2); diff --git a/test/jdk/java/awt/Focus/OwnedWindowFocusIMECrashTest/OwnedWindowFocusIMECrashTest.java b/test/jdk/java/awt/Focus/OwnedWindowFocusIMECrashTest/OwnedWindowFocusIMECrashTest.java index 6fe6b6a1fa5..f81b25cb1d4 100644 --- a/test/jdk/java/awt/Focus/OwnedWindowFocusIMECrashTest/OwnedWindowFocusIMECrashTest.java +++ b/test/jdk/java/awt/Focus/OwnedWindowFocusIMECrashTest/OwnedWindowFocusIMECrashTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,6 +64,7 @@ public void start() { window.setVisible(true); Util.waitForIdle(robot); + robot.delay(1000); test(); diff --git a/test/jdk/java/awt/Focus/RowToleranceTransitivityTest.java b/test/jdk/java/awt/Focus/RowToleranceTransitivityTest.java index 099e81a1ab0..e3ea5ce0c0c 100644 --- a/test/jdk/java/awt/Focus/RowToleranceTransitivityTest.java +++ b/test/jdk/java/awt/Focus/RowToleranceTransitivityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ @summary Tests for a transitivity problem with ROW_TOLERANCE in SortingFTP. @run main RowToleranceTransitivityTest */ -import java.awt.BorderLayout; + import java.awt.Component; import java.awt.Dimension; import java.awt.EventQueue; @@ -36,7 +36,6 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.KeyboardFocusManager; -import java.awt.Panel; import java.awt.Point; import java.awt.Robot; import java.awt.event.FocusAdapter; @@ -49,8 +48,6 @@ import javax.swing.JLabel; import javax.swing.JPanel; import java.util.concurrent.atomic.AtomicBoolean; -import java.lang.reflect.InvocationTargetException; -import java.util.concurrent.atomic.AtomicBoolean; public class RowToleranceTransitivityTest { static JFrame frame; @@ -60,7 +57,7 @@ public class RowToleranceTransitivityTest { static GridBagConstraints gc; static Robot robot; - static AtomicBoolean focusGained = new AtomicBoolean(false); + static final AtomicBoolean focusGained = new AtomicBoolean(false); public static void main(String[] args) throws Exception { robot = new Robot(); @@ -121,6 +118,7 @@ public void focusGained(FocusEvent e) { robot.delay(1000); test(); } finally { + robot.keyRelease(KeyEvent.VK_TAB); if (frame != null) { frame.dispose(); } diff --git a/test/jdk/java/awt/Focus/WrongKeyTypedConsumedTest/WrongKeyTypedConsumedTest.java b/test/jdk/java/awt/Focus/WrongKeyTypedConsumedTest/WrongKeyTypedConsumedTest.java index 7a71d5f77f8..bae0e493634 100644 --- a/test/jdk/java/awt/Focus/WrongKeyTypedConsumedTest/WrongKeyTypedConsumedTest.java +++ b/test/jdk/java/awt/Focus/WrongKeyTypedConsumedTest/WrongKeyTypedConsumedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,6 +75,7 @@ public void start () frame.setLocationRelativeTo(null); frame.setVisible(true); Util.waitForIdle(robot); + robot.delay(500); if (!frame.isActive()) { throw new RuntimeException("Test Fialed: frame isn't active"); diff --git a/test/jdk/java/awt/FontMetrics/ExtremeFontSizeTest.java b/test/jdk/java/awt/FontMetrics/ExtremeFontSizeTest.java new file mode 100644 index 00000000000..caa365a3f21 --- /dev/null +++ b/test/jdk/java/awt/FontMetrics/ExtremeFontSizeTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; + +/* + * @test + * @bug 8328896 + * @summary test that using very large font sizes used don't break later uses + */ + +public class ExtremeFontSizeTest { + + static BufferedImage bi = new BufferedImage(1,1,1); + static Graphics2D g2d = bi.createGraphics(); + static String testString = "M"; + static Font font = new Font("SansSerif", Font.PLAIN, 12); + static int fontSize = 0; + static boolean failed = false; + static int[] fontSizes = { 10, 12, 1000, 2000, 20000, 100000, 8 }; + static double[] scales = { 1.0, 900.0}; + static boolean[] fms = { false, true }; + + public static void main(String[] args) { + + /* run tests validating bounds etc are non-zero + * then run with extreme scales for which zero is allowed - but not required + * then run the first tests again to be sure they are still reasonable. + */ + runTests(); + test(5_000_000, 10_000, false, testString, false); + test(5_000_000, 10_000, true, testString, false); + test(0, 0.00000001, false, testString, false); + runTests(); + + if (failed) { + throw new RuntimeException("Test failed. Check stdout log."); + } + } + + static void runTests() { + for (int fontSize : fontSizes) { + for (double scale : scales) { + for (boolean fm : fms) { + test(fontSize, scale, fm, testString, true); + } + } + } + } + + static void test(int size, double scale, boolean fm, String str, boolean checkAll) { + + AffineTransform at = AffineTransform.getScaleInstance(scale, scale); + FontRenderContext frc = new FontRenderContext(at, false, fm); + font = font.deriveFont((float)size); + g2d.setTransform(at); + g2d.setFont(font); + FontMetrics metrics = g2d.getFontMetrics(); + int height = metrics.getHeight(); + double width = font.getStringBounds(str, frc).getWidth(); + + GlyphVector gv = font.createGlyphVector(frc, str.toCharArray()); + Rectangle pixelBounds = gv.getPixelBounds(frc, 0, 0); + Rectangle2D visualBounds = gv.getVisualBounds(); + + System.out.println("Test parameters: size="+size+" scale="+scale+" fm="+fm+" str="+str); + System.out.println("font height="+metrics.getHeight()); + System.out.println("string bounds width="+width); + System.out.println("GlyphVector Pixel Bounds="+ pixelBounds); + System.out.println("GlyphVector Visual Bounds="+ visualBounds); + + + if (height < 0 || width < 0 || pixelBounds.getWidth() < 0 || visualBounds.getWidth() < 0) { + failed = true; + System.out.println(" *** Unexpected negative size reported *** "); + } + if (!checkAll) { + System.out.println(); + return; + } + + if (height == 0 || width == 0 || (pixelBounds.isEmpty()) || visualBounds.isEmpty() ) { + failed = true; + System.out.println("Pixel bounds empty="+pixelBounds.isEmpty()); + System.out.println("Visual bounds empty="+visualBounds.isEmpty()); + System.out.println(" *** RESULTS NOT AS EXPECTED *** "); + } + System.out.println(); + } +} diff --git a/test/jdk/java/awt/Frame/DefaultSizeTest.java b/test/jdk/java/awt/Frame/DefaultSizeTest.java new file mode 100644 index 00000000000..dff1ff147c5 --- /dev/null +++ b/test/jdk/java/awt/Frame/DefaultSizeTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * 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.EventQueue; +import java.awt.Frame; + +/* + * @test 4033151 + * @summary Test that frame default size is minimum possible size + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DefaultSizeTest + */ + +public class DefaultSizeTest { + + private static final String INSTRUCTIONS = """ + An empty frame is created. + It should be located to the right of this window + and should be the minimum size allowed by the window manager. + For any WM, the frame should be very small. + If the frame is not large, click Pass or Fail otherwise. + """; + + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("DefaultSizeTest Instructions Frame") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(10) + .columns(45) + .screenCapture() + .build(); + + EventQueue.invokeAndWait(() -> { + Frame frame = new Frame("DefaultSize"); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame + .positionTestWindow(frame, PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Frame/FrameRepackTest.java b/test/jdk/java/awt/Frame/FrameRepackTest.java new file mode 100644 index 00000000000..4f77d195ca6 --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameRepackTest.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.ScrollPane; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @key headful + * @summary Test dynamically changing frame component visibility and repacking + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameRepackTest + */ + +public class FrameRepackTest { + + private static final String INSTRUCTIONS = """ + There is a green frame with a menubar. + The menubar has one menu, labelled 'Flip'. + The menu has two items, labelled 'visible' and 'not visible'. + The frame also contains a red panel that contains two line labels, + 'This panel is always displayed' and 'it is a test'. + + If you select the menu item 'Flip->visible', then another panel is + added below the red panel. + The added panel is blue and has yellow horizontal and vertical scrollbars. + + If you select menu item 'Flip->not visible', the second panel + is removed and the frame appears as it did originally. + + You can repeatedly add and remove the second panel in this way. + After such an addition or removal, the frame's location on the screen + should not change, while the size changes to accommodate + either just the red panel or both the red and the blue panels. + + If you resize the frame larger, the red panel remains at the + top of the frame with its height fixed and its width adjusted + to the width of the frame. + + Similarly, if it is present, the blue panel and its yellow scroolbars + remain at the bottom of the frame with fixed height and width adjusted + to the size of the frame. But selecting 'visible' or 'not visible' + repacks the frame, thereby adjusting its size tightly to its panel(s). + + Upon test completion, click Pass or Fail appropriately. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("FrameRepackTest Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(30) + .columns(45) + .build(); + + EventQueue.invokeAndWait(() -> { + FrameRepack frame = new FrameRepack(); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } + +} + +class FrameRepack extends Frame implements ActionListener { + + Panel south; + + public FrameRepack() { + super("FrameRepack"); + + // create the menubar + MenuBar menubar = new MenuBar(); + this.setMenuBar(menubar); + // create the options + Menu flip = new Menu("Flip"); + MenuItem mi; + mi = new MenuItem("visible"); + mi.addActionListener(this); + flip.add(mi); + mi = new MenuItem("not visible"); + mi.addActionListener(this); + flip.add(mi); + + menubar.add(flip); + + setLayout(new BorderLayout(2, 2)); + setBackground(Color.green); + + // north panel is always displayed + Panel north = new Panel(); + north.setBackground(Color.red); + north.setLayout(new BorderLayout(2, 2)); + north.add("North", new Label("This panel is always displayed")); + north.add("Center", new Label("it is a test")); + north.setSize(200, 200); + add("North", north); + + // south panel can be visible or not... + // The problem seems to occur when I put this panel not visible + south = new Panel(); + south.setBackground(Color.white); + south.setLayout(new BorderLayout()); + + ScrollPane scroller = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS); + scroller.setBackground(Color.yellow); + Panel pan1 = new Panel(); + pan1.setBackground(Color.blue); + pan1.setLayout(new BorderLayout()); + + pan1.setSize(400, 150); + scroller.add("Center", pan1); + + south.add("South", scroller); + + add("South", south); + + south.setVisible(false); + + setSize(350, 300); + + pack(); + } + + @Override + public void actionPerformed(ActionEvent evt) { + if (evt.getSource() instanceof MenuItem) { + if (evt.getActionCommand().equals("visible")) { + south.setVisible(true); + pack(); + } else if (evt.getActionCommand().equals("not visible")) { + south.setVisible(false); + pack(); + } + } + } +} diff --git a/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_1.java b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_1.java new file mode 100644 index 00000000000..7503672fccd --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_1.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; + +/* + * @test + * @bug 4041442 + * @key headful + * @summary Test resizing a frame containing a canvas + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameResizeTest_1 + */ + +public class FrameResizeTest_1 { + + private static final String INSTRUCTIONS = """ + To the right of this frame is an all-white 200x200 frame. + + This is actually a white canvas component in the frame. + The frame itself is red. + The red should never show. + In particular, after you resize the frame, you should see all white and no red. + (During very fast window resizing, red color may appear briefly, + which is not a failure.) + + Upon test completion, click Pass or Fail appropriately. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("FrameResizeTest_1 Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(12) + .columns(45) + .build(); + + EventQueue.invokeAndWait(() -> { + FrameResize_1 frame = new FrameResize_1(); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} + +class FrameResize_1 extends Frame { + + FrameResize_1() { + super("FrameResize_1"); + // Create a white canvas + Canvas canvas = new Canvas(); + canvas.setBackground(Color.white); + + setLayout(new BorderLayout()); + add("Center", canvas); + + setBackground(Color.red); + setSize(200,200); + } +} diff --git a/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_2.java b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_2.java new file mode 100644 index 00000000000..e8fdd52522b --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_2.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Panel; + +/* + * @test + * @bug 4065568 + * @key headful + * @summary Test resizing a frame containing a canvas + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameResizeTest_2 + */ + +public class FrameResizeTest_2 { + private static final String INSTRUCTIONS = """ + There is a frame (size 300x300). + The left half is red and the right half is blue. + + When you resize the frame, it should still have a red left half + and a blue right half. + + In particular, no green should be visible after a resize. + + Upon test completion, click Pass or Fail appropriately. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("FrameResizeTest_2 Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(10) + .columns(45) + .build(); + + EventQueue.invokeAndWait(() -> { + FrameResize_2 frame = new FrameResize_2(); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} + +class FrameResize_2 extends Frame { + + FrameResize_2() { + super("FrameResize_2"); + + setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + c.weighty = 1; + + Container dumbContainer = new DumbContainer(); + add(dumbContainer, c); + + Panel dumbPanel = new DumbPanel(); + add(dumbPanel, c); + + setSize(300, 300); + } +} + + +class Fake extends Canvas { + public Fake(String name, Color what) { + setBackground(what); + setName(name); + } + + public void paint(Graphics g) { + Dimension d = getSize(); + g.setColor(getBackground()); + g.fillRect(0, 0, d.width, d.height); + } +} + +class DumbContainer extends Container { + public DumbContainer() { + setLayout(new BorderLayout()); + add("Center", new Fake("dumbc", Color.red)); + } + + public void paint(Graphics g) { + Dimension d = getSize(); + g.setColor(Color.green); + g.fillRect(0, 0, d.width, d.height); + super.paint(g); + } +} + +class DumbPanel extends Panel { + public DumbPanel() { + setLayout(new BorderLayout()); + add("Center", new Fake("dumbp", Color.blue)); + } + + public void paint(Graphics g) { + Dimension d = getSize(); + g.setColor(Color.green); + g.fillRect(0, 0, d.width, d.height); + super.paint(g); + } +} diff --git a/test/jdk/java/awt/Frame/GetBoundsResizeTest.java b/test/jdk/java/awt/Frame/GetBoundsResizeTest.java new file mode 100644 index 00000000000..d3c2ffb0bad --- /dev/null +++ b/test/jdk/java/awt/Frame/GetBoundsResizeTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.Button; +import java.awt.Frame; +import java.awt.EventQueue; +import java.awt.Robot; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +/* + * @test + * @bug 4103095 + * @summary Test for getBounds() after a Frame resize. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual GetBoundsResizeTest +*/ + +public class GetBoundsResizeTest { + private static final String INSTRUCTIONS = """ + 0. There is a test window with a "Press" button, + Its original bounds should be printed in the text area below. + 1. Resize the test window using the upper left corner. + 2. Press the button to print the result of getBounds() to the text area. + 3. Previously, a window could report an incorrect position on the + screen after resizing the window in this way. + If getBounds() prints the appropriate values for the window, + click Pass, otherwise click Fail. + """; + + private static JTextArea textArea; + private static Frame frame; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + PassFailJFrame passFailJFrame = PassFailJFrame + .builder() + .title("GetBoundsResizeTest Instructions") + .instructions(INSTRUCTIONS) + .splitUIBottom(() -> { + textArea = new JTextArea("", 8, 55); + textArea.setEditable(false); + return new JScrollPane(textArea); + }) + .testUI(GetBoundsResizeTest::getFrame) + .rows((int) (INSTRUCTIONS.lines().count() + 2)) + .columns(40) + .build(); + + robot.waitForIdle(); + robot.delay(500); + + EventQueue.invokeAndWait(() -> + logFrameBounds("Original Frame.getBounds() = %s\n")); + + passFailJFrame.awaitAndCheck(); + } + + private static Frame getFrame() { + frame = new Frame("GetBoundsResizeTest"); + + Button button = new Button("Press"); + button.addActionListener((e) -> + logFrameBounds("Current Frame.getBounds() = %s\n")); + + frame.add(button); + frame.setSize(200, 100); + + return frame; + } + + private static void logFrameBounds(String format) { + textArea.append(format.formatted(frame.getBounds())); + } +} diff --git a/test/jdk/java/awt/Frame/GetBoundsResizeTest/GetBoundsResizeTest.java b/test/jdk/java/awt/Frame/GetBoundsResizeTest/GetBoundsResizeTest.java deleted file mode 100644 index 9dad65ddd2c..00000000000 --- a/test/jdk/java/awt/Frame/GetBoundsResizeTest/GetBoundsResizeTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test - @bug 4103095 - @summary Test for getBounds() after a Frame resize. - @author andrei.dmitriev : area=awt.toplevel - @run main/manual GetBoundsResizeTest -*/ - -import java.applet.Applet; -import java.lang.*; -import java.awt.*; -import java.awt.event.*; - -class Globals { - static boolean testPassed=false; - static Thread mainThread=null; -} - -public class GetBoundsResizeTest extends Applet { - - public static void main(String args[]) throws Exception { - GetBoundsResizeTest app = new GetBoundsResizeTest(); - app.start(); - Globals.mainThread = Thread.currentThread(); - try { - Thread.sleep(300000); - } catch (InterruptedException e) { - if (!Globals.testPassed) - throw new Exception("GetBoundsResizeTest failed."); - } - } - - public void start() - { - String[] message = { - "Resize the window using the upper left corner.", - "Press the button to print the result of getBounds() to the terminal.", - "If getBounds() prints the correct values for the window", - "then click Pass, else click Fail." - }; - new TestDialog(new Frame(), "GetBoundsResizeTest", message).start(); - new GetBoundsResizeTester("GetBoundsResizeTester").start(); - } -} - -//////////////////////////////////////////////////////////////////////// -// Test Dialog -//////////////////////////////////////////////////////////////////////// - -class TestDialog extends Dialog - implements ActionListener { - - static TextArea output; - Button passButton; - Button failButton; - String name; - - public TestDialog(Frame frame, String name, String[] message) - { - super(frame, name + " Pass/Fail Dialog"); - this.name = name; - int maxStringLength = 0; - for (int i=0; i { + if (test.frame != null) { + test.frame.dispose(); + } + if (test.frame2 != null) { + test.frame2.dispose(); + } + }); + } } public ActiveAWTWindowTest() { @@ -105,7 +115,7 @@ public void windowDeactivated(WindowEvent e) { System.out.println("Undecorated Frame got Deactivated\n"); synchronized (lock2) { try { - lock2.notifyAll(); + lock2.notifyAll(); } catch (Exception ex) { ex.printStackTrace(); } @@ -146,6 +156,7 @@ public void actionPerformed(ActionEvent e) { } public void doTest() { + ExtendedRobot robot; try { robot = new ExtendedRobot(); } catch (Exception e) { @@ -153,13 +164,14 @@ public void doTest() { throw new RuntimeException("Cannot create robot"); } + robot.setAutoDelay(delay); + robot.setAutoWaitForIdle(true); + robot.waitForIdle(5*delay); robot.mouseMove(button.getLocationOnScreen().x + button.getSize().width / 2, button.getLocationOnScreen().y + button.getSize().height / 2); - robot.waitForIdle(delay); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.waitForIdle(delay); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); if (eventType != WindowEvent.WINDOW_ACTIVATED) { synchronized (lock1) { @@ -176,15 +188,12 @@ public void doTest() { "undecorated frame is activated!"); } - eventType1 = -1; eventType = -1; robot.mouseMove(button2.getLocationOnScreen().x + button2.getSize().width / 2, button2.getLocationOnScreen().y + button2.getSize().height / 2); - robot.waitForIdle(delay); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.waitForIdle(delay); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); if (eventType != WindowEvent.WINDOW_DEACTIVATED) { synchronized (lock2) { diff --git a/test/jdk/java/awt/Frame/MiscUndecorated/RepaintTest.java b/test/jdk/java/awt/Frame/MiscUndecorated/RepaintTest.java index ce4ecc7e36c..cf286601001 100644 --- a/test/jdk/java/awt/Frame/MiscUndecorated/RepaintTest.java +++ b/test/jdk/java/awt/Frame/MiscUndecorated/RepaintTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,27 +28,29 @@ * all the components on it are repainted correctly * @author Jitender(jitender.singh@eng.sun.com) area=AWT * @author yan - * @library /lib/client - * @build ExtendedRobot + * @library /lib/client /test/lib + * @build ExtendedRobot jdk.test.lib.Platform * @run main RepaintTest */ +import jdk.test.lib.Platform; + import java.awt.BorderLayout; import java.awt.Button; import java.awt.Color; import java.awt.Component; import java.awt.Container; +import java.awt.EventQueue; import java.awt.Frame; import java.awt.Panel; import java.awt.Point; import java.awt.Rectangle; import java.awt.TextField; -import java.awt.Toolkit; -import java.awt.event.*; import javax.swing.JFrame; import javax.swing.JButton; import javax.swing.JTextField; import javax.swing.JPanel; +import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.awt.image.PixelGrabber; import java.io.File; @@ -57,38 +59,24 @@ public class RepaintTest { private static final int delay = 150; private Frame frame; - private Container panel1, panel2; private Component button; private Component textField; private ExtendedRobot robot; private final Object buttonLock = new Object(); - private boolean passed = true; - private boolean buttonClicked = false; + private volatile boolean buttonClicked = false; private final int MAX_TOLERANCE_LEVEL = 10; - public static void main(String[] args) { + public static void main(String[] args) throws Exception { RepaintTest test = new RepaintTest(); - test.doTest(false); try { - Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(new Runnable() { - public void run() { - test.frame.dispose(); - } - }); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Unexpected Exception occured"); + test.doTest(false); + } finally { + EventQueue.invokeAndWait(test::dispose); } - test.doTest(true); try { - Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(new Runnable() { - public void run() { - test.frame.dispose(); - } - }); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Unexpected Exception occured"); + test.doTest(true); + } finally { + EventQueue.invokeAndWait(test::dispose); } } @@ -101,8 +89,8 @@ private void initializeGUI(boolean swingControl) { button = createButton(swingControl, (swingControl ? "Swing Button" : "AWT Button")); textField = swingControl ? new JTextField("TextField") : new TextField("TextField"); - panel1 = swingControl ? new JPanel() : new Panel(); - panel2 = swingControl ? new JPanel() : new Panel(); + Container panel1 = swingControl ? new JPanel() : new Panel(); + Container panel2 = swingControl ? new JPanel() : new Panel(); panel1.add(button); panel2.add(textField); frame.add(panel2, BorderLayout.SOUTH); @@ -112,58 +100,44 @@ private void initializeGUI(boolean swingControl) { frame.setBackground(Color.green); frame.setVisible(true); } + + private void dispose() { + if (frame != null) { + frame.dispose(); + } + } + private Component createButton(boolean swingControl, String txt) { + ActionListener actionListener = e -> { + buttonClicked = true; + System.out.println("Clicked!!"); + synchronized (buttonLock) { + try { + buttonLock.notifyAll(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + }; + if(swingControl) { JButton jbtn = new JButton(txt); - jbtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - buttonClicked = true; - synchronized (buttonLock) { - try { - buttonLock.notifyAll(); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - } - }); + jbtn.addActionListener(actionListener); return jbtn; } else { Button btn = new Button(txt); - btn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - buttonClicked = true; - synchronized (buttonLock) { - try { - buttonLock.notifyAll(); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - } - }); + btn.addActionListener(actionListener); return btn; } } - public void doTest(boolean swingControl) { - try { - Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(new Runnable() { - public void run() { - initializeGUI(swingControl); - } - }); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Interrupted or unexpected Exception occured"); - } - try { - robot = new ExtendedRobot(); - robot.waitForIdle(1000); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Cannot create robot"); - } + public void doTest(boolean swingControl) throws Exception { + + robot = new ExtendedRobot(); + robot.setAutoDelay(50); + + EventQueue.invokeAndWait(() -> initializeGUI(swingControl)); + robot.waitForIdle(1000); robot.mouseMove(button.getLocationOnScreen().x + button.getSize().width / 2, button.getLocationOnScreen().y + button.getSize().height / 2); @@ -180,54 +154,50 @@ public void run() { } } if (! buttonClicked) { - passed = false; System.err.println("ActionEvent not triggered when " + "button is clicked!"); throw new RuntimeException("ActionEvent not triggered"); } - robot.waitForIdle(delay * 5); // Need to wait until look of the button + robot.waitForIdle(1000); // Need to wait until look of the button // returns to normal undepressed - passed = paintAndRepaint(button, (swingControl? "J": "")+"Button"); - if( !paintAndRepaint(button, (swingControl? "J": "")+"TextField") ) { - passed = false; - } - if(!passed) { + + if (!paintAndRepaint(button, (swingControl ? "J" : "") + "Button") + || !paintAndRepaint(textField, (swingControl ? "J" : "") + "TextField")) { throw new RuntimeException("Test failed"); } } - private boolean paintAndRepaint(Component comp, String prefix) { + private boolean paintAndRepaint(Component comp, String prefix) throws Exception { + boolean passed = true; //Capture the component & compare it's dimensions //before iconifying & after frame comes back from //iconified to normal state - System.out.println("paintAndRepaint "+prefix); + System.out.printf("paintAndRepaint %s %s\n", prefix, comp); Point p = comp.getLocationOnScreen(); Rectangle bRect = new Rectangle((int)p.getX(), (int)p.getY(), comp.getWidth(), comp.getHeight()); BufferedImage capturedImage = robot.createScreenCapture(bRect); + BufferedImage frameImage = robot.createScreenCapture(frame.getBounds()); - try { - Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(new Runnable() { - public void run() { - frame.setExtendedState(Frame.ICONIFIED); - } - }); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Exception while setting extended state ICONIFIED"); - } - robot.waitForIdle(delay * 5); - try { - Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(new Runnable() { - public void run() { - frame.setExtendedState(Frame.NORMAL); - } - }); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Exception while setting extended state NORMAL"); + EventQueue.invokeAndWait(() -> frame.setExtendedState(Frame.ICONIFIED)); + robot.waitForIdle(1500); + EventQueue.invokeAndWait(() -> frame.setExtendedState(Frame.NORMAL)); + robot.waitForIdle(1500); + + if (Platform.isOnWayland()) { + // Robot.mouseMove does not move the actual mouse cursor on the + // screen in X11 compatibility mode on Wayland, but only within + // the XWayland server. + // This can cause the test to fail if the actual mouse cursor on + // the screen is somewhere over the test window, so that when the + // test window is restored from the iconified state, it's detected + // that the mouse cursor has moved to the mouse cursor position on + // the screen, and is no longer hovering over the button, so the + // button is painted differently. + robot.mouseMove(button.getLocationOnScreen().x + button.getSize().width / 2, + button.getLocationOnScreen().y + button.getSize().height / 2); + robot.waitForIdle(); } - robot.waitForIdle(delay * 5); if (! p.equals(comp.getLocationOnScreen())) { passed = false; @@ -238,14 +208,20 @@ public void run() { bRect = new Rectangle((int)p.getX(), (int)p.getY(), comp.getWidth(), comp.getHeight()); BufferedImage capturedImage2 = robot.createScreenCapture(bRect); + BufferedImage frameImage2 = robot.createScreenCapture(frame.getBounds()); - if (! compareImages(capturedImage, capturedImage2)) { + if (!compareImages(capturedImage, capturedImage2)) { passed = false; + try { - javax.imageio.ImageIO.write(capturedImage, "jpg", new File( - prefix+"BeforeMinimize.jpg")); - javax.imageio.ImageIO.write(capturedImage2, "jpg", new File( - prefix+"AfterMinimize.jpg")); + javax.imageio.ImageIO.write(capturedImage, "png", + new File(prefix + "BeforeMinimize.png")); + javax.imageio.ImageIO.write(capturedImage2, "png", + new File(prefix + "AfterMinimize.png")); + javax.imageio.ImageIO.write(frameImage, "png", + new File("Frame" + prefix + "BeforeMinimize.png")); + javax.imageio.ImageIO.write(frameImage2, "png", + new File("Frame" + prefix + "AfterMinimize.png")); } catch (Exception e) { e.printStackTrace(); } diff --git a/test/jdk/java/awt/Frame/WindowMoveTest.java b/test/jdk/java/awt/Frame/WindowMoveTest.java new file mode 100644 index 00000000000..0b086216a3b --- /dev/null +++ b/test/jdk/java/awt/Frame/WindowMoveTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * 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; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/* + * @test + * @bug 4077874 + * @key headful + * @summary Test window position at opening, closing, and closed for consistency + */ + +public class WindowMoveTest { + + static WindowMove frame; + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.setAutoWaitForIdle(true); + + EventQueue.invokeAndWait(() -> frame = new WindowMove()); + + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> + frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING))); + + if (!WindowMove.latch.await(2, TimeUnit.SECONDS)) { + throw new RuntimeException("Test timeout."); + } + + if (WindowMove.failMessage != null) { + throw new RuntimeException(WindowMove.failMessage); + } + } +} + +class WindowMove extends Frame implements WindowListener { + static final Rectangle expectedBounds = + new Rectangle(100, 100, 300, 300); + + static CountDownLatch latch = new CountDownLatch(1); + static String failMessage = null; + + private boolean layoutCheck; + private boolean visibleCheck; + private boolean openedCheck; + private boolean closingCheck; + private boolean closedCheck; + + public WindowMove() { + super("WindowMove"); + addWindowListener(this); + + setSize(300, 300); + setLocation(100, 100); + setBackground(Color.white); + + setLayout(null); + if (checkBounds()) { + layoutCheck = true; + } + System.out.println("setLayout bounds: " + getBounds()); + + setVisible(true); + if (checkBounds()) { + visibleCheck = true; + } + System.out.println("setVisible bounds: " + getBounds()); + } + + private boolean checkBounds() { + return getBounds().equals(expectedBounds); + } + + public void checkResult() { + if (layoutCheck + && visibleCheck + && openedCheck + && closingCheck + && closedCheck) { + System.out.println("Test passed."); + } else { + failMessage = """ + Some of the checks failed: + layoutCheck %s + visibleCheck %s + openedCheck %s + closingCheck %s + closedCheck %s + """ + .formatted( + layoutCheck, + visibleCheck, + openedCheck, + closingCheck, + closedCheck + ); + } + + latch.countDown(); + } + + public void windowClosing(WindowEvent evt) { + if (checkBounds()) { + closingCheck = true; + } + System.out.println("Closing bounds: " + getBounds()); + + setVisible(false); + dispose(); + } + + public void windowClosed(WindowEvent evt) { + if (checkBounds()) { + closedCheck = true; + } + System.out.println("Closed bounds: " + getBounds()); + + checkResult(); + } + + public void windowOpened(WindowEvent evt) { + if (checkBounds()) { + openedCheck = true; + } + System.out.println("Opening bounds: " + getBounds()); + } + + public void windowActivated(WindowEvent evt) {} + + public void windowIconified(WindowEvent evt) {} + + public void windowDeactivated(WindowEvent evt) {} + + public void windowDeiconified(WindowEvent evt) {} +} diff --git a/test/jdk/java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemonicKeyTypedTest.java b/test/jdk/java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemonicKeyTypedTest.java index 9ae79971af0..5b2dc2844f1 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, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,34 +33,50 @@ import jdk.test.lib.Platform; -import java.awt.*; -import javax.swing.*; -import java.awt.event.*; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; public class ConsumeNextMnemonicKeyTypedTest { - Robot robot; - JFrame frame = new JFrame("Test Frame"); - JTextField text = new JTextField(); - JMenuBar bar = new JMenuBar(); - JMenu menu = new JMenu("Menu"); - JMenuItem item = new JMenuItem("item"); - - public static void main(String[] args) { - ConsumeNextMnemonicKeyTypedTest app = new ConsumeNextMnemonicKeyTypedTest(); - app.init(); - app.start(); - } - - public void init() { + static Robot robot; + static JFrame frame; + static JTextField text; + static JMenuBar bar; + static JMenu menu; + static JMenuItem item; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoDelay(50); try { - robot = new Robot(); - robot.setAutoDelay(50); - } catch (AWTException e) { - throw new RuntimeException("Error: unable to create robot", e); + SwingUtilities.invokeAndWait(ConsumeNextMnemonicKeyTypedTest::init); + + robot.waitForIdle(); + robot.delay(500); + + test(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); } } - public void start() { + public static void init() { + frame = new JFrame("Test Frame"); + text = new JTextField(); + bar = new JMenuBar(); + menu = new JMenu("Menu"); + item = new JMenuItem("item"); + menu.setMnemonic('f'); item.setMnemonic('i'); menu.add(item); @@ -72,20 +88,18 @@ public void start() { frame.setLocationRelativeTo(null); frame.setVisible(true); - - test(); } - void test() { + static void test() { robot.waitForIdle(); if (!text.isFocusOwner()) { robot.mouseMove(text.getLocationOnScreen().x + 5, text.getLocationOnScreen().y + 5); robot.delay(100); - robot.mousePress(MouseEvent.BUTTON1_MASK); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); robot.delay(100); - robot.mouseRelease(MouseEvent.BUTTON1_MASK); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); int iter = 10; while (!text.isFocusOwner() && iter-- > 0) { @@ -146,7 +160,7 @@ void test() { robot.waitForIdle(); - System.err.println("Test: chracter typed with VK_A: " + text.getText()); + System.err.println("Test: character typed with VK_A: " + text.getText()); if (!charA.equals(text.getText())) { throw new RuntimeException("Test failed!"); diff --git a/test/jdk/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java b/test/jdk/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java index b1429d92e9e..baf70c16e6e 100644 --- a/test/jdk/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java +++ b/test/jdk/java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,19 +21,6 @@ * questions. */ -/* - @test - @key headful - @bug 6380743 8158380 8198624 - @summary Submenu should be shown by mnemonic key press. - @author anton.tarasov@...: area=awt.focus - @library ../../../regtesthelpers - @library /test/lib - @build Util - @build jdk.test.lib.Platform - @run main SubMenuShowTest -*/ - import java.awt.Robot; import java.awt.BorderLayout; import java.awt.event.KeyEvent; @@ -48,6 +35,17 @@ import jdk.test.lib.Platform; import test.java.awt.regtesthelpers.Util; +/* + @test + @key headful + @bug 6380743 8158380 8198624 + @summary Submenu should be shown by mnemonic key press. + @library /java/awt/regtesthelpers + @library /test/lib + @build Util + @build jdk.test.lib.Platform + @run main SubMenuShowTest +*/ public class SubMenuShowTest { private static Robot robot; private static JFrame frame; @@ -116,6 +114,8 @@ public void actionPerformed(ActionEvent e) { } public static void doTest() { + robot.waitForIdle(); + robot.delay(1000); boolean isMacOSX = Platform.isOSX(); if (isMacOSX) { robot.keyPress(KeyEvent.VK_CONTROL); diff --git a/test/jdk/java/awt/LightweightComponent/LightweightCliprect.java b/test/jdk/java/awt/LightweightComponent/LightweightCliprect.java new file mode 100644 index 00000000000..a6b1e3bc95c --- /dev/null +++ b/test/jdk/java/awt/LightweightComponent/LightweightCliprect.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * 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; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; + +/* + * @test + * @bug 4116029 + * @summary drawString does not honor clipping regions for lightweight components + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual LightweightCliprect + */ + +public class LightweightCliprect { + + private static final String INSTRUCTIONS = """ + If some text is drawn outside the red rectangle, press "Fail" button. + Otherwise, press "Pass" button. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("LightweightCliprect Instructions Frame") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(10) + .columns(45) + .build(); + + EventQueue.invokeAndWait(() -> { + Frame frame = new Frame("DefaultSize"); + + Container panel = new MyContainer(); + MyComponent c = new MyComponent(); + panel.add(c); + + frame.add(panel); + frame.setSize(400, 300); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame + .positionTestWindow(frame, PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} + +class MyComponent extends Component { + + public void paint(Graphics g) { + Color c = g.getColor(); + g.setColor(Color.red); + g.fillRect(20, 20, 400, 200); + Shape clip = g.getClip(); + g.setClip(20, 20, 400, 200); + //draw the current java version in the component + g.setColor(Color.black); + String version = System.getProperty("java.version"); + String vendor = System.getProperty("java.vendor"); + int y = 10; + for(int i = 0; i < 30; i++) { + g.drawString("Lightweight: Java version: " + version + + ", Vendor: " + vendor, 10, y += 20); + } + g.setColor(c); + g.setClip(clip); + super.paint(g); + } + + public Dimension getPreferredSize() { + return new Dimension(300, 300); + } +} + +class MyContainer extends Container { + public MyContainer() { + super(); + setLayout(new FlowLayout()); + } + + public void paint(Graphics g) { + Rectangle bounds = new Rectangle(getSize()); + g.setColor(Color.cyan); + g.drawRect(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1); + super.paint(g); + } +} diff --git a/test/jdk/java/awt/List/ActionEventTest/ActionEventTest.java b/test/jdk/java/awt/List/ActionEventTest/ActionEventTest.java index ecda27e4249..19665a6dc29 100644 --- a/test/jdk/java/awt/List/ActionEventTest/ActionEventTest.java +++ b/test/jdk/java/awt/List/ActionEventTest/ActionEventTest.java @@ -29,59 +29,55 @@ * @run main ActionEventTest */ -import java.awt.AWTException; +import java.awt.EventQueue; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.List; import java.awt.Robot; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; -public class ActionEventTest extends Frame { - List list; - Robot robot; - public ActionEventTest() { - try { - robot = new Robot(); - robot.setAutoDelay(100); - robot.setAutoWaitForIdle(true); - } catch(AWTException e) { - throw new RuntimeException(e.getMessage()); - } +public class ActionEventTest { + + static List list; + static Frame frame; + static Robot robot; + static final CountDownLatch countDownLatch = new CountDownLatch(1); + static volatile boolean failed; + + static void initAndShowGui() { list = new List(1, false); list.add("0"); - add(list); - setSize(400,400); - setLayout(new FlowLayout()); - setLocationRelativeTo(null); - pack(); - setVisible(true); - } - void performTest() { - list.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent ae) { - int md = ae.getModifiers(); - int expectedMask = ActionEvent.ALT_MASK | ActionEvent.CTRL_MASK - | ActionEvent.SHIFT_MASK; - - if ((md & expectedMask) != expectedMask) { - - robot.keyRelease(KeyEvent.VK_CONTROL); - robot.keyRelease(KeyEvent.VK_SHIFT); - robot.keyRelease(KeyEvent.VK_ALT); - dispose(); - throw new RuntimeException("Action Event modifiers are not" - + " set correctly."); - } + list.addActionListener(ae -> { + int md = ae.getModifiers(); + int expectedMask = ActionEvent.ALT_MASK | ActionEvent.CTRL_MASK + | ActionEvent.SHIFT_MASK; + + if ((md & expectedMask) != expectedMask) { + failed = true; } + countDownLatch.countDown(); }); + frame = new Frame("ActionEventTest"); + frame.add(list); + frame.setSize(400, 400); + frame.setLayout(new FlowLayout()); + frame.setLocationRelativeTo(null); + frame.pack(); + frame.setVisible(true); list.select(0); + } + + static void performTest() { + robot.waitForIdle(); + robot.delay(500); + robot.keyPress(KeyEvent.VK_ALT); robot.keyPress(KeyEvent.VK_SHIFT); robot.keyPress(KeyEvent.VK_CONTROL); @@ -93,9 +89,29 @@ public void actionPerformed(ActionEvent ae) { robot.keyRelease(KeyEvent.VK_ALT); } - public static void main(String args[]) { - ActionEventTest test = new ActionEventTest(); - test.performTest(); - test.dispose(); + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoDelay(100); + robot.setAutoWaitForIdle(true); + + try { + EventQueue.invokeAndWait(ActionEventTest::initAndShowGui); + performTest(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + if (!countDownLatch.await(10, TimeUnit.SECONDS)) { + throw new RuntimeException("Action Listener is not triggered"); + } + + if (failed) { + throw new RuntimeException("Action Event modifiers are not" + + " set correctly."); + } } } diff --git a/test/jdk/java/awt/List/KeyEventsTest/KeyEventsTest.java b/test/jdk/java/awt/List/KeyEventsTest/KeyEventsTest.java index 13a019bb6dc..16fbccdafd1 100644 --- a/test/jdk/java/awt/List/KeyEventsTest/KeyEventsTest.java +++ b/test/jdk/java/awt/List/KeyEventsTest/KeyEventsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,33 +32,87 @@ @run main KeyEventsTest */ -import java.awt.*; -import java.awt.event.*; -import java.lang.reflect.*; +import java.awt.BorderLayout; +import java.awt.EventQueue; +import java.awt.KeyboardFocusManager; +import java.awt.Frame; +import java.awt.List; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.InputEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; import jdk.test.lib.Platform; -public class KeyEventsTest extends Frame implements ItemListener, FocusListener, KeyListener -{ +public class KeyEventsTest { TestState currentState; final Object LOCK = new Object(); final int ACTION_TIMEOUT = 500; - List single = new List(3, false); - List multiple = new List(3, true); + List single; + List multiple; - Panel p1 = new Panel (); - Panel p2 = new Panel (); + KeyFrame keyFrame; - public static void main(final String[] args) { + static Robot r; + + public static void main(final String[] args) throws Exception { + r = new Robot(); KeyEventsTest app = new KeyEventsTest(); - app.init(); - app.start(); + try { + EventQueue.invokeAndWait(app::initAndShowGui); + r.waitForIdle(); + r.delay(500); + app.doTest(); + } finally { + EventQueue.invokeAndWait(() -> { + if (app.keyFrame != null) { + app.keyFrame.dispose(); + } + }); + } + } + + class KeyFrame extends Frame implements ItemListener, FocusListener, KeyListener { + public void itemStateChanged(ItemEvent ie) { + System.out.println("itemStateChanged-" + ie); + currentState.setAction(true); + } + + public void focusGained(FocusEvent e) { + synchronized (LOCK) { + LOCK.notifyAll(); + } + } + + public void focusLost(FocusEvent e) { + } + + public void keyPressed(KeyEvent e) { + System.out.println("keyPressed-" + e); + } + + public void keyReleased(KeyEvent e) { + System.out.println("keyReleased-" + e); + } + + public void keyTyped(KeyEvent e) { + System.out.println("keyTyped-" + e); + } } - public void init() - { - setLayout (new BorderLayout ()); + public void initAndShowGui() { + keyFrame = new KeyFrame(); + keyFrame.setLayout(new BorderLayout ()); + + single = new List(3, false); + multiple = new List(3, true); single.add("0"); single.add("1"); @@ -80,161 +134,105 @@ public void init() multiple.add("7"); multiple.add("8"); - single.addKeyListener(this); - single.addItemListener(this); - single.addFocusListener(this); + single.addKeyListener(keyFrame); + single.addItemListener(keyFrame); + single.addFocusListener(keyFrame); + Panel p1 = new Panel(); p1.add(single); - add("North", p1); + keyFrame.add("North", p1); - multiple.addKeyListener(this); - multiple.addItemListener(this); - multiple.addFocusListener(this); + multiple.addKeyListener(keyFrame); + multiple.addItemListener(keyFrame); + multiple.addFocusListener(keyFrame); + Panel p2 = new Panel(); p2.add(multiple); - add("South", p2); - - }//End init() - - public void start () - { - - try{ - setSize (200,200); - validate(); - setUndecorated(true); - setLocationRelativeTo(null); - setVisible(true); - - doTest(); - System.out.println("Test passed."); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("The test failed."); - } + keyFrame.add("South", p2); - }// start() - - public void itemStateChanged (ItemEvent ie) { - System.out.println("itemStateChanged-"+ie); - this.currentState.setAction(true); + keyFrame.setSize(200, 200); + keyFrame.validate(); + keyFrame.setUndecorated(true); + keyFrame.setLocationRelativeTo(null); + keyFrame.setVisible(true); } - public void focusGained(FocusEvent e){ - + private void test(TestState currentState) throws Exception { synchronized (LOCK) { - LOCK.notifyAll(); - } - - } - - public void focusLost(FocusEvent e){ - } - - public void keyPressed(KeyEvent e){ - System.out.println("keyPressed-"+e); - } - - public void keyReleased(KeyEvent e){ - System.out.println("keyReleased-"+e); - } - - public void keyTyped(KeyEvent e){ - System.out.println("keyTyped-"+e); - } - - private void test(TestState currentState) - throws InterruptedException, InvocationTargetException { - - synchronized (LOCK) { - this.currentState = currentState; System.out.println(this.currentState); List list; - if (currentState.getMultiple()){ + if (currentState.getMultiple()) { list = multiple; - }else{ + } else { list = single; } - Robot r; - try { - r = new Robot(); - } catch(AWTException e) { - throw new RuntimeException(e.getMessage()); - } - r.delay(10); - Point loc = this.getLocationOnScreen(); + Point loc = keyFrame.getLocationOnScreen(); - r.mouseMove(loc.x+10, loc.y+10); - r.mousePress(InputEvent.BUTTON1_MASK); + r.mouseMove(loc.x + 10, loc.y + 10); + r.mousePress(InputEvent.BUTTON1_DOWN_MASK); r.delay(10); - r.mouseRelease(InputEvent.BUTTON1_MASK); + r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); r.delay(10); list.requestFocusInWindow(); LOCK.wait(ACTION_TIMEOUT); + r.waitForIdle(); + if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != list){ throw new RuntimeException("Test failed - list isn't focus owner."); } - list.deselect(0); - list.deselect(1); - list.deselect(2); - list.deselect(3); - list.deselect(4); - list.deselect(5); - list.deselect(6); - list.deselect(7); - list.deselect(8); - - int selectIndex = 0; - int visibleIndex = 0; - - if (currentState.getScrollMoved()){ - - if (currentState.getKeyID() == KeyEvent.VK_PAGE_UP || - currentState.getKeyID() == KeyEvent.VK_HOME){ - selectIndex = 8; - visibleIndex = 8; - }else if (currentState.getKeyID() == KeyEvent.VK_PAGE_DOWN || - currentState.getKeyID() == KeyEvent.VK_END){ - selectIndex = 0; - visibleIndex = 0; - } - - }else{ - - if (currentState.getKeyID() == KeyEvent.VK_PAGE_UP || - currentState.getKeyID() == KeyEvent.VK_HOME){ - - if (currentState.getSelectedMoved()){ - selectIndex = 1; - visibleIndex = 0; - }else{ + EventQueue.invokeAndWait(() -> { + list.deselect(0); + list.deselect(1); + list.deselect(2); + list.deselect(3); + list.deselect(4); + list.deselect(5); + list.deselect(6); + list.deselect(7); + list.deselect(8); + + int selectIndex = 0; + int visibleIndex = 0; + + if (currentState.getScrollMoved()) { + if (currentState.getKeyID() == KeyEvent.VK_PAGE_UP || + currentState.getKeyID() == KeyEvent.VK_HOME) { + selectIndex = 8; + visibleIndex = 8; + } else if (currentState.getKeyID() == KeyEvent.VK_PAGE_DOWN || + currentState.getKeyID() == KeyEvent.VK_END) { selectIndex = 0; visibleIndex = 0; } - - }else if (currentState.getKeyID() == KeyEvent.VK_PAGE_DOWN || - currentState.getKeyID() == KeyEvent.VK_END){ - - if (currentState.getSelectedMoved()){ - selectIndex = 7; - visibleIndex = 8; - }else{ - selectIndex = 8; + } else { + if (currentState.getKeyID() == KeyEvent.VK_PAGE_UP || + currentState.getKeyID() == KeyEvent.VK_HOME) { + if (currentState.getSelectedMoved()) { + selectIndex = 1; + } else { + selectIndex = 0; + } + visibleIndex = 0; + } else if (currentState.getKeyID() == KeyEvent.VK_PAGE_DOWN || + currentState.getKeyID() == KeyEvent.VK_END) { + if (currentState.getSelectedMoved()) { + selectIndex = 7; + } else { + selectIndex = 8; + } visibleIndex = 8; } - } - - } - - list.select(selectIndex); - list.makeVisible(visibleIndex); + list.select(selectIndex); + list.makeVisible(visibleIndex); + }); r.delay(10); + r.waitForIdle(); if (currentState.getKeyID() == KeyEvent.VK_HOME || currentState.getKeyID() == KeyEvent.VK_END){ @@ -259,11 +257,9 @@ private void test(TestState currentState) throw new RuntimeException("Test failed."); } - } - private void doTest() - throws InterruptedException, InvocationTargetException { + private void doTest() throws Exception { boolean isWin = false; if (Platform.isWindows()) { @@ -310,9 +306,9 @@ private void doTest() } }// class KeyEventsTest -class TestState{ +class TestState { - private boolean multiple; + private final boolean multiple; // after key pressing selected item moved private final boolean selectedMoved; // after key pressing scroll moved diff --git a/test/jdk/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.html b/test/jdk/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.html deleted file mode 100644 index 7049e827033..00000000000 --- a/test/jdk/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - ManualYesNoTest - - - -

ManualYesNoTest
Bug ID:

- -

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

- - - - diff --git a/test/jdk/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.java b/test/jdk/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.java index 8b509a12311..09ea5bc11cc 100644 --- a/test/jdk/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.java +++ b/test/jdk/java/awt/List/MouseDraggedOutCauseScrollingTest/MouseDraggedOutCauseScrollingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,29 +22,29 @@ */ /* - test + @test @bug 6243382 8006070 @summary Dragging of mouse outside of a List and Choice area don't work properly on XAWT - @author Dmitry.Cherepanov@SUN.COM area=awt.list - @run applet/manual=yesno MouseDraggedOutCauseScrollingTest.html + @requires (os.family == "linux") + @library /java/awt/regtesthelpers + @run main/manual MouseDraggedOutCauseScrollingTest */ -import java.applet.Applet; -import java.awt.*; +import java.awt.Choice; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.List; +import java.awt.Toolkit; -public class MouseDraggedOutCauseScrollingTest extends Applet -{ - Choice choice; - List singleList; - List multipleList; +public class MouseDraggedOutCauseScrollingTest { - public void init() - { - this.setLayout (new GridLayout (1, 3)); + static Frame createUI() { + Frame frame = new Frame("MouseDraggedOutCausesScrollingTest"); + frame.setLayout(new GridLayout(1, 3)); - choice = new Choice(); - singleList = new List(3, false); - multipleList = new List(3, true); + Choice choice = new Choice(); + List singleList = new List(3, false); + List multipleList = new List(3, true); choice.add("Choice"); for (int i = 1; i < 100; i++){ @@ -59,188 +59,68 @@ public void init() for (int i = 1; i < 100; i++) multipleList.add(""+i); - this.add(choice); - this.add(singleList); - this.add(multipleList); + frame.add(choice); + frame.add(singleList); + frame.add(multipleList); + frame.setSize(400, 100); + return frame; + } + public static void main(String[] args) throws Exception { String toolkitName = Toolkit.getDefaultToolkit().getClass().getName(); + if (!toolkitName.equals("sun.awt.X11.XToolkit")) { - String[] instructions = - { - "This test is not applicable to the current platform. Press PASS" - }; - Sysout.createDialogWithInstructions( instructions ); - } else { - String[] instructions = - { - "0) Please note, that this is only Motif/XAWT test. At first, make the applet active", - "1.1) Click on the choice", - "1.2) Press the left button of the mouse and keep on any item of the choice, for example 5", - "1.3) Drag mouse out of the area of the unfurled list, at the same time hold the X coordinate of the mouse position about the same", - "1.4) To make sure, that when the Y coordinate of the mouse position higher of the upper bound of the list then scrolling UP of the list and selected item changes on the upper. If not, the test failed", - "1.5) To make sure, that when the Y coordinate of the mouse position under of the lower bound of the list then scrolling DOWN of the list and selected item changes on the lower. If not, the test failed", - "-----------------------------------", - "2.1) Click on the single list", - "2.2) Press the left button of the mouse and keep on any item of the list, for example 5", - "2.3) Drag mouse out of the area of the unfurled list, at the same time hold the X coordinate of the mouse position about the same", - "2.4) To make sure, that when the Y coordinate of the mouse position higher of the upper bound of the list then scrolling UP of the list and selected item changes on the upper. If not, the test failed", - "2.5) To make sure, that when the Y coordinate of the mouse position under of the lower bound of the list then scrolling DOWN of the list and selected item changes on the lower. If not, the test failed", - "-----------------------------------", - "3.1) Click on the multiple list", - "3.2) Press the left button of the mouse and keep on any item of the list, for example 5", - "3.3) Drag mouse out of the area of the unfurled list, at the same time hold the X coordinate of the mouse position about the same", - "3.4) To make sure, that when the Y coordinate of the mouse position higher of the upper bound of the list then scrolling of the list NO OCCURED and selected item NO CHANGES on the upper. If not, the test failed", - "3.5) To make sure, that when the Y coordinate of the mouse position under of the lower bound of the list then scrolling of the list NO OCCURED and selected item NO CHANGES on the lower. If not, the test failed", - "4) Test passed." - }; - Sysout.createDialogWithInstructions( instructions ); + System.out.println(INAPPLICABLE); + return; } - }//End init() - - public void start () - { - setSize (400,100); - setVisible(true); - validate(); - - }// start() - -}// class ManualYesNoTest - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); + PassFailJFrame + .builder() + .instructions(INSTRUCTIONS) + .rows(40) + .columns(70) + .testUI(MouseDraggedOutCauseScrollingTest::createUI) + .build() + .awaitAndCheck(); } -}// TestDialog class + static final String INAPPLICABLE = "The test is not applicable to the current platform. Test PASSES."; + static final String INSTRUCTIONS = """ + 0) Please note, that this is an XAWT/Linux only test. First, make the test window is active. + ----------------------------------- + 1.1) Click on the Choice. + 1.2) Press and hold down the left button of the mouse to select (eg) item 5 in the choice. + 1.3) Drag the mouse vertically out of the area of the open list, + keeping the X coordinate of the mouse position about the same. + 1.4) Check that when the Y coordinate of the mouse position is higher than the upper bound of the list + then the list continues to scrolls UP and the selected item changes at the top until you reach the topmost item. + If not, the test failed. Press FAIL. + 1.5) Check that when the Y coordinate of the mouse position is lower than the lower bound of the list + then the list continues to scroll DOWN and the selected item changes at the bottom until you reach the bottommost item. + If not, the test failed. Press FAIL. + ----------------------------------- + 2.1) Click on the Single List. + 2.2) Press and hold down the left button of the mouse to select (eg) item 5 in the list. + 2.3) Drag the mouse vertically out of the area of the open list, + keeping the X coordinate of the mouse position about the same. + 2.4) Check that when the Y coordinate of the mouse position is higher than the upper bound of the list + then the list continues to scrolls UP and the selected item changes at the top until you reach the topmost item. + If not, the test failed. Press FAIL. + 2.5) Check that when the Y coordinate of the mouse position is lower than the lower bound of the list + then the list continues to scroll DOWN and the selected item changes at the bottom until you reach the bottommost item. + If not, the test failed. Press FAIL. + ----------------------------------- + 3.1) Click on the Multiple List. + 3.2) Press and hold down the left button of the mouse to select (eg) item 5 in the list. + 3.3) Drag the mouse vertically out of the area of the open list, + keeping the X coordinate of the mouse position about the same. + 3.4) Check that when the Y coordinate of the mouse is higher than the upper bound of the list + that scrolling of the list DOES NOT OCCUR and the selected item IS UNCHANGED at the top. + If not, the test failed. Press FAIL. + 3.5) Check that when the Y coordinate of the mouse is below the lower bound of the list + that scrolling of the list DOES NOT OCCUR and the selected item IS UNCHANGED at the bottom. + If not, the test failed. Press FAIL. + ----------------------------------- + 4) The test has now passed. Press PASS. + """; +} diff --git a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_1.java b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_1.java new file mode 100644 index 00000000000..808bb598cec --- /dev/null +++ b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_1.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * 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.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4028130 + * @summary Test dynamically adding and removing a menu bar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AddRemoveMenuBarTest_1 + */ + +public class AddRemoveMenuBarTest_1 { + + private static final String INSTRUCTIONS = """ + An initially empty frame should appear. + + Click anywhere in the frame to add a menu bar at the top of the frame. + + Click again to replace the menu bar with another menu bar. + + Each menu bar has one (empty) menu, labelled with the + number of the menu bar appearing. + + After a menubar is added, the frame should not be resized nor repositioned + on the screen; + + it should have the same size and position. + + Upon test completion, click Pass or Fail appropriately. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("AddRemoveMenuBarTest_1 Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(18) + .columns(45) + .build(); + + SwingUtilities.invokeAndWait(() -> { + AddRemoveMenuBar_1 frame = new AddRemoveMenuBar_1(); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} + +class AddRemoveMenuBar_1 extends Frame { + int menuCount; + + AddRemoveMenuBar_1() { + super("AddRemoveMenuBar_1"); + setSize(200, 200); + menuCount = 0; + + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + setMenuBar(); + } + }); + } + + void setMenuBar() { + MenuBar bar = new MenuBar(); + bar.add(new Menu(Integer.toString(menuCount++))); + setMenuBar(bar); + } +} diff --git a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_2.java b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_2.java new file mode 100644 index 00000000000..c0c98a5ca95 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_2.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * 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.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4028130 + * @key headful + * @summary Test dynamically adding and removing a menu bar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AddRemoveMenuBarTest_2 + */ + +public class AddRemoveMenuBarTest_2 { + private static final String INSTRUCTIONS = """ + A frame with a menu bar appears. + + Click anywhere in the frame to replace the menu bar with + another one. + + Each menu bar has one (empty) menu, 'foo'. + + After the menu bar replacement, the containing frame + should not be resized nor repositioned on the screen. + + Upon test completion, click Pass or Fail appropriately. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("AddRemoveMenuBarTest_2 Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(15) + .columns(45) + .build(); + + SwingUtilities.invokeAndWait(() -> { + AddRemoveMenuBar_2 frame = new AddRemoveMenuBar_2(); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} + +class AddRemoveMenuBar_2 extends Frame { + AddRemoveMenuBar_2() { + super("AddRemoveMenuBar_2"); + setSize(200, 200); + setMenuBar(); + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + setMenuBar(); + } + }); + } + + int count = 0; + + void setMenuBar() { + MenuBar bar = new MenuBar(); + bar.add(new Menu("foo " + count++)); + super.setMenuBar(bar); + } +} diff --git a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_3.java b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_3.java new file mode 100644 index 00000000000..a01ddd9925b --- /dev/null +++ b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_3.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Checkbox; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.TextField; +import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4017504 + * @summary Test dynamically adding and removing a menu bar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AddRemoveMenuBarTest_3 + */ + +public class AddRemoveMenuBarTest_3 { + private static final String INSTRUCTIONS = """ + A frame at (100,100) contains two (2) rows of three (3) text + fields each, and under this, a checkbox labelled 'Use menubar'. + + The first row's text fields pertain to the x coordinates and + the second row's text fields pertain to the y coordinates. + + The first column, 'request', is an input only field for frame + location. (press enter to apply). + + The second column, 'reported', is an output only + field reporting frame location. + + The third column, 'inset', is an output only field reporting + the frame's inset values. + + You can click the 'Use menubar' checkbox to alternately add + and remove a menu bar containing an (empty) 'Help' menu. + + After a menubar is added or removed, the frame should not + have been resized nor repositioned on the screen and the + y inset should accurately reflect the presence or absence + of the menubar within the inset. + + The insets always include the window manager's title and border + decorations, if any. + + Upon test completion, click Pass or Fail appropriately. + """; + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("AddRemoveMenuBarTest_3 Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(30) + .columns(38) + .build(); + + SwingUtilities.invokeAndWait(() -> { + AddRemoveMenuBar_3 frame = new AddRemoveMenuBar_3(); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(null, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} + +class AddRemoveMenuBar_3 extends Frame { + TextField xfield; + TextField yfield; + + TextField xfield_out; + TextField yfield_out; + TextField xinset_out; + TextField yinset_out; + + Checkbox menu_checkbox; + MenuBar menubar; + + public AddRemoveMenuBar_3() { + super("AddRemoveMenuBar_3"); + + menubar = new MenuBar(); + menubar.setHelpMenu(new Menu("Help")); + + setLayout(new BorderLayout()); + Panel p = new Panel(); + add("Center", p); + p.setLayout(new GridLayout(3, 3)); + + menu_checkbox = new Checkbox("Use menubar"); + add("South", menu_checkbox); + + xfield = new TextField(); + yfield = new TextField(); + xfield_out = new TextField(); + xfield_out.setEditable(false); + xfield_out.setFocusable(false); + yfield_out = new TextField(); + yfield_out.setEditable(false); + yfield_out.setFocusable(false); + + xinset_out = new TextField(); + xinset_out.setEditable(false); + xinset_out.setFocusable(false); + yinset_out = new TextField(); + yinset_out.setEditable(false); + yinset_out.setFocusable(false); + + p.add(new Label("request")); + p.add(new Label("reported")); + p.add(new Label("inset")); + + p.add(xfield); + p.add(xfield_out); + p.add(xinset_out); + + p.add(yfield); + p.add(yfield_out); + p.add(yinset_out); + + setSize(200, 200); + setLocation(100, 100); + + addComponentListener(new ComponentAdapter() { + @Override + public void componentMoved(ComponentEvent e) { + xfield_out.setText(Integer.toString(getLocation().x)); + yfield_out.setText(Integer.toString(getLocation().y)); + + xinset_out.setText(Integer.toString(getInsets().left)); + yinset_out.setText(Integer.toString(getInsets().top)); + } + }); + + ActionListener setLocationListener = e -> { + Rectangle r = getBounds(); + try { + r.x = Integer.parseInt(xfield.getText()); + r.y = Integer.parseInt(yfield.getText()); + } catch (java.lang.NumberFormatException ignored) { + } + + setLocation(r.x, r.y); + }; + + xfield.addActionListener(setLocationListener); + yfield.addActionListener(setLocationListener); + + menu_checkbox.addItemListener(e -> { + if (menu_checkbox.getState()) { + setMenuBar(menubar); + } else { + setMenuBar(null); + } + + validate(); + xinset_out.setText(Integer.toString(getInsets().left)); + yinset_out.setText(Integer.toString(getInsets().top)); + }); + } +} diff --git a/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_4.java b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_4.java new file mode 100644 index 00000000000..571fce7fba5 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/AddRemoveMenuBarTests/AddRemoveMenuBarTest_4.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * 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.Button; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4071086 + * @key headful + * @summary Test dynamically adding and removing a menu bar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AddRemoveMenuBarTest_4 + */ + +public class AddRemoveMenuBarTest_4 { + + private static final String INSTRUCTIONS = """ + There is a frame with a menubar and a single button. + + The button is labelled 'Add new MenuBar'. + + If you click the button, the menubar is replaced with another menubar. + This can be done repeatedly. + + The -th menubar contains one menu, 'TestMenu', + with two items, 'one ' and 'two '. + + Click again to replace the menu bar with another menu bar. + + After a menubar has been replaced with another menubar, + the frame should not be resized nor repositioned on the screen. + + Upon test completion, click Pass or Fail appropriately. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("AddRemoveMenuBarTest_4 Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(18) + .columns(45) + .build(); + + SwingUtilities.invokeAndWait(() -> { + AddRemoveMenuBar_4 frame = new AddRemoveMenuBar_4(); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} + +class AddRemoveMenuBar_4 extends Frame { + int count = 1; + MenuBar mb = null; + + AddRemoveMenuBar_4() { + super("AddRemoveMenuBar_4"); + setLayout(new FlowLayout()); + + Button b = new Button("Add new MenuBar"); + b.addActionListener((e) -> createMenuBar()); + add(b); + + createMenuBar(); + + setSize(300, 300); + } + + void createMenuBar() { + if (mb != null) { + remove(mb); + } + + mb = new MenuBar(); + Menu m = new Menu("TestMenu" + count); + m.add(new MenuItem("one " + count)); + m.add(new MenuItem("two " + count)); + count++; + mb.add(m); + setMenuBar(mb); + } +} diff --git a/test/jdk/java/awt/MenuBar/SeparatorsNavigation/SeparatorsNavigation.java b/test/jdk/java/awt/MenuBar/SeparatorsNavigation/SeparatorsNavigation.java index 8aca3ab9b05..6bf6069bf04 100644 --- a/test/jdk/java/awt/MenuBar/SeparatorsNavigation/SeparatorsNavigation.java +++ b/test/jdk/java/awt/MenuBar/SeparatorsNavigation/SeparatorsNavigation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; /* * @test @@ -51,6 +53,7 @@ public class SeparatorsNavigation { static class Listener implements ActionListener { public void actionPerformed(ActionEvent e) { SeparatorsNavigation.pressed = true; + latch.countDown(); } } @@ -61,7 +64,8 @@ public void actionPerformed(ActionEvent e) { static Menu m3; static MenuItem i31; static Listener l = new Listener(); - static boolean pressed = false; + static volatile boolean pressed = false; + static final CountDownLatch latch = new CountDownLatch(1); public static void main(String args[]) { f = new Frame(); @@ -83,27 +87,23 @@ public static void main(String args[]) { f.setVisible(true); try { Robot r = new Robot(); + r.setAutoDelay(20); r.delay(1000); r.keyPress(KeyEvent.VK_F10); - r.delay(10); r.keyRelease(KeyEvent.VK_F10); r.delay(1000); r.keyPress(KeyEvent.VK_DOWN); - r.delay(10); r.keyRelease(KeyEvent.VK_DOWN); r.delay(1000); r.keyPress(KeyEvent.VK_RIGHT); - r.delay(10); r.keyRelease(KeyEvent.VK_RIGHT); r.delay(1000); r.keyPress(KeyEvent.VK_RIGHT); - r.delay(10); r.keyRelease(KeyEvent.VK_RIGHT); r.delay(1000); r.keyPress(KeyEvent.VK_ENTER); - r.delay(10); r.keyRelease(KeyEvent.VK_ENTER); - r.delay(10000); + latch.await(5, TimeUnit.SECONDS); } catch (Exception ex) { throw new RuntimeException("Execution interrupted by an " + "exception " + ex.getLocalizedMessage()); diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/HierarchyBoundsListenerMixingTest.java b/test/jdk/java/awt/Mixing/AWT_Mixing/HierarchyBoundsListenerMixingTest.java index 108cdc99d1f..3dfdfd8b6b8 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/HierarchyBoundsListenerMixingTest.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/HierarchyBoundsListenerMixingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,12 +21,33 @@ * questions. */ - -import java.awt.*; -import java.awt.event.*; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.List; +import java.awt.Panel; +import java.awt.Robot; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.InputEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import javax.swing.SwingUtilities; -import java.io.*; + +import jdk.test.lib.Platform; /** * AWT Mixing test for HierarchyBoundsListener ancestors. @@ -37,7 +58,8 @@ * @key headful * @bug 6768230 8221823 * @summary Mixing test for HierarchyBoundsListener ancestors - * @build FrameBorderCounter + * @library /test/lib + * @build FrameBorderCounter jdk.test.lib.Platform * @run main HierarchyBoundsListenerMixingTest */ public class HierarchyBoundsListenerMixingTest { @@ -137,9 +159,9 @@ protected boolean performTest() { robot.mouseMove((int) components[0].getLocationOnScreen().x + components[0].getSize().width / 2, (int) components[0].getLocationOnScreen().y + components[0].getSize().height / 2); robot.delay(delay); - robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.delay(delay); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.delay(delay); resetValues(); @@ -177,45 +199,54 @@ public void run() { robot.delay(delay * 5); resetValues(); - int x = (int) frame.getLocationOnScreen().x; - int y = (int) frame.getLocationOnScreen().y; - int w = frame.getSize().width; - int h = frame.getSize().height; - - robot.mouseMove(x + w + BORDER_SHIFT, y + h / 2); - robot.delay(delay); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.delay(delay); - for (int i = 0; i < 20; i++) { - robot.mouseMove(x + w + i + BORDER_SHIFT, y + h / 2); - robot.delay(50); - } - robot.delay(delay); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - if (! resizeTriggered) { - synchronized (resizeLock) { - try { - resizeLock.wait(delay * 10); - } catch (Exception e) { + int x; + int y; + int w; + int h; + + if (!Platform.isOnWayland()) { + x = frame.getLocationOnScreen().x; + y = frame.getLocationOnScreen().y; + w = frame.getSize().width; + h = frame.getSize().height; + + robot.mouseMove(x + w + BORDER_SHIFT, y + h / 2); + robot.delay(delay); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(delay); + for (int i = 0; i < 20; i++) { + robot.mouseMove(x + w + i + BORDER_SHIFT, y + h / 2); + robot.delay(50); + } + robot.delay(delay); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + if (!resizeTriggered) { + synchronized (resizeLock) { + try { + resizeLock.wait(delay * 10); + } catch (Exception e) { + } } } - } - for (int i = 0; i < components.length; i++) { - if (! ancestorResized[i]) { - System.err.println("FAIL: Frame resized using mouse action. " + - "Ancestor resized event did not occur for " + - components[i].getClass()); + for (int i = 0; i < components.length; i++) { + if (!ancestorResized[i]) { + System.err.println("FAIL: Frame resized using mouse action. " + + "Ancestor resized event did not occur for " + + components[i].getClass()); + passed = false; + } + } + if (moveCount > 0) { + System.err.println("FAIL: Ancestor moved event occurred when Frame resized using mouse"); passed = false; } - } - if (moveCount > 0) { - System.err.println("FAIL: Ancestor moved event occured when Frame resized using mouse"); - passed = false; + + resetValues(); } - resetValues(); try { EventQueue.invokeAndWait(new Runnable() { public void run() { @@ -250,52 +281,55 @@ public void run() { robot.delay(delay * 10); resetValues(); - x = (int) frame.getLocationOnScreen().x; - y = (int) frame.getLocationOnScreen().y; - w = frame.getSize().width; - h = frame.getSize().height; - - //Click on the dummy frame so that the test frame loses focus. This is to workaround - //a bug in Linux AS. - robot.mouseMove((int) dummy.getLocationOnScreen().x + dummy.getSize().width / 2, - (int) dummy.getLocationOnScreen().y + dummy.getSize().height / 2); - robot.delay(delay); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.delay(delay); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - robot.delay(delay); - robot.mouseMove(x + w / 2, y + 10); - robot.delay(delay); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.delay(delay); - for (int i = 1; i <= 20; i++) { - robot.mouseMove(x + w / 2 + i, y + 10); - robot.delay(50); - } - robot.delay(delay); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - - if (! moveTriggered) { - synchronized (moveLock) { - try { - moveLock.wait(delay * 10); - } catch (Exception e) { + if (!Platform.isOnWayland()) { + x = frame.getLocationOnScreen().x; + y = frame.getLocationOnScreen().y; + w = frame.getSize().width; + h = frame.getSize().height; + + //Click on the dummy frame so that the test frame loses focus. This is to workaround + //a bug in Linux AS. + robot.mouseMove((int) dummy.getLocationOnScreen().x + dummy.getSize().width / 2, + (int) dummy.getLocationOnScreen().y + dummy.getSize().height / 2); + robot.delay(delay); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(delay); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(delay); + + robot.mouseMove(x + w / 2, y + 10); + robot.delay(delay); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(delay); + for (int i = 1; i <= 20; i++) { + robot.mouseMove(x + w / 2 + i, y + 10); + robot.delay(50); + } + robot.delay(delay); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + if (! moveTriggered) { + synchronized (moveLock) { + try { + moveLock.wait(delay * 10); + } catch (Exception e) { + } } } - } - for (int i = 0; i < components.length; i++) { - if (! ancestorMoved[i]) { - System.err.println("FAIL: Frame moved using mouse action. " + - "Ancestor moved event did not occur for " + components[i].getClass()); + for (int i = 0; i < components.length; i++) { + if (! ancestorMoved[i]) { + System.err.println("FAIL: Frame moved using mouse action. " + + "Ancestor moved event did not occur for " + components[i].getClass()); + passed = false; + } + } + if (resizeCount > 0) { + System.err.println("FAIL: Ancestor resized event occured when Frame moved using mouse"); passed = false; } } - if (resizeCount > 0) { - System.err.println("FAIL: Ancestor resized event occured when Frame moved using mouse"); - passed = false; - } return passed; } @@ -450,7 +484,7 @@ private static void init() throws InterruptedException { // instantiated in the same VM. Being static (and using // static vars), it aint gonna work. Not worrying about // it for now. - public static void main(String args[]) throws InterruptedException { + public static void main(String[] args) throws InterruptedException { mainThread = Thread.currentThread(); try { init(); diff --git a/test/jdk/java/awt/Modal/ToFront/FrameToFrontModelessTest.java b/test/jdk/java/awt/Modal/ToFront/FrameToFrontModelessTest.java index 03ceb6e022d..00c67cc1fc6 100644 --- a/test/jdk/java/awt/Modal/ToFront/FrameToFrontModelessTest.java +++ b/test/jdk/java/awt/Modal/ToFront/FrameToFrontModelessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,9 @@ public class FrameToFrontModelessTest { private boolean isModeless; + private static final boolean IS_ON_WAYLAND = + System.getenv("WAYLAND_DISPLAY") != null; + public FrameToFrontModelessTest(boolean modeless) throws Exception { isModeless = modeless; robot = new ExtendedRobot(); @@ -76,6 +79,9 @@ public void doTest() throws Exception { robot.waitForIdle(delay); // show the right frame appear on top of the dialog + if (IS_ON_WAYLAND) { + rightFrame.toFront(); + } rightFrame.clickDummyButton(robot); robot.waitForIdle(delay); diff --git a/test/jdk/java/awt/Modal/helpers/TestDialog.java b/test/jdk/java/awt/Modal/helpers/TestDialog.java index 6252fe46b7a..2ae93f835b9 100644 --- a/test/jdk/java/awt/Modal/helpers/TestDialog.java +++ b/test/jdk/java/awt/Modal/helpers/TestDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,9 @@ public class TestDialog extends Dialog implements ActionListener, public static int delay = 500; public static int keyDelay = 100; + private static final boolean IS_ON_WAYLAND = + System.getenv("WAYLAND_DISPLAY") != null; + public TestDialog(Frame frame) { super(frame); initializeGUI(); @@ -287,6 +290,9 @@ public void transferFocusToDialog(ExtendedRobot robot, String message, Button b) throws Exception { focusGained.reset(); + if (IS_ON_WAYLAND) { + toFront(); + } clickInside(robot); focusGained.waitForFlagTriggered(); assertTrue(focusGained.flag(), @@ -303,6 +309,9 @@ public void transferFocusToBlockedDialog(ExtendedRobot robot, String message, Button b) throws Exception { focusGained.reset(); + if (IS_ON_WAYLAND) { + toFront(); + } clickInside(robot); robot.waitForIdle(delay); diff --git a/test/jdk/java/awt/Modal/helpers/TestFrame.java b/test/jdk/java/awt/Modal/helpers/TestFrame.java index 925b216b963..dd8ed1530ef 100644 --- a/test/jdk/java/awt/Modal/helpers/TestFrame.java +++ b/test/jdk/java/awt/Modal/helpers/TestFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,8 @@ public class TestFrame extends Frame implements ActionListener, public static int delay = 500; public static int keyDelay = 100; + private static final boolean IS_ON_WAYLAND = + System.getenv("WAYLAND_DISPLAY") != null; public TestFrame() { super(); @@ -251,7 +253,7 @@ public void clickDummyButton(ExtendedRobot robot, String message) throws Exception { dummyClicked.reset(); clickButton(dummyButton, robot); - dummyClicked.waitForFlagTriggered(); + dummyClicked.waitForFlagTriggered(attempts); String msg = "Clicking the frame Dummy button " + (refState ? "did not trigger an action." : @@ -277,6 +279,9 @@ public void transferFocusToFrame(ExtendedRobot robot, String message, Button b) throws Exception { focusGained.reset(); + if (IS_ON_WAYLAND) { + toFront(); + } clickInside(robot); focusGained.waitForFlagTriggered(); @@ -293,6 +298,9 @@ public void transferFocusToBlockedFrame(ExtendedRobot robot, String message, Button b) throws Exception { focusGained.reset(); + if (IS_ON_WAYLAND) { + toFront(); + } clickInside(robot); robot.waitForIdle(delay); diff --git a/test/jdk/java/awt/Paint/ListRepaint.java b/test/jdk/java/awt/Paint/ListRepaint.java index 6a5df92561e..08cf06d63f6 100644 --- a/test/jdk/java/awt/Paint/ListRepaint.java +++ b/test/jdk/java/awt/Paint/ListRepaint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,22 +34,23 @@ */ public final class ListRepaint extends List { - public static void main(final String[] args) { + static ListRepaint listRepaint; + static Frame frame; + + public static void main(final String[] args) throws Exception { for (int i = 0; i < 10; ++i) { - final Frame frame = new Frame(); - frame.setSize(300, 300); - frame.setLocationRelativeTo(null); - ListRepaint list = new ListRepaint(); - list.add("1"); - list.add("2"); - list.add("3"); - list.add("4"); - list.select(0); - frame.add(list); - frame.setVisible(true); - sleep(); - list.test(); - frame.dispose(); + try { + EventQueue.invokeLater(ListRepaint::createAndShowGUI); + sleep(); + EventQueue.invokeAndWait(listRepaint::test); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + frame = null; + } + }); + } } } @@ -60,6 +61,22 @@ private static void sleep() { } } + static void createAndShowGUI() { + frame = new Frame(); + frame.setSize(300, 300); + frame.setLocationRelativeTo(null); + + listRepaint = new ListRepaint(); + listRepaint.add("1"); + listRepaint.add("2"); + listRepaint.add("3"); + listRepaint.add("4"); + listRepaint.select(0); + + frame.add(listRepaint); + frame.setVisible(true); + } + @Override public void paint(final Graphics g) { super.paint(g); diff --git a/test/jdk/java/awt/print/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java b/test/jdk/java/awt/Paint/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java similarity index 100% rename from test/jdk/java/awt/print/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java rename to test/jdk/java/awt/Paint/PaintSetEnabledDeadlock/PaintSetEnabledDeadlock.java diff --git a/test/jdk/java/awt/PrintJob/ConstrainedPrintingTest/ConstrainedPrintingTest.java b/test/jdk/java/awt/PrintJob/ConstrainedPrintingTest/ConstrainedPrintingTest.java index 1532a01ca4f..f5c349ac9a5 100644 --- a/test/jdk/java/awt/PrintJob/ConstrainedPrintingTest/ConstrainedPrintingTest.java +++ b/test/jdk/java/awt/PrintJob/ConstrainedPrintingTest/ConstrainedPrintingTest.java @@ -24,6 +24,7 @@ /* @test @bug 4116029 4300383 + @key printer @summary verify that child components can draw only inside their visible bounds @library /test/lib diff --git a/test/jdk/java/awt/PrintJob/EdgeTest/EdgeTest.java b/test/jdk/java/awt/PrintJob/EdgeTest/EdgeTest.java index f7bf5e72a60..58f84b43fb2 100644 --- a/test/jdk/java/awt/PrintJob/EdgeTest/EdgeTest.java +++ b/test/jdk/java/awt/PrintJob/EdgeTest/EdgeTest.java @@ -24,9 +24,9 @@ /** * @test * @bug 4092755 + * @key printer * @summary Verifies that (0, 0) is the upper-left corner of the page, not * the upper-left corner adjusted for the margins. - * @author dpm * @run main/manual EdgeTest */ diff --git a/test/jdk/java/awt/PrintJob/HighResTest.java b/test/jdk/java/awt/PrintJob/HighResTest.java index e802214fdaf..dbf7d4a2ce6 100644 --- a/test/jdk/java/awt/PrintJob/HighResTest.java +++ b/test/jdk/java/awt/PrintJob/HighResTest.java @@ -26,7 +26,7 @@ @test @bug 4227128 8066139 @summary Test printing at resolutions > 72dpi - @author dpm: area=awt.print + @key printer @run main/manual HighResTest */ import java.awt.Button; diff --git a/test/jdk/java/awt/PrintJob/JobAttrUpdateTest.java b/test/jdk/java/awt/PrintJob/JobAttrUpdateTest.java index 186b9a6d8ba..cbc8d6a7ae8 100644 --- a/test/jdk/java/awt/PrintJob/JobAttrUpdateTest.java +++ b/test/jdk/java/awt/PrintJob/JobAttrUpdateTest.java @@ -23,6 +23,7 @@ /* * @test * @bug 6357905 + * @key printer * @summary JobAttributes.getFromPage() and getToPage() always returns 1 * @run main/manual JobAttrUpdateTest */ diff --git a/test/jdk/java/awt/PrintJob/MultipleEnd/MultipleEnd.java b/test/jdk/java/awt/PrintJob/MultipleEnd/MultipleEnd.java index b115e8d4a91..88b6a4720d9 100644 --- a/test/jdk/java/awt/PrintJob/MultipleEnd/MultipleEnd.java +++ b/test/jdk/java/awt/PrintJob/MultipleEnd/MultipleEnd.java @@ -23,7 +23,7 @@ /** * @test - * @key headful + * @key headful printer * @bug 4112758 * @summary Checks that a second invocation of PrintJob.end() does not cause * an exception or segmentation violation. diff --git a/test/jdk/java/awt/PrintJob/PageSetupDlgBlockingTest/PageSetupDlgBlockingTest.java b/test/jdk/java/awt/PrintJob/PageSetupDlgBlockingTest/PageSetupDlgBlockingTest.java index 805a2fa5c2c..9fbf48f3eb4 100644 --- a/test/jdk/java/awt/PrintJob/PageSetupDlgBlockingTest/PageSetupDlgBlockingTest.java +++ b/test/jdk/java/awt/PrintJob/PageSetupDlgBlockingTest/PageSetupDlgBlockingTest.java @@ -25,7 +25,7 @@ @test @bug 4507585 @summary Native modal dialog shouldn't block event dispatching when called on EventDispatchThread. - @author tav@sparc.spb.su: area=awt.PrintJob + @key printer @run main/manual=yesno PageSetupDlgBlockingTest */ diff --git a/test/jdk/java/awt/PrintJob/PrintArcTest/PrintArcTest.java b/test/jdk/java/awt/PrintJob/PrintArcTest/PrintArcTest.java index 7e9023b1afc..f04ce62c1a6 100644 --- a/test/jdk/java/awt/PrintJob/PrintArcTest/PrintArcTest.java +++ b/test/jdk/java/awt/PrintJob/PrintArcTest/PrintArcTest.java @@ -23,10 +23,9 @@ /* * @test - * @key headful + * @key headful printer * @bug 4105609 * @summary Test printing of drawArc preceded by drawString - * @author robi.khan */ import java.awt.*; diff --git a/test/jdk/java/awt/PrintJob/PrintCheckboxTest/PrintCheckboxManualTest.java b/test/jdk/java/awt/PrintJob/PrintCheckboxTest/PrintCheckboxManualTest.java index 33ef83bfddd..4fd3ee8ef16 100644 --- a/test/jdk/java/awt/PrintJob/PrintCheckboxTest/PrintCheckboxManualTest.java +++ b/test/jdk/java/awt/PrintJob/PrintCheckboxTest/PrintCheckboxManualTest.java @@ -26,7 +26,7 @@ @bug 5045936 5055171 @summary Tests that there is no ClassCastException thrown in printing checkbox and scrollbar with XAWT - @author art@sparc.spb.su + @key printer @run applet/manual=yesno PrintCheckboxManualTest.html */ diff --git a/test/jdk/java/awt/PrintJob/QuoteAndBackslashTest/QuoteAndBackslashTest.java b/test/jdk/java/awt/PrintJob/QuoteAndBackslashTest/QuoteAndBackslashTest.java index dcc720de23e..c84671b6dc2 100644 --- a/test/jdk/java/awt/PrintJob/QuoteAndBackslashTest/QuoteAndBackslashTest.java +++ b/test/jdk/java/awt/PrintJob/QuoteAndBackslashTest/QuoteAndBackslashTest.java @@ -23,11 +23,10 @@ /** * @test - * @key headful + * @key headful printer * @bug 4040668 * @summary Checks that banner titles which contain double quotation marks * or backslashes still print correctly. - * @author dpm */ import java.awt.*; diff --git a/test/jdk/java/awt/PrintJob/RoundedRectTest/RoundedRectTest.java b/test/jdk/java/awt/PrintJob/RoundedRectTest/RoundedRectTest.java index a8af7b585f1..650203889c7 100644 --- a/test/jdk/java/awt/PrintJob/RoundedRectTest/RoundedRectTest.java +++ b/test/jdk/java/awt/PrintJob/RoundedRectTest/RoundedRectTest.java @@ -23,10 +23,9 @@ /** * @test - * @key headful + * @key headful printer * @bug 4061440 * @summary Checks that rounded rectangles print correctly. - * @author dpm */ import java.awt.*; diff --git a/test/jdk/java/awt/PrintJob/SaveDialogTitleTest.java b/test/jdk/java/awt/PrintJob/SaveDialogTitleTest.java index 4e502290f94..b0d7c9cd238 100644 --- a/test/jdk/java/awt/PrintJob/SaveDialogTitleTest.java +++ b/test/jdk/java/awt/PrintJob/SaveDialogTitleTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 4851363 8025988 8025990 + * @key printer * @summary Tests the save to file dialog has a title. * @run main/manual=yesno/othervm SaveDialogTitleTest */ diff --git a/test/jdk/java/awt/PrintJob/Security/SecurityDialogTest.java b/test/jdk/java/awt/PrintJob/Security/SecurityDialogTest.java index 3bda65e0a71..b84afc6eb9b 100644 --- a/test/jdk/java/awt/PrintJob/Security/SecurityDialogTest.java +++ b/test/jdk/java/awt/PrintJob/Security/SecurityDialogTest.java @@ -23,7 +23,7 @@ /** * @test - * @key headful + * @key headful printer * @bug 6195901 6195923 6195928 6195933 6491273 6888734 * @summary No SecurityException should be thrown when printing to a file using the given policy. diff --git a/test/jdk/java/awt/PrintJob/TestPrintJobFrameAssociation.java b/test/jdk/java/awt/PrintJob/TestPrintJobFrameAssociation.java index 1dd861cf325..2a58cb724d7 100644 --- a/test/jdk/java/awt/PrintJob/TestPrintJobFrameAssociation.java +++ b/test/jdk/java/awt/PrintJob/TestPrintJobFrameAssociation.java @@ -23,6 +23,7 @@ /* * @test * @bug 8154218 + * @key printer * @summary Verifies if owner Frame is associated with print dialog * @run main/manual TestPrintJobFrameAssociation */ diff --git a/test/jdk/java/awt/PrintJob/Text/stringwidth.sh b/test/jdk/java/awt/PrintJob/Text/stringwidth.sh index 32bce9e728b..fea11e5ba5f 100644 --- a/test/jdk/java/awt/PrintJob/Text/stringwidth.sh +++ b/test/jdk/java/awt/PrintJob/Text/stringwidth.sh @@ -23,6 +23,7 @@ # # @test # @bug 4692562 +# @key printer # @summary Requirement: Windows with printer installed. It should print with text "Hello World". # @compile StringWidth.java # @run shell/manual stringwidth.sh diff --git a/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java b/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java index 6ba5ec18e0a..1f6298a2a61 100644 --- a/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java +++ b/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2022, JetBrains s.r.o.. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -32,7 +32,6 @@ import java.awt.Rectangle; import java.awt.Robot; import java.awt.image.BufferedImage; -import javax.swing.UIManager; import javax.imageio.ImageIO; import java.io.File; import java.io.IOException; @@ -54,6 +53,12 @@ public class ScreenCaptureGtkTest { Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED}; public static void main(String[] args) throws Exception { + if ("2".equals(System.getProperty("jdk.gtk.version")) + && System.getenv("WAYLAND_DISPLAY") != null) { + // screen capture is not supported with gtk2 on Wayland + return; + } + final int topOffset = 50; final int leftOffset = 50; diff --git a/test/jdk/java/awt/Robot/ManualInstructions/ManualInstructions.java b/test/jdk/java/awt/Robot/ManualInstructions/ManualInstructions.java deleted file mode 100644 index df842ab841e..00000000000 --- a/test/jdk/java/awt/Robot/ManualInstructions/ManualInstructions.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. - * 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 %W% %E% %I%, %G% - @bug 6315717 - @summary manual control over the Robot - @author Andrei Dmitriev : area=awt.robot - @run applet/manual=yesno ManualInstructions.html -*/ - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.*; -import java.util.Timer; -import java.util.TimerTask; - -public class ManualInstructions extends Applet -{ - final static long SEND_DELAY = 1000; - - public static void main(String s[]){ - ManualInstructions mi = new ManualInstructions(); - mi.init(); - mi.start(); - } - - static Robot robot; - Point mouseLocation; //where mouse should be pressed each time - Panel target = new Panel(); - Button pressOn = new Button("press on ..."); - Button releaseOn = new Button("release on ..."); - Button clickOn = new Button("click on ..."); - Choice buttonNumber = new Choice(); - - public void init() - { - try { - robot = new Robot(); - } catch (AWTException ex) { - ex.printStackTrace(); - throw new RuntimeException(ex); - } - this.setLayout (new BorderLayout ()); - - target.setBackground(Color.green); - target.setName("GreenBox");//for the ease of debug - target.setPreferredSize(new Dimension(100, 100)); - String toolkit = Toolkit.getDefaultToolkit().getClass().getName(); - - // on X systems two buttons are reserved for wheel though they are countable by MouseInfo. - int buttonsNumber = toolkit.equals("sun.awt.windows.WToolkit")?MouseInfo.getNumberOfButtons():MouseInfo.getNumberOfButtons()-2; - - for (int i = 0; i < 8; i++){ - buttonNumber.add("BUTTON"+(i+1)+"_MASK"); - } - - pressOn.addActionListener(new ActionListener(){ - public void actionPerformed(ActionEvent e){ - System.out.println("Now pressing : " + (buttonNumber.getSelectedIndex()+1)); - - Timer timer = new Timer(); - TimerTask robotInteraction = new TimerTask(){ - public void run(){ - robot.mouseMove(updateTargetLocation().x, updateTargetLocation().y); - robot.mousePress(getMask(buttonNumber.getSelectedIndex()+1)); - } - }; - timer.schedule(robotInteraction, SEND_DELAY); - } - }); - - releaseOn.addActionListener(new ActionListener(){ - public void actionPerformed(ActionEvent e){ - System.out.println("Now releasing : " + (buttonNumber.getSelectedIndex()+1)); - Timer timer = new Timer(); - TimerTask robotInteraction = new TimerTask(){ - public void run(){ - robot.mouseMove(updateTargetLocation().x, updateTargetLocation().y); - robot.mouseRelease(getMask(buttonNumber.getSelectedIndex()+1)); - } - }; - timer.schedule(robotInteraction, SEND_DELAY); - } - }); - - clickOn.addActionListener(new ActionListener(){ - public void actionPerformed(ActionEvent e){ - System.out.println("Now clicking : " + (buttonNumber.getSelectedIndex()+1)); - Timer timer = new Timer(); - TimerTask robotInteraction = new TimerTask(){ - public void run(){ - robot.mouseMove(updateTargetLocation().x, updateTargetLocation().y); - robot.mousePress(getMask(buttonNumber.getSelectedIndex()+1)); - robot.mouseRelease(getMask(buttonNumber.getSelectedIndex()+1)); - } - }; - timer.schedule(robotInteraction, SEND_DELAY); - } - - }); - target.addMouseListener(new MouseAdapter(){ - public void mousePressed(MouseEvent e){ - Sysout.println(""+e); - } - public void mouseReleased(MouseEvent e){ - Sysout.println(""+e); - } - public void mouseClicked(MouseEvent e){ - Sysout.println(""+e); - } - }); - - String[] instructions = - { - "Do provide an instruction to the robot by", - "choosing the button number to act and ", - "pressing appropriate java.awt.Button on the left.", - "Inspect an output in the TextArea below.", - "Please don't generate non-natural sequences like Release-Release, etc.", - "If you use keyboard be sure that you released the keyboard shortly.", - "If events are generated well press Pass, otherwise Fail." - }; - Sysout.createDialogWithInstructions( instructions ); - - }//End init() - - private int getMask(int button){ - return InputEvent.getMaskForButton(button); - - /* - //this only works for standard buttons and for old JDK builds - int mask = 0; - switch (button){ - case 1: { - mask = InputEvent.BUTTON1_MASK; - break; - } - case 2: { - mask = InputEvent.BUTTON2_MASK; - break; - } - case 3: { - mask = InputEvent.BUTTON3_MASK; - break; - } - } - return mask; - */ - } - - private Point updateTargetLocation() { - return new Point(target.getLocationOnScreen().x + target.getWidth()/2, target.getLocationOnScreen().y + target.getHeight()/2); - } - - public void start () - { - //Get things going. Request focus, set size, et cetera - setSize (200,200); - setVisible(true); - validate(); - Frame f = new Frame ("Set action for Robot here."); - f.setLayout(new FlowLayout()); - f.add(buttonNumber); - f.add(pressOn); - f.add(releaseOn); - f.add(clickOn); - f.add(target); - f.pack(); - f.setVisible(true); - }// start() -}// class - -/* Place other classes related to the test after this line */ - - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 120; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - }// while - }// for - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff --git a/test/jdk/java/awt/Robot/ModifierRobotKey/ModifierRobotKeyTest.java b/test/jdk/java/awt/Robot/ModifierRobotKey/ModifierRobotKeyTest.java index 69c189146f2..e6ae8ff866a 100644 --- a/test/jdk/java/awt/Robot/ModifierRobotKey/ModifierRobotKeyTest.java +++ b/test/jdk/java/awt/Robot/ModifierRobotKey/ModifierRobotKeyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,7 +71,7 @@ public static void main(String[] args) throws Exception { public ModifierRobotKeyTest() throws Exception { String os = System.getProperty("os.name").toLowerCase(); - if (os.contains("os x")) { + if (os.contains("os x") || os.contains("linux")) { modifierKeys = new int[3]; modifierKeys[0] = KeyEvent.VK_SHIFT; modifierKeys[1] = KeyEvent.VK_CONTROL; diff --git a/test/jdk/java/awt/ScrollPane/ScrollPaneTest.java b/test/jdk/java/awt/ScrollPane/ScrollPaneTest.java new file mode 100644 index 00000000000..7b628d900a5 --- /dev/null +++ b/test/jdk/java/awt/ScrollPane/ScrollPaneTest.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.ScrollPane; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; + +/* + * @test + * @bug 4124460 + * @key headful + * @summary Test for initializing a Motif peer component causes a crash. +*/ + +public class ScrollPaneTest { + private static volatile Point p1 = null; + private static volatile Point p2 = null; + private static Robot robot = null; + + private static Point getClickPoint(Component component) { + Point locationOnScreen = component.getLocationOnScreen(); + Dimension size = component.getSize(); + locationOnScreen.x += size.width / 2; + locationOnScreen.y += size.height / 2; + return locationOnScreen; + } + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(100); + + try { + doTest(); + } finally { + ScrollPaneTester.disposeAll(); + } + } + + private static void doTest() throws Exception { + EventQueue.invokeAndWait(ScrollPaneTester::initAndShowGui); + + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + p1 = getClickPoint(ScrollPaneTester.st1.buttonRight); + p2 = getClickPoint(ScrollPaneTester.st1.buttonSwap); + }); + + robot.mouseMove(p1.x, p1.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.mouseMove(p2.x, p2.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + p1 = getClickPoint(ScrollPaneTester.st2.buttonRight); + p2 = getClickPoint(ScrollPaneTester.st2.buttonSwap); + }); + + robot.mouseMove(p1.x, p1.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.mouseMove(p2.x, p2.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } +} + +class ScrollPaneTester implements ActionListener { + static ScrollPaneTester st1, st2; + final Button buttonLeft, buttonRight, buttonQuit, buttonSwap; + protected ScrollPane sp; + protected Frame f; + + public static void initAndShowGui() { + ScrollPaneTester.st1 = new ScrollPaneTester(true); + ScrollPaneTester.st2 = new ScrollPaneTester(false); + } + + public ScrollPaneTester(boolean large) { + sp = new ScrollPane(ScrollPane.SCROLLBARS_NEVER); + + Panel p = new Panel(); + + if (large) { + p.setLayout(new GridLayout(10, 10)); + for (int i = 0; i < 10; i++) + for (int j = 0; j < 10; j++) { + TextField tf = new TextField("I am " + i + j); + tf.setSize(100, 20); + p.add(tf); + } + } else { + TextField tf = new TextField("Smallness:"); + tf.setSize(150, 50); + p.add(tf); + } + + sp.add(p); + + // Button panel + buttonLeft = new Button("Left"); + buttonLeft.addActionListener(this); + buttonQuit = new Button("Quit"); + buttonQuit.addActionListener(this); + buttonSwap = new Button("Swap"); + buttonSwap.addActionListener(this); + buttonRight = new Button("Right"); + buttonRight.addActionListener(this); + + Panel bp = new Panel(); + bp.add(buttonLeft); + bp.add(buttonSwap); + bp.add(buttonQuit); + bp.add(buttonRight); + + // Window w/ button panel and scrollpane + f = new Frame("ScrollPane Test " + (large ? "large" : "small")); + f.setLayout(new BorderLayout()); + f.add("South", bp); + f.add("Center", sp); + + if (large) { + f.setSize(300, 200); + f.setLocation(100, 100); + } else { + f.setSize(200, 100); + f.setLocation(500, 100); + } + + f.setVisible(true); + } + + public static void disposeAll() { + ScrollPaneTester.st1.f.dispose(); + ScrollPaneTester.st2.f.dispose(); + } + + public static void + swapPanels() { + ScrollPane sss = st1.sp; + + st1.f.add("Center", st2.sp); + st1.sp = st2.sp; + + st2.f.add("Center", sss); + st2.sp = sss; + } + + public void + actionPerformed(ActionEvent ev) { + Object s = ev.getSource(); + + if (s == buttonLeft) { + scroll(true); + } else if (s == buttonRight) { + scroll(false); + } else if (s == buttonSwap) { + swapPanels(); + } else if (s == buttonQuit) { + disposeAll(); + } + } + + private void + scroll(boolean scroll_left) { + Point p = sp.getScrollPosition(); + + if (scroll_left) + p.x = Math.max(0, p.x - 20); + else { + int cwidth = sp.getComponent(0).getSize().width; + p.x = Math.min(p.x + 20, cwidth); + } + + sp.setScrollPosition(p); + } +} diff --git a/test/jdk/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java b/test/jdk/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java index 6018d044a61..1f2de081cce 100644 --- a/test/jdk/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java +++ b/test/jdk/java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,6 +120,7 @@ static void testSplash(ImageInfo test) throws Exception { static void testFocus() throws Exception { Robot robot = new Robot(); + robot.setAutoWaitForIdle(true); robot.setAutoDelay(50); Frame frame = new Frame(); @@ -130,6 +131,7 @@ static void testFocus() throws Exception { frame.add(textField); frame.setVisible(true); robot.waitForIdle(); + robot.delay(1000); robot.keyPress(KeyEvent.VK_A); robot.keyRelease(KeyEvent.VK_A); diff --git a/test/jdk/java/awt/TextArea/Length.java b/test/jdk/java/awt/TextArea/Length.java new file mode 100644 index 00000000000..1ea99659383 --- /dev/null +++ b/test/jdk/java/awt/TextArea/Length.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * 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.EventQueue; +import java.awt.TextArea; + +/* + * @test + * @bug 4120876 + * @key headful + * @summary Ensure that getText can handle strings of various lengths, + * in particular strings longer than 255 characters + */ + +public class Length { + + public static void main(String[] args) throws Exception { + EventQueue.invokeAndWait(() -> { + TextArea ta = new TextArea(); + StringBuffer sb = new StringBuffer("x"); + + for (int i = 0; i < 14; i++) { + String s = sb.toString(); + check(ta, s.substring(1)); + check(ta, s); + check(ta, s + "y"); + sb.append(s); + } + }); + } + + static void check(TextArea ta, String s) { + ta.setText(s); + String s2 = ta.getText(); + System.err.println(s.length() + " " + s2.length()); + if (s.length() != s2.length()) { + throw new RuntimeException("Expected " + s.length() + + "chars, got " + s2.length()); + } + } +} diff --git a/test/jdk/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java b/test/jdk/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java index 61c9ba6c22f..c052468a8b9 100644 --- a/test/jdk/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java +++ b/test/jdk/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,6 +98,7 @@ public void run() { } }); robot.waitForIdle(); + robot.delay(500); SwingUtilities.invokeAndWait(new Runnable() { @Override diff --git a/test/jdk/java/awt/Toolkit/DesktopProperties/rfe4758438.sh b/test/jdk/java/awt/Toolkit/DesktopProperties/rfe4758438.sh index ce5628ac9d4..e1c00e9adc0 100644 --- a/test/jdk/java/awt/Toolkit/DesktopProperties/rfe4758438.sh +++ b/test/jdk/java/awt/Toolkit/DesktopProperties/rfe4758438.sh @@ -28,20 +28,6 @@ OS=`uname` case "$OS" in Linux* ) - GNOMESID=`pgrep gnome-session | head -n1` - - printf "\n/* gnome-session environ\n" - cat "/proc/$GNOMESID/environ" | tr '\0' '\n' - printf "\n*/\n\n" - - DBUS_SESSION_BUS_ADDRESS=`grep -z DBUS_SESSION_BUS_ADDRESS /proc/$GNOMESID/environ | cut -d= -f2-` - export DBUS_SESSION_BUS_ADDRESS - - DISPLAY=`grep -z DISPLAY /proc/$GNOMESID/environ | cut -d= -f2-` - export DISPLAY - - XDG_CURRENT_DESKTOP=`grep -z XDG_CURRENT_DESKTOP /proc/$GNOMESID/environ | cut -d= -f2-` - export XDG_CURRENT_DESKTOP ;; * ) echo "This Feature is not to be tested on $OS" diff --git a/test/jdk/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java b/test/jdk/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java index 5161fa3cc9b..23920e89c50 100644 --- a/test/jdk/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java +++ b/test/jdk/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java @@ -79,7 +79,10 @@ public static void main(String[] args) throws Exception { public ActionEventTest() throws Exception { robot = new Robot(); + robot.setAutoDelay(25); EventQueue.invokeAndWait(this::initializeGUI); + robot.waitForIdle(); + robot.delay(500); } private void initializeGUI() { @@ -117,10 +120,6 @@ public void clear() { } void doTest() throws Exception { - robot.keyPress(KeyEvent.VK_ALT); - robot.keyPress(KeyEvent.VK_SHIFT); - robot.keyPress(KeyEvent.VK_CONTROL); - Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon); if (iconPosition == null) { throw new RuntimeException("Unable to find the icon location!"); @@ -129,6 +128,10 @@ void doTest() throws Exception { robot.mouseMove(iconPosition.x, iconPosition.y); robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.delay(100); diff --git a/test/jdk/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java b/test/jdk/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java index 9d6189722c3..7b487364f96 100644 --- a/test/jdk/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java +++ b/test/jdk/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ public class TrayIconPopupTest { boolean actionPerformed = false; Object actionLock = new Object(); - static final int ATTEMPTS = 50; + static final int ATTEMPTS = 10; PopupMenu popup; Dialog window; diff --git a/test/jdk/java/awt/Window/FindOwner/FindOwnerTest.html b/test/jdk/java/awt/Window/FindOwner/FindOwnerTest.html deleted file mode 100644 index 38846d9285f..00000000000 --- a/test/jdk/java/awt/Window/FindOwner/FindOwnerTest.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - Testing Menus - - - - - - diff --git a/test/jdk/java/awt/Window/FindOwner/FindOwnerTest.java b/test/jdk/java/awt/Window/FindOwner/FindOwnerTest.java deleted file mode 100644 index 0d4f0ccd60e..00000000000 --- a/test/jdk/java/awt/Window/FindOwner/FindOwnerTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @bug 8139227 - @summary Text fields in JPopupMenu structure do not receive focus in hosted - Applets - @author Semyon Sadetsky -*/ - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; - -public class FindOwnerTest extends Applet -{ - - private boolean gained; - - public void init() { - super.init(); - } - - @Override - public void start() { - Window owner = SwingUtilities.windowForComponent(this); - - Window window1 = new Window(owner); - window1.setVisible(true); - - Window window2 = new Window(window1); - window2.setFocusable(true); - JTextField field = new JTextField("JTextField"); - field.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - gained = true; - } - - @Override - public void focusLost(FocusEvent e) { - } - }); - window2.setBounds(100, 100, 200, 200); - window2.add(field); - window2.setVisible(true); - - try { - gained = false; - Robot robot = new Robot(); - robot.setAutoDelay(50); - robot.waitForIdle(); - robot.delay(200); - - Point p = field.getLocationOnScreen(); - System.out.println(p); - robot.mouseMove(p.x + 1, p.y + 1); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.mouseRelease(InputEvent.BUTTON1_MASK); - robot.waitForIdle(); - robot.delay(200); - - if (!gained) { - throw new Exception("Focus is not gained upon mouse click"); - } - System.out.println("ok"); - } catch (SecurityException e) { - - JOptionPane optionPane = new JOptionPane( - "You are in the browser so test is manual. Try to " + - "click \"JTextField\" in the opened window then press OK " + - "below", - JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION); - JDialog dialog = - optionPane.createDialog(null,"FindOwnerTest instruction"); - dialog.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL); - dialog.setVisible(true); - if (!gained) { - throw new RuntimeException( - "Focus is not gained upon mouse click"); - } - System.out.println("ok"); - } catch (Exception e) { - throw new RuntimeException(e); - } finally { - window1.dispose(); - stop(); - } - } -} diff --git a/test/jdk/java/awt/Window/Grab/GrabTest.java b/test/jdk/java/awt/Window/Grab/GrabTest.java index 5db28cb15b5..b173477c164 100644 --- a/test/jdk/java/awt/Window/Grab/GrabTest.java +++ b/test/jdk/java/awt/Window/Grab/GrabTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. * 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,19 +22,34 @@ */ /* - @test - @key headful - @bug 7124430 - @summary Tests that SunToolkit.grab API works - @author anton.tarasov@oracle.com: area=awt.toolkit - @library ../../regtesthelpers - @modules java.desktop/sun.awt - @build Util - @run main GrabTest -*/ - -import java.awt.*; -import java.awt.event.*; + * @test + * @key headful + * @bug 7124430 + * @summary Tests that SunToolkit.grab API works + * @library ../../regtesthelpers + * @modules java.desktop/sun.awt + * @build Util + * @run main GrabTest + */ + + +import java.awt.AWTEvent; +import java.awt.Button; +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.AWTEventListener; +import java.awt.event.MouseAdapter; + +import javax.swing.SwingUtilities; import test.java.awt.regtesthelpers.Util; public class GrabTest { @@ -56,9 +71,13 @@ public class GrabTest { static volatile boolean passed = true; - public static void main(String[] args) { + public static void main(String[] args) throws Exception { + + robot = new Robot(); + robot.setAutoDelay(100); - Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() { + SwingUtilities.invokeAndWait(() -> { + Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() { public void eventDispatched(AWTEvent e) { System.out.println(e); if (e instanceof sun.awt.UngrabEvent) { @@ -67,61 +86,56 @@ public void eventDispatched(AWTEvent e) { } }, sun.awt.SunToolkit.GRAB_EVENT_MASK); - f = new Frame("Frame"); - f.setBounds(0, 0, 300, 300); - f.addMouseListener(new MouseAdapter() { + f = new Frame("Frame"); + f.setBounds(0, 0, 300, 300); + f.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { System.out.println(e); framePressed = true; } }); - f1 = new Frame("OtherFrame"); - f1.setBounds(700, 100, 300, 300); + f1 = new Frame("OtherFrame"); + f1.setBounds(700, 100, 300, 300); - w = new Window(f); - w.setLayout(new FlowLayout()); - b = new Button("Press"); - b.addActionListener(new ActionListener() { + w = new Window(f); + w.setLayout(new FlowLayout()); + b = new Button("Press"); + b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println(e); buttonPressed = true; } }); - w.add(b); - w.setBounds(400, 100, 300, 300); - w.setBackground(Color.blue); - w.addMouseListener(new MouseAdapter() { + w.add(b); + w.setBounds(400, 100, 300, 300); + w.setBackground(Color.blue); + w.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { System.out.println(e); windowPressed = true; } }); - f.setVisible(true); - w.setVisible(true); + f.setVisible(true); + w.setVisible(true); - frame = new Frame(); - window1 = new Window(frame); - window1.setSize(200, 200); - window1.setLocationRelativeTo(null); - window1.setBackground(Color.blue); + frame = new Frame(); + window1 = new Window(frame); + window1.setSize(200, 200); + window1.setLocationRelativeTo(null); + window1.setBackground(Color.blue); - window2 = new Window(window1); - window2.setSize(100, 100); - window2.setLocationRelativeTo(null); - window2.setBackground(Color.green); + window2 = new Window(window1); + window2.setSize(100, 100); + window2.setLocationRelativeTo(null); + window2.setBackground(Color.green); - tk = (sun.awt.SunToolkit)Toolkit.getDefaultToolkit(); - - try { - robot = new Robot(); - } catch (AWTException ex) { - throw new RuntimeException(ex); - } + tk = (sun.awt.SunToolkit)Toolkit.getDefaultToolkit(); + }); Util.waitForIdle(robot); - + robot.delay(500); test(); } @@ -131,6 +145,7 @@ public static void test() { // 1. Check that button press doesn't cause ungrab Util.clickOnComp(b, robot); Util.waitForIdle(robot); + checkAndThrow(buttonPressed, "Error: Button can not be pressed"); if (ungrabbed) { passed = false; @@ -151,6 +166,7 @@ public static void test() { // 3. Check that press on the frame causes ungrab, event must be dispatched Util.clickOnComp(f, robot); Util.waitForIdle(robot); + checkAndThrow(framePressed, "Error: Frame can't be pressed"); if (!ungrabbed) { passed = false; @@ -173,28 +189,33 @@ public static void test() { // 5. Check that press on the other frame's title causes ungrab f1.setVisible(true); Util.waitForIdle(robot); + robot.delay(500); + Util.clickOnTitle(f1, robot); + Util.waitForIdle(robot); + if (!ungrabbed) { passed = false; System.err.println("Failure: [5] Press inside of other Frame's title didn't cause ungrab"); } f.requestFocus(); // restore focus Util.waitForIdle(robot); + if (!f.hasFocus()) { System.err.println("Error: Frame can't be focused"); } ungrabbed = false; tk.grab(w); - // 6. Check that press on the outside area causes ungrab Point loc = f.getLocationOnScreen(); robot.mouseMove(loc.x + 100, loc.y + f.getSize().height + 10); Util.waitForIdle(robot); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.delay(50); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); Util.waitForIdle(robot); + if (!ungrabbed) { passed = false; System.err.println("Failure: [6] Press on the outside area didn't cause ungrab"); @@ -218,6 +239,7 @@ public static void test() { window1.setVisible(true); window2.setVisible(true); Util.waitForIdle(robot); + robot.delay(500); tk.grab(window1); diff --git a/test/jdk/java/awt/Window/SetWindowLocationByPlatformTest/SetWindowLocationByPlatformTest.java b/test/jdk/java/awt/Window/SetWindowLocationByPlatformTest/SetWindowLocationByPlatformTest.java index 06c2a505cd4..141e9f45df0 100644 --- a/test/jdk/java/awt/Window/SetWindowLocationByPlatformTest/SetWindowLocationByPlatformTest.java +++ b/test/jdk/java/awt/Window/SetWindowLocationByPlatformTest/SetWindowLocationByPlatformTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,6 +51,7 @@ public static void main(String[] args) { frame2.setLocationByPlatform(true); frame2.setVisible(true); Util.waitForIdle(r); + r.delay(500); Point point1 = frame1.getLocationOnScreen(); Point point2 = frame2.getLocationOnScreen(); diff --git a/test/jdk/java/awt/Window/WindowOwner.java b/test/jdk/java/awt/Window/WindowOwner.java new file mode 100644 index 00000000000..82cb35a1faa --- /dev/null +++ b/test/jdk/java/awt/Window/WindowOwner.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * 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.Dialog; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Panel; +import java.awt.Window; +import java.util.ArrayList; +import java.util.List; + +/* + * @test + * @key headful + * @summary automated test for window-ownership on Windows, Frames, and Dialogs + */ + +public class WindowOwner extends Panel { + + Label status = null; + static List windowsToDispose = new ArrayList<>(); + + public static void main(String[] args) throws Exception { + WindowOwner windowOwner = new WindowOwner(); + try { + EventQueue.invokeAndWait(windowOwner::init); + Thread.sleep(2000); + } finally { + EventQueue.invokeAndWait( + () -> windowsToDispose.forEach(Window::dispose) + ); + } + } + + public void init() { + status = new Label(); + add(status); + + statusMessage("Testing Window Ownership..."); + + // Test Frame as owner + Frame frame0 = new Frame("WindowOwner Test"); + windowsToDispose.add(frame0); + frame0.add("Center", new Label("Frame Level0")); + + Dialog dialog1 = new Dialog(frame0, "WindowOwner Test"); + windowsToDispose.add(dialog1); + dialog1.add("Center", new Label("Dialog Level1")); + verifyOwner(dialog1, frame0); + + Window window1 = new Window(frame0); + windowsToDispose.add(window1); + window1.add("Center", new Label("Window Level1")); + window1.setBounds(10, 10, 140, 70); + verifyOwner(window1, frame0); + + verifyOwnee(frame0, dialog1); + verifyOwnee(frame0, window1); + + // Test Dialog as owner + Dialog dialog2 = new Dialog(dialog1, "WindowOwner Test"); + windowsToDispose.add(dialog2); + dialog2.add("Center", new Label("Dialog Level2")); + verifyOwner(dialog2, dialog1); + + Window window2 = new Window(dialog1); + windowsToDispose.add(window2); + window2.add("Center", new Label("Window Level2")); + window2.setBounds(110, 110, 140, 70); + verifyOwner(window2, dialog1); + + verifyOwnee(dialog1, window2); + verifyOwnee(dialog1, dialog2); + + // Test Window as owner + Window window3 = new Window(window2); + windowsToDispose.add(window3); + window3.add("Center", new Label("Window Level3")); + window3.setBounds(210, 210, 140, 70); + verifyOwner(window3, window2); + verifyOwnee(window2, window3); + + // Ensure native peers handle ownership without errors + frame0.pack(); + frame0.setVisible(true); + + dialog1.pack(); + dialog1.setVisible(true); + + window1.setLocation(50, 50); + window1.setVisible(true); + + dialog2.pack(); + dialog2.setVisible(true); + + window2.setLocation(100, 100); + window2.setVisible(true); + + window3.setLocation(150, 150); + window3.setVisible(true); + + statusMessage("Window Ownership test completed successfully."); + } + + public void statusMessage(String msg) { + status.setText(msg); + status.invalidate(); + validate(); + } + + public static void verifyOwner(Window ownee, Window owner) { + if (ownee.getOwner() != owner) { + throw new RuntimeException("Window owner not valid for " + + ownee.getName()); + } + } + + public static void verifyOwnee(Window owner, Window ownee) { + Window[] ownedWins = owner.getOwnedWindows(); + if (!windowInList(ownedWins, ownee)) { + throw new RuntimeException("Ownee " + ownee.getName() + + " not found in owner list for " + owner.getName()); + } + } + + public static boolean windowInList(Window[] windows, Window target) { + for (Window window : windows) { + if (window == target) { + return true; + } + } + return false; + } +} diff --git a/test/jdk/java/awt/color/ICC_Profile/CustomCMMID.java b/test/jdk/java/awt/color/ICC_Profile/CustomCMMID.java new file mode 100644 index 00000000000..5eb6221d39e --- /dev/null +++ b/test/jdk/java/awt/color/ICC_Profile/CustomCMMID.java @@ -0,0 +1,69 @@ +/* + * 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.util.Arrays; + +/** + * @test + * @bug 8321489 + * @summary tests that the cmm id is not ignored + */ +public final class CustomCMMID { + + private static final byte[] JAVA_ID = { + (byte) 'j', (byte) 'a', (byte) 'v', (byte) 'a', + }; + + private static final int[] CS = { + ColorSpace.CS_CIEXYZ, ColorSpace.CS_GRAY, ColorSpace.CS_LINEAR_RGB, + ColorSpace.CS_PYCC, ColorSpace.CS_sRGB + }; + + public static void main(String[] args) { + for (int cs : CS) { + ICC_Profile p = createProfile(cs); + validate(p); + } + } + + private static ICC_Profile createProfile(int type) { + byte[] data = ICC_Profile.getInstance(type).getData(); + System.arraycopy(JAVA_ID, 0, data, ICC_Profile.icHdrCmmId, + JAVA_ID.length); + return ICC_Profile.getInstance(data); + } + + private static void validate(ICC_Profile p) { + byte[] header = p.getData(ICC_Profile.icSigHead); + byte[] id = new byte[JAVA_ID.length]; + System.arraycopy(header, ICC_Profile.icHdrCmmId, id, 0, JAVA_ID.length); + + if (!java.util.Arrays.equals(id, JAVA_ID)) { + System.err.println("Expected: " + Arrays.toString(JAVA_ID)); + System.err.println("Actual: " + Arrays.toString(id)); + throw new RuntimeException("Wrong cmm id"); + } + } +} diff --git a/test/jdk/java/awt/dnd/MouseEventAfterStartDragTest/MouseEventAfterStartDragTest.java b/test/jdk/java/awt/dnd/MouseEventAfterStartDragTest/MouseEventAfterStartDragTest.java new file mode 100644 index 00000000000..faa98c43b75 --- /dev/null +++ b/test/jdk/java/awt/dnd/MouseEventAfterStartDragTest/MouseEventAfterStartDragTest.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.event.AWTEventListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.MouseMotionListener; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4613903 + * @summary verifies that mouse events are not dispatched during drag + * @key headful + * @run main MouseEventAfterStartDragTest + */ + +public final class MouseEventAfterStartDragTest implements AWTEventListener { + final Frame frame = new Frame(); + volatile Point srcPoint; + volatile Dimension d; + volatile MouseEvent lastMouseEvent = null; + volatile boolean passed = true; + final DragSource dragSource = DragSource.getDefaultDragSource(); + final Transferable transferable = new StringSelection("TEXT"); + + final MouseMotionListener mouseMotionListener = new MouseMotionAdapter() { + public void mouseDragged(MouseEvent e) { + System.out.println("mouseDragged: " + e + + ", hash:" + e.hashCode()); + if (lastMouseEvent != null && !e.equals(lastMouseEvent)) { + System.out.println("Unexpected: " + e + + ", hash:" + e.hashCode()); + passed = false; + } + } + }; + + final DragSourceListener dragSourceListener = new DragSourceAdapter() { + public void dragDropEnd(DragSourceDragEvent dsde) { + System.out.println("dragDropEnd: " + dsde); + lastMouseEvent = null; + } + }; + + final DragGestureListener dragGestureListener = new DragGestureListener() { + public void dragGestureRecognized(DragGestureEvent dge) { + System.out.println("dragGestureRecognized: " + dge); + Object[] events = dge.toArray(); + Object lastEvent = events[events.length - 1]; + if (lastEvent instanceof MouseEvent) { + lastMouseEvent = (MouseEvent) lastEvent; + } + System.out.println("The last mouse event: " + lastMouseEvent + + ", hash:" + lastMouseEvent.hashCode()); + dge.startDrag(null, transferable, dragSourceListener); + } + }; + + static final Object SYNC_LOCK = new Object(); + static final int MOUSE_RELEASE_TIMEOUT = 1000; + volatile Component clickedComponent = null; + + public static void main(String[] args) throws Exception { + System.setProperty("awt.dnd.drag.threshold", "0"); + MouseEventAfterStartDragTest app = new MouseEventAfterStartDragTest(); + try { + app.createAndShowGUI(); + app.test(); + } finally { + app.dispose(); + } + } + + public void createAndShowGUI() throws Exception { + SwingUtilities.invokeAndWait(() -> { + frame.setTitle("Test frame"); + frame.setBounds(100, 100, 200, 200); + frame.setLocationRelativeTo(null); + frame.addMouseMotionListener(mouseMotionListener); + dragSource.createDefaultDragGestureRecognizer(frame, DnDConstants.ACTION_COPY_OR_MOVE, + dragGestureListener); + + frame.getToolkit().addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK); + frame.setVisible(true); + }); + } + + public static int sign(int n) { + return n < 0 ? -1 : n == 0 ? 0 : 1; + } + + public void test() throws Exception { + final Robot robot = new Robot(); + robot.setAutoDelay(45); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> { + srcPoint = frame.getLocationOnScreen(); + d = frame.getSize(); + }); + srcPoint.translate(d.width / 2, d.height / 2); + + if (!pointInComponent(robot, srcPoint, frame)) { + System.err.println("WARNING: Couldn't locate source frame."); + return; + } + + final Point dstPoint = new Point(srcPoint); + dstPoint.translate(d.width / 4, d.height / 4); + + if (!pointInComponent(robot, dstPoint, frame)) { + System.err.println("WARNING: Couldn't locate target frame."); + return; + } + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.delay(250); + System.out.println("srcPoint = " + srcPoint); + for (; !srcPoint.equals(dstPoint); + srcPoint.translate(sign(dstPoint.x - srcPoint.x), + sign(dstPoint.y - srcPoint.y))) { + robot.mouseMove(srcPoint.x, srcPoint.y); + System.out.println("srcPoint = " + srcPoint); + } + + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + System.out.println("done"); + robot.waitForIdle(); + robot.delay(MOUSE_RELEASE_TIMEOUT); + + if (!passed) { + throw new RuntimeException("Test failed"); + } + } + + public void dispose() throws Exception { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + public void reset() { + clickedComponent = null; + } + + public void eventDispatched(AWTEvent e) { + if (e.getID() == MouseEvent.MOUSE_RELEASED) { + clickedComponent = (Component) e.getSource(); + synchronized (SYNC_LOCK) { + SYNC_LOCK.notifyAll(); + } + } + } + + boolean pointInComponent(Robot robot, Point p, Component comp) + throws InterruptedException { + robot.waitForIdle(); + reset(); + robot.mouseMove(p.x, p.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + synchronized (SYNC_LOCK) { + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + SYNC_LOCK.wait(MOUSE_RELEASE_TIMEOUT); + } + + Component c = clickedComponent; + + while (c != null && c != comp) { + c = c.getParent(); + } + + return c == comp; + } +} diff --git a/test/jdk/java/awt/event/KeyEvent/FunctionKeyTest.java b/test/jdk/java/awt/event/KeyEvent/FunctionKeyTest.java new file mode 100644 index 00000000000..02e7a890d83 --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/FunctionKeyTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Event; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Robot; +import java.awt.TextArea; +import java.awt.event.KeyEvent; + +/* + * @test + * @bug 4011219 + * @summary Test for function key press/release received by Java client. + * @key headful + */ + +public class FunctionKeyTest { + private static FunctionKeyTester frame; + private static Robot robot; + + static volatile boolean keyPressReceived; + static volatile boolean keyReleaseReceived; + + static final StringBuilder failures = new StringBuilder(); + + private static void testKey(int keyCode, String keyText) { + keyPressReceived = false; + keyReleaseReceived = false; + + robot.keyPress(keyCode); + + if (!keyPressReceived) { + failures.append(keyText).append(" key press is not received\n"); + } + + robot.keyRelease(keyCode); + + if (!keyReleaseReceived) { + failures.append(keyText).append(" key release is not received\n"); + } + } + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(150); + + try { + EventQueue.invokeAndWait(() -> { + frame = new FunctionKeyTester(); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + + robot.waitForIdle(); + robot.delay(1000); + + testKey(KeyEvent.VK_F11, "F11"); + testKey(KeyEvent.VK_F12, "F12"); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + if (failures.isEmpty()) { + System.out.println("Passed"); + } else { + throw new RuntimeException(failures.toString()); + } + } +} + +class FunctionKeyTester extends Frame { + Label l = new Label ("NULL"); + Button b = new Button(); + TextArea log = new TextArea(); + + FunctionKeyTester() { + super("Function Key Test"); + this.setLayout(new BorderLayout()); + this.add(BorderLayout.NORTH, l); + this.add(BorderLayout.SOUTH, b); + this.add(BorderLayout.CENTER, log); + log.setFocusable(false); + log.setEditable(false); + l.setBackground(Color.red); + setSize(200, 200); + } + + public boolean handleEvent(Event e) { + String message = "e.id=" + e.id + "\n"; + System.out.print(message); + log.append(message); + + switch (e.id) { + case 403 -> FunctionKeyTest.keyPressReceived = true; + case 404 -> FunctionKeyTest.keyReleaseReceived = true; + } + + return super.handleEvent(e); + } + + public boolean keyDown(Event e, int key) { + l.setText("e.key=" + Integer.valueOf(e.key).toString()); + return false; + } +} diff --git a/test/jdk/java/awt/event/KeyEvent/SwallowKeyEvents/SwallowKeyEvents.java b/test/jdk/java/awt/event/KeyEvent/SwallowKeyEvents/SwallowKeyEvents.java index 421d8fe2faf..58a72aa8767 100644 --- a/test/jdk/java/awt/event/KeyEvent/SwallowKeyEvents/SwallowKeyEvents.java +++ b/test/jdk/java/awt/event/KeyEvent/SwallowKeyEvents/SwallowKeyEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,20 +21,6 @@ * questions. */ -/* - @test - @key headful - @bug 7154072 7161320 - @summary Tests that key events with modifiers are not swallowed. - @author anton.tarasov: area=awt.focus - @library ../../../regtesthelpers - @library /test/lib - @modules java.desktop/sun.awt - @build jdk.test.lib.Platform - @build Util - @run main SwallowKeyEvents -*/ - import jdk.test.lib.Platform; import java.awt.AWTException; import java.awt.Frame; @@ -44,6 +30,20 @@ import java.awt.event.KeyEvent; import test.java.awt.regtesthelpers.Util; +/* + @test + @key headful + @bug 7154072 7161320 + @summary Tests that key events with modifiers are not swallowed. + @requires (os.family != "windows") + @library /java/awt/regtesthelpers + @library /test/lib + @modules java.desktop/sun.awt + @build jdk.test.lib.Platform + @build Util + @run main SwallowKeyEvents +*/ + public class SwallowKeyEvents { static final int PRESS_COUNT = 10; @@ -83,6 +83,8 @@ public void keyPressed(KeyEvent ke) { }); test(); + r.waitForIdle(); + r.delay(500); System.out.println("key_pressed count: " + keyPressedCount); diff --git a/test/jdk/java/awt/event/MouseEvent/ClickDuringKeypress/ClickDuringKeypress.java b/test/jdk/java/awt/event/MouseEvent/ClickDuringKeypress/ClickDuringKeypress.java index 2f0affd5620..ae757bb7d4e 100644 --- a/test/jdk/java/awt/event/MouseEvent/ClickDuringKeypress/ClickDuringKeypress.java +++ b/test/jdk/java/awt/event/MouseEvent/ClickDuringKeypress/ClickDuringKeypress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,116 +21,89 @@ * questions. */ +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + /* - @test 1.2 98/08/05 + @test @key headful @bug 4515763 @summary Tests that clicking mouse and pressing keys generates correct amount of click-counts - @author andrei.dmitriev: area=awt.mouse @run main ClickDuringKeypress */ -/** - * ClickDuringKeypress.java - * - * summary: - */ - -import java.applet.Applet; -import java.awt.*; -import java.awt.event.*; +public class ClickDuringKeypress implements MouseListener { -public class ClickDuringKeypress implements MouseListener - { - //Declare things used in the test, like buttons and labels here final static int CLICKCOUNT = 10; - final static int DOUBLE_CLICK_AUTO_DELAY = 10; - volatile int lastClickCount = 0; - volatile boolean clicked = false; - volatile boolean ready = false; - - Frame frame; - Robot robot; - - public void init() - { - //Create instructions for the user here, as well as set up - // the environment -- set the layout manager, add buttons, - // etc. - + final static int DOUBLE_CLICK_AUTO_DELAY = 20; + static volatile int lastClickCount = 0; + static volatile boolean clicked = false; + static volatile boolean ready = false; + + static volatile Frame frame; + static volatile Robot robot; + static final ClickDuringKeypress clicker = new ClickDuringKeypress(); + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(ClickDuringKeypress::createUI); + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.delay(2000); + robot.mouseMove(200, 200); + robot.delay(2000); + EventQueue.invokeAndWait(() -> frame.setVisible(true)); + doTest(); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + } + + static void createUI() { frame = new Frame("ClickDuringKeypress"); - frame.addMouseListener(this); + frame.addMouseListener(clicker); frame.addWindowListener(new WindowAdapter() { public void windowActivated(WindowEvent e) { - synchronized(ClickDuringKeypress.this) { ready = true; - ClickDuringKeypress.this.notifyAll(); - } } }); frame.setBounds(0, 0, 400, 400); + } - start(); - - }//End init() - - public void start () - { - try { - robot = new Robot(); - } catch (AWTException e) { - System.out.println("Could not create Robot."); - throw new RuntimeException("Couldn't create Robot. Test fails"); - } - - robot.mouseMove(200, 200); - frame.show(); - - synchronized(this) { - try { - if (!ready) { - wait(10000); - } - } catch (InterruptedException ex) { - } - if (!ready) { - System.out.println("Not Activated. Test fails"); - throw new RuntimeException("Not Activated. Test fails"); - } + static void doTest() throws Exception { + robot.waitForIdle(); + robot.delay(1000); + if (!ready) { + System.out.println("Not Activated. Test fails"); + throw new RuntimeException("Not Activated. Test fails"); } - - doTest(); - - //What would normally go into main() will probably go here. - //Use System.out.println for diagnostic messages that you want - //to read after the test is done. - //Use Sysout.println for messages you want the tester to read. - - }// start() - - // Mouse should be over the Frame by this point - private void doTest() { + // Mouse should be over the Frame by this point robot.setAutoDelay(2000); robot.waitForIdle(); robot.keyPress(KeyEvent.VK_B); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.delay(10); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); // Should trigger mouseClicked robot.keyRelease(KeyEvent.VK_B); robot.delay(1000); robot.setAutoDelay(DOUBLE_CLICK_AUTO_DELAY); for (int i = 0; i < CLICKCOUNT / 2; i++) { - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.delay(10); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.keyPress(KeyEvent.VK_B); - robot.delay(10); robot.keyRelease(KeyEvent.VK_B); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.delay(10); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); } robot.waitForIdle(); // check results @@ -156,9 +129,4 @@ public void mouseClicked(MouseEvent e) { clicked = true; lastClickCount = e.getClickCount(); } - - public static void main(String[] args) { - new ClickDuringKeypress().init(); - } - - }// class ClickDuringKeypress +} diff --git a/test/jdk/java/awt/font/Rotate/RotateTest3.java b/test/jdk/java/awt/font/Rotate/RotateTest3.java new file mode 100644 index 00000000000..0241e65e1eb --- /dev/null +++ b/test/jdk/java/awt/font/Rotate/RotateTest3.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * 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; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +/* + * @test + * @key headful + * @bug 4240228 + * @summary This test is designed to test for a crashing bug in the zh + * locale on Solaris. Rotated text should be displayed, but + * anything other than a crash passes the specific test. + * For example, the missing glyph empty box may be displayed + * in some locales, or no text at all. + */ + +public class RotateTest3 extends Panel { + static JFrame frame; + + protected Java2DView java2DView; + + public RotateTest3(){ + this.setLayout(new GridLayout(1, 1)); + this.setSize(300, 300); + this.java2DView = new Java2DView(); + this.add(this.java2DView); + } + + public static void main(String[] s) throws Exception { + try { + SwingUtilities.invokeAndWait(RotateTest3::initAndShowGui); + Thread.sleep(1000); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void initAndShowGui() { + RotateTest3 panel = new RotateTest3(); + + frame = new JFrame("RotateTest3"); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + frame.dispose(); + } + }); + frame.getContentPane().setLayout(new GridLayout(1, 1)); + frame.getContentPane().add("Center", panel); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + static public class Java2DView extends Component { + + public void paint(Graphics g){ + Graphics2D g2d = (Graphics2D) g; + Dimension d = this.getSize(); + g.setColor(this.getBackground()); + g.fillRect(0, 0, d.width, d.height); + g2d.setPaint(Color.black); + + g2d.translate(150,150); + g2d.rotate(-Math.PI / 3); + + String testString = + "\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341"; + g2d.drawString(testString, 0, 0); + } + + public Dimension getMinimumSize(){ + return new Dimension(300, 300); + } + + public Dimension getPreferredSize(){ + return new Dimension(300, 300); + } + } +} diff --git a/test/jdk/java/awt/font/TextLayout/ArabicBox.java b/test/jdk/java/awt/font/TextLayout/ArabicBox.java new file mode 100644 index 00000000000..e03c4cf918e --- /dev/null +++ b/test/jdk/java/awt/font/TextLayout/ArabicBox.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.font.FontRenderContext; +import java.awt.font.TextLayout; + +import javax.swing.JPanel; + +/* + * @test + * @bug 4427483 + * @summary Arabic text followed by newline should have no missing glyphs + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ArabicBox + */ +public final class ArabicBox { + + private static final String TEXT = + "\u0627\u0644\u0639\u0631\u0628\u064A\u0629\n"; + + private static final String FONT_NAME = Font.DIALOG; + + private static final String INSTRUCTIONS = """ + In the below panel, you should see the following text: + + """ + + TEXT + """ + (It's \u2018Arabic\u2019 in Arabic.) + + If there are no 'box glyphs' for missing glyphs, + press Pass; otherwise, press Fail."""; + + public static void main(String[] args) throws Exception { + final Font font = new Font(FONT_NAME, Font.PLAIN, 24); + System.out.println("asked for " + FONT_NAME + " and got: " + font.getFontName()); + + PassFailJFrame.builder() + .title("Arabic Box") + .instructions(INSTRUCTIONS) + .rows(7) + .columns(40) + .splitUIBottom(() -> createPanel(font)) + .build() + .awaitAndCheck(); + } + + private static JPanel createPanel(Font font) { + return new TextPanel(font); + } + + private static final class TextPanel extends JPanel { + private TextLayout layout; + + private TextPanel(Font font) { + setForeground(Color.black); + setBackground(Color.white); + setFont(font); + setPreferredSize(new Dimension(300, 150)); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + Graphics2D g2d = (Graphics2D)g; + if (layout == null) { + Font font = g2d.getFont(); + FontRenderContext frc = g2d.getFontRenderContext(); + + layout = new TextLayout(TEXT, font, frc); + System.out.println(layout.getBounds()); + } + + layout.draw(g2d, 10, 50); + g2d.drawString(TEXT, 10, 100); + } + } +} diff --git a/test/jdk/java/awt/font/TextLayout/TestJustification.html b/test/jdk/java/awt/font/TextLayout/TestJustification.html deleted file mode 100644 index c9e79f44cb2..00000000000 --- a/test/jdk/java/awt/font/TextLayout/TestJustification.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - -Test Justification - - - -

Test Justification

-
-

Five lines of text should appear, all justified to the same width, -followed by a sixth line containing only roman characters and no spaces -which is not justified, and instead is centered. -Carets should appear between all characters. Pass the test if this is -true. -

- -alt="Your browser understands the <APPLET> tag but isn't running the applet, for some reason." -Your browser is completely ignoring the <APPLET> tag! - - - - diff --git a/test/jdk/java/awt/font/TextLayout/TestJustification.java b/test/jdk/java/awt/font/TextLayout/TestJustification.java index 417ddd5adfc..62377531e9d 100644 --- a/test/jdk/java/awt/font/TextLayout/TestJustification.java +++ b/test/jdk/java/awt/font/TextLayout/TestJustification.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,229 +21,241 @@ * questions. */ +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.font.FontRenderContext; +import java.awt.font.LineBreakMeasurer; +import java.awt.font.TextAttribute; +import java.awt.font.TextLayout; +import java.awt.geom.Rectangle2D; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; + /* - * - * See TestJustification.html for main test. + * @test + * @bug 4211728 4178140 8145542 + * @summary Justify several lines of text and verify that the lines are the same + length and cursor positions are correct. + Bug 4211728: TextLayout.draw() draws characters at wrong position. + Bug 4178140: TextLayout does not justify. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestJustification */ -import java.applet.*; -import java.awt.*; -import java.awt.event.*; -import java.awt.font.*; -import java.awt.geom.*; -import java.text.*; - -public class TestJustification extends Applet { - JustificationPanel panel; - - public void init() { - setLayout(new BorderLayout()); - panel = new JustificationPanel("Bitstream Cyberbit"); - add("Center", panel); - } - - public void destroy() { - remove(panel); - } - - // calls system.exit, not for use in tests. - public static void main(String args[]) { - TestJustification justificationTest = new TestJustification(); - justificationTest.init(); - justificationTest.start(); - - Frame f = new Frame("Test Justification"); - f.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - System.exit(0); - } - }); - - f.add("Center", justificationTest); - f.setSize(500, 500); - f.show(); - } - - public String getAppletInfo() { - return "Test TextLayout.getJustifiedLayout()"; - } - - static class JustificationPanel extends Panel { - TextLayout[] layouts; - String fontname; - float height; - float oldfsize; - - AttributedCharacterIterator lineText; - TextLayout[] lines; - int linecount; - float oldwidth; - - JustificationPanel(String fontname) { - this.fontname = fontname; +public class TestJustification { + private static final String INSTRUCTIONS = """ + Five lines of text should appear, all justified to the same width, + followed by a sixth line containing only roman characters and + no spaces which is not justified, and instead is centered. + Carets should appear between all characters. + + PASS the test if this is true, else press FAIL. + """; + + public static void main(String[] args) throws Exception { + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(TestJustification::createUI) + .build() + .awaitAndCheck(); } - private static final String[] texts = { - "This is an english Highlighting demo.", "Highlighting", - "This is an arabic \u0627\u0628\u062a\u062c \u062e\u0644\u0627\u062e demo.", "arabic \u0627\u0628\u062a\u062c", - "This is a hebrew \u05d0\u05d1\u05d2 \u05d3\u05d4\u05d5 demo.", "hebrew \u05d0\u05d1\u05d2", - "This is a cjk \u4e00\u4e01\u4e02\uac00\uac01\uc4fa\uf900\uf901\uf902 demo.", "cjk", - "NoSpaceCJK:\u4e00\u4e01\u4e02and\uac00\uac01\uc4faand\uf900\uf901\uf902", "No", - "NoSpaceRoman", "Space" - }; + private static Frame createUI() { + Frame frame= new Frame("Test Text Justification"); + JustificationPanel panel = new JustificationPanel("Bitstream Cyberbit"); + frame.add(panel); + frame.add("Center", panel); + frame.setSize(500, 450); + return frame; + } - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D)g; + static class JustificationPanel extends Panel { + TextLayout[] layouts; + String fontname; + float height; + float oldfsize; - Dimension d = getSize(); - Insets insets = getInsets(); + AttributedCharacterIterator lineText; + TextLayout[] lines; + int linecount; + float oldwidth; - float w = d.width - insets.left - insets.right; - float h = d.height - insets.top - insets.bottom; - int fsize = (int)w/25; + JustificationPanel(String fontname) { + this.fontname = fontname; + } - FontRenderContext frc = g2d.getFontRenderContext(); + private static final String[] texts = { + "This is an english Highlighting demo.", "Highlighting", + "This is an arabic \u0627\u0628\u062a\u062c \u062e\u0644\u0627\u062e demo.", "arabic \u0627\u0628\u062a\u062c", + "This is a hebrew \u05d0\u05d1\u05d2 \u05d3\u05d4\u05d5 demo.", "hebrew \u05d0\u05d1\u05d2", + "This is a cjk \u4e00\u4e01\u4e02\uac00\uac01\uc4fa\uf900\uf901\uf902 demo.", "cjk", + "NoSpaceCJK:\u4e00\u4e01\u4e02and\uac00\uac01\uc4faand\uf900\uf901\uf902", "No", + "NoSpaceRoman", "Space" + }; - if (layouts == null || fsize != oldfsize) { - oldfsize = fsize; + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D)g; - Font f0 = new Font(fontname, Font.PLAIN, fsize); - Font f1 = new Font(fontname, Font.ITALIC, (int)(fsize * 1.5)); + Dimension d = getSize(); + Insets insets = getInsets(); - if (layouts == null) { - layouts = new TextLayout[texts.length / 2]; - } + float w = d.width - insets.left - insets.right; + float h = d.height - insets.top - insets.bottom; + int fsize = (int)w/25; - height = 0; - for (int i = 0; i < layouts.length; ++i) { - String text = texts[i*2]; - String target = texts[i*2+1]; + FontRenderContext frc = g2d.getFontRenderContext(); - AttributedString astr = new AttributedString(text); - astr.addAttribute(TextAttribute.FONT, f0, 0, text.length()); + if (layouts == null || fsize != oldfsize) { + oldfsize = fsize; - int start = text.indexOf(target); - int limit = start + target.length(); - astr.addAttribute(TextAttribute.FONT, f1, start, limit); + Font f0 = new Font(fontname, Font.PLAIN, fsize); + Font f1 = new Font(fontname, Font.ITALIC, (int)(fsize * 1.5)); - TextLayout layout = new TextLayout(astr.getIterator(), frc); + if (layouts == null) { + layouts = new TextLayout[texts.length / 2]; + } - layout = layout.getJustifiedLayout(w - 20); + height = 0; + for (int i = 0; i < layouts.length; ++i) { + String text = texts[i*2]; + String target = texts[i*2+1]; - layouts[i] = layout; + AttributedString astr = new AttributedString(text); + astr.addAttribute(TextAttribute.FONT, f0, 0, text.length()); + + int start = text.indexOf(target); + int limit = start + target.length(); + astr.addAttribute(TextAttribute.FONT, f1, start, limit); + + TextLayout layout = new TextLayout(astr.getIterator(), frc); - height += layout.getAscent() + layout.getDescent() + layout.getLeading(); - } - } + layout = layout.getJustifiedLayout(w - 20); + + layouts[i] = layout; - g2d.setColor(Color.white); - g2d.fill(new Rectangle.Float(insets.left, insets.top, w, h)); + height += layout.getAscent() + layout.getDescent() + layout.getLeading(); + } + } - float basey = 20; + g2d.setColor(Color.white); + g2d.fill(new Rectangle.Float(insets.left, insets.top, w, h)); - for (int i = 0; i < layouts.length; ++i) { - TextLayout layout = layouts[i]; + float basey = 20; - float la = layout.getAscent(); - float ld = layout.getDescent(); - float ll = layout.getLeading(); - float lw = layout.getAdvance(); - float lh = la + ld + ll; - float lx = (w - lw) / 2f; - float ly = basey + layout.getAscent(); + for (TextLayout layout : layouts) { + float la = layout.getAscent(); + float ld = layout.getDescent(); + float ll = layout.getLeading(); + float lw = layout.getAdvance(); + float lh = la + ld + ll; + float lx = (w - lw) / 2f; + float ly = basey + layout.getAscent(); - g2d.setColor(Color.black); - g2d.translate(insets.left + lx, insets.top + ly); + g2d.setColor(Color.black); + g2d.translate(insets.left + lx, insets.top + ly); - Rectangle2D bounds = new Rectangle2D.Float(0, -la, lw, lh); - g2d.draw(bounds); + Rectangle2D bounds = new Rectangle2D.Float(0, -la, lw, lh); + g2d.draw(bounds); - layout.draw(g2d, 0, 0); + layout.draw(g2d, 0, 0); - g2d.setColor(Color.red); - for (int j = 0, e = layout.getCharacterCount(); j <= e; ++j) { - Shape[] carets = layout.getCaretShapes(j, bounds); - g2d.draw(carets[0]); - } + g2d.setColor(Color.red); + for (int j = 0, e = layout.getCharacterCount(); j <= e; ++j) { + Shape[] carets = layout.getCaretShapes(j, bounds); + g2d.draw(carets[0]); + } - g2d.translate(-insets.left - lx, -insets.top - ly); - basey += layout.getAscent() + layout.getDescent() + layout.getLeading(); - } - - // add LineBreakMeasurer-generated layouts - - if (lineText == null) { - String text = "This is a long line of text that should be broken across multiple " - + "lines and then justified to fit the break width. This test should pass if " - + "these lines are justified to the same width, and fail otherwise. It should " - + "also format the hebrew (\u05d0\u05d1\u05d2 \u05d3\u05d4\u05d5) and arabic " - + "(\u0627\u0628\u062a\u062c \u062e\u0644\u0627\u062e) and CJK " - + "(\u4e00\u4e01\u4e02\uac00\uac01\uc4fa\u67b1\u67b2\u67b3\u67b4\u67b5\u67b6\u67b7" - + "\u67b8\u67b9) text correctly."; - - Float regular = new Float(16.0); - Float big = new Float(24.0); - AttributedString astr = new AttributedString(text); - astr.addAttribute(TextAttribute.SIZE, regular, 0, text.length()); - astr.addAttribute(TextAttribute.FAMILY, fontname, 0, text.length()); - - int ix = text.indexOf("broken"); - astr.addAttribute(TextAttribute.SIZE, big, ix, ix + 6); - ix = text.indexOf("hebrew"); - astr.addAttribute(TextAttribute.SIZE, big, ix, ix + 6); - ix = text.indexOf("arabic"); - astr.addAttribute(TextAttribute.SIZE, big, ix, ix + 6); - ix = text.indexOf("CJK"); - astr.addAttribute(TextAttribute.SIZE, big, ix, ix + 3); - - lineText = astr.getIterator(); - } - - float width = w - 20; - if (lines == null || width != oldwidth) { - oldwidth = width; - - lines = new TextLayout[10]; - linecount = 0; - - LineBreakMeasurer measurer = new LineBreakMeasurer(lineText, frc); - - for (;;) { - TextLayout layout = measurer.nextLayout(width); - if (layout == null) { - break; - } - - // justify all but last line - if (linecount > 0) { - lines[linecount - 1] = lines[linecount - 1].getJustifiedLayout(width); - } - - if (linecount == lines.length) { - TextLayout[] nlines = new TextLayout[lines.length * 2]; - System.arraycopy(lines, 0, nlines, 0, lines.length); - lines = nlines; - } - - lines[linecount++] = layout; - } - } + g2d.translate(-insets.left - lx, -insets.top - ly); + basey += layout.getAscent() + layout.getDescent() + layout.getLeading(); + } - float basex = insets.left + 10; - basey += 10; - g2d.setColor(Color.black); + // add LineBreakMeasurer-generated layouts - for (int i = 0; i < linecount; ++i) { - TextLayout layout = lines[i]; + if (lineText == null) { + String text = "This is a long line of text that should be broken across multiple " + + "lines and then justified to fit the break width. This test should pass if " + + "these lines are justified to the same width, and fail otherwise. It should " + + "also format the hebrew (\u05d0\u05d1\u05d2 \u05d3\u05d4\u05d5) and arabic " + + "(\u0627\u0628\u062a\u062c \u062e\u0644\u0627\u062e) and CJK " + + "(\u4e00\u4e01\u4e02\uac00\uac01\uc4fa\u67b1\u67b2\u67b3\u67b4\u67b5\u67b6\u67b7" + + "\u67b8\u67b9) text correctly."; - basey += layout.getAscent(); - float adv = layout.getAdvance(); - float dx = layout.isLeftToRight() ? 0 : width - adv; + Float regular = 16.0F; + Float big = 24.0F; + AttributedString astr = new AttributedString(text); + astr.addAttribute(TextAttribute.SIZE, regular, 0, text.length()); + astr.addAttribute(TextAttribute.FAMILY, fontname, 0, text.length()); - layout.draw(g2d, basex + dx, basey); + int ix = text.indexOf("broken"); + astr.addAttribute(TextAttribute.SIZE, big, ix, ix + 6); + ix = text.indexOf("hebrew"); + astr.addAttribute(TextAttribute.SIZE, big, ix, ix + 6); + ix = text.indexOf("arabic"); + astr.addAttribute(TextAttribute.SIZE, big, ix, ix + 6); + ix = text.indexOf("CJK"); + astr.addAttribute(TextAttribute.SIZE, big, ix, ix + 3); - basey += layout.getDescent() + layout.getLeading(); - } + lineText = astr.getIterator(); + } + + float width = w - 20; + if (lines == null || width != oldwidth) { + oldwidth = width; + + lines = new TextLayout[10]; + linecount = 0; + + LineBreakMeasurer measurer = new LineBreakMeasurer(lineText, frc); + + for (;;) { + TextLayout layout = measurer.nextLayout(width); + if (layout == null) { + break; + } + + // justify all but last line + if (linecount > 0) { + lines[linecount - 1] = lines[linecount - 1].getJustifiedLayout(width); + } + + if (linecount == lines.length) { + TextLayout[] nlines = new TextLayout[lines.length * 2]; + System.arraycopy(lines, 0, nlines, 0, lines.length); + lines = nlines; + } + + lines[linecount++] = layout; + } + } + + float basex = insets.left + 10; + basey += 10; + g2d.setColor(Color.black); + + for (int i = 0; i < linecount; ++i) { + TextLayout layout = lines[i]; + + basey += layout.getAscent(); + float adv = layout.getAdvance(); + float dx = layout.isLeftToRight() ? 0 : width - adv; + + layout.draw(g2d, basex + dx, basey); + + basey += layout.getDescent() + layout.getLeading(); + } + } } - } } diff --git a/test/jdk/java/awt/print/Dialog/DestinationTest.java b/test/jdk/java/awt/print/Dialog/DestinationTest.java index 8bb9403b566..933fba3042b 100644 --- a/test/jdk/java/awt/print/Dialog/DestinationTest.java +++ b/test/jdk/java/awt/print/Dialog/DestinationTest.java @@ -24,6 +24,7 @@ /** * @test * @bug 4846344 4851365 4851321 4851316 4863656 5046198 6293139 + * @key printer * @summary Confirm that cancelling the dialog will not prompt for file. * @run main/manual DestinationTest */ diff --git a/test/jdk/java/awt/print/Dialog/DialogCopies.java b/test/jdk/java/awt/print/Dialog/DialogCopies.java index 39d15461de8..1fb874a9d57 100644 --- a/test/jdk/java/awt/print/Dialog/DialogCopies.java +++ b/test/jdk/java/awt/print/Dialog/DialogCopies.java @@ -24,6 +24,7 @@ /* * @test * @bug 6357858 + * @key printer * @summary Job must reports the number of copies set in the dialog. * @run main/manual DialogCopies */ diff --git a/test/jdk/java/awt/print/Dialog/DialogOrient.java b/test/jdk/java/awt/print/Dialog/DialogOrient.java index c8009d742d7..6650ced64f4 100644 --- a/test/jdk/java/awt/print/Dialog/DialogOrient.java +++ b/test/jdk/java/awt/print/Dialog/DialogOrient.java @@ -24,6 +24,7 @@ /* @test @bug 6594374 + @key printer @summary Confirm that the orientation is as specified. @run main/manual DialogOrient */ diff --git a/test/jdk/java/awt/print/Dialog/DialogOwnerTest.java b/test/jdk/java/awt/print/Dialog/DialogOwnerTest.java index b4fbc7c3d37..dc4064466ca 100644 --- a/test/jdk/java/awt/print/Dialog/DialogOwnerTest.java +++ b/test/jdk/java/awt/print/Dialog/DialogOwnerTest.java @@ -23,6 +23,7 @@ /* @test @bug 8203796 + @key printer @run main/manual DialogOwnerTest @summary Test DialogOwner API */ diff --git a/test/jdk/java/awt/print/Dialog/DialogType.java b/test/jdk/java/awt/print/Dialog/DialogType.java index 00b07930cf0..472b89e44f2 100644 --- a/test/jdk/java/awt/print/Dialog/DialogType.java +++ b/test/jdk/java/awt/print/Dialog/DialogType.java @@ -24,6 +24,7 @@ /** * @test * @bug 6568874 + * @key printer * @summary Verify the native dialog works with attribute sets. * @run main/manual=yesno DialogType */ diff --git a/test/jdk/java/awt/print/Dialog/MediaInPrintable.java b/test/jdk/java/awt/print/Dialog/MediaInPrintable.java index a800f69c74d..cb74cb140f5 100644 --- a/test/jdk/java/awt/print/Dialog/MediaInPrintable.java +++ b/test/jdk/java/awt/print/Dialog/MediaInPrintable.java @@ -24,6 +24,7 @@ /** * @test * @bug 4869575 6361766 + * @key printer * @summary Setting orientation in the page format does not have any effect on the printout. To test 6361766, the application must exit. * @run main/manual MediaInPrintable */ diff --git a/test/jdk/java/awt/print/Dialog/PaperSizeError.java b/test/jdk/java/awt/print/Dialog/PaperSizeError.java index 970c7df2fcc..fea7bb85af8 100644 --- a/test/jdk/java/awt/print/Dialog/PaperSizeError.java +++ b/test/jdk/java/awt/print/Dialog/PaperSizeError.java @@ -24,6 +24,7 @@ /** * @test * @bug 6360339 + * @key printer * @summary Test for fp error in paper size calculations. * @run main/manual PaperSizeError */ diff --git a/test/jdk/java/awt/print/Dialog/PrintApplet.java b/test/jdk/java/awt/print/Dialog/PrintApplet.java index ecd9920571c..c8a3cd955fe 100644 --- a/test/jdk/java/awt/print/Dialog/PrintApplet.java +++ b/test/jdk/java/awt/print/Dialog/PrintApplet.java @@ -24,6 +24,7 @@ /* @test @bug 5024549 + @key printer @summary Pass if dialogs are modal. @run applet/manual PrintApplet.html */ diff --git a/test/jdk/java/awt/print/Dialog/PrintDialog.java b/test/jdk/java/awt/print/Dialog/PrintDialog.java index 870db01a985..c81ebfbc452 100644 --- a/test/jdk/java/awt/print/Dialog/PrintDialog.java +++ b/test/jdk/java/awt/print/Dialog/PrintDialog.java @@ -24,6 +24,7 @@ /* @test @bug 6342748 + @key printer @summary Pass if dialogs display correctly @run main/manual PrintDialog */ diff --git a/test/jdk/java/awt/print/Dialog/PrintDlgPageable.java b/test/jdk/java/awt/print/Dialog/PrintDlgPageable.java index d447874f72a..eadd3cf9cb6 100644 --- a/test/jdk/java/awt/print/Dialog/PrintDlgPageable.java +++ b/test/jdk/java/awt/print/Dialog/PrintDlgPageable.java @@ -24,6 +24,7 @@ /** * @test * @bug 4869502 4869539 + * @key printer * @summary Confirm that ToPage is populated for argument =2. Range is disabled for argument = 0. * @run main/manual PrintDlgPageable */ diff --git a/test/jdk/java/awt/print/Dialog/RestoreActiveWindowTest/RestoreActiveWindowTest.java b/test/jdk/java/awt/print/Dialog/RestoreActiveWindowTest/RestoreActiveWindowTest.java index 8d29dbb5849..2d2e00f2ed7 100644 --- a/test/jdk/java/awt/print/Dialog/RestoreActiveWindowTest/RestoreActiveWindowTest.java +++ b/test/jdk/java/awt/print/Dialog/RestoreActiveWindowTest/RestoreActiveWindowTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 6365992 6379599 8137137 + * @key printer * @summary REG: Showing and disposing a native print dialog makes the main * frame inactive, Win32 * @run main/manual RestoreActiveWindowTest diff --git a/test/jdk/java/awt/print/Headless/HeadlessPrinterJob.java b/test/jdk/java/awt/print/Headless/HeadlessPrinterJob.java index ff7a22ec8a3..143c898e32a 100644 --- a/test/jdk/java/awt/print/Headless/HeadlessPrinterJob.java +++ b/test/jdk/java/awt/print/Headless/HeadlessPrinterJob.java @@ -31,6 +31,7 @@ /* * @test + * @key printer * @summary Check that PrinterJob constructor and methods do not throw unexpected * exceptions in headless mode * @run main/othervm -Djava.awt.headless=true HeadlessPrinterJob diff --git a/test/jdk/java/awt/print/MissedFontFamilyName/PrintFontWithMissedFontFamilyTest.java b/test/jdk/java/awt/print/MissedFontFamilyName/PrintFontWithMissedFontFamilyTest.java index a6808282f37..af655f2d69e 100644 --- a/test/jdk/java/awt/print/MissedFontFamilyName/PrintFontWithMissedFontFamilyTest.java +++ b/test/jdk/java/awt/print/MissedFontFamilyName/PrintFontWithMissedFontFamilyTest.java @@ -25,6 +25,7 @@ /** * @test * @bug 8265761 + * @key printer * @requires (os.family == "windows") * @summary Font with missed font family name is not properly printed on Windows * @run main/othervm/manual PrintFontWithMissedFontFamilyTest diff --git a/test/jdk/java/awt/print/PageFormat/CustomPaper.java b/test/jdk/java/awt/print/PageFormat/CustomPaper.java index 3b8e83d5c1b..1976a20c01f 100644 --- a/test/jdk/java/awt/print/PageFormat/CustomPaper.java +++ b/test/jdk/java/awt/print/PageFormat/CustomPaper.java @@ -25,7 +25,7 @@ * @test * @bug 4355514 * @bug 4385157 - * @author Jennifer Godinez + * @key printer * @summary Prints a rectangle to show the imageable area of a * 12in x 14in custom paper size. * @run main/manual CustomPaper diff --git a/test/jdk/java/awt/print/PageFormat/ImageableAreaTest.java b/test/jdk/java/awt/print/PageFormat/ImageableAreaTest.java index 7bf37415e6e..07f458704a5 100644 --- a/test/jdk/java/awt/print/PageFormat/ImageableAreaTest.java +++ b/test/jdk/java/awt/print/PageFormat/ImageableAreaTest.java @@ -47,7 +47,7 @@ * @test * @bug 8044444 8081491 * @summary The output's 'Page-n' footer does not show completely - * @author Alexandr Scherbatiy + * @key printer * @run main/manual ImageableAreaTest */ public class ImageableAreaTest { diff --git a/test/jdk/java/awt/print/PageFormat/NullPaper.java b/test/jdk/java/awt/print/PageFormat/NullPaper.java index 0bae3aa9592..1a9000b6135 100644 --- a/test/jdk/java/awt/print/PageFormat/NullPaper.java +++ b/test/jdk/java/awt/print/PageFormat/NullPaper.java @@ -23,13 +23,11 @@ /* @test - @key headful @bug 4199506 @summary java.awt.print.PageFormat.setpaper(Paper paper) assertion test fails by not throwing NullPointerException when a null paper instance is passed as argument and this is specified in the doc. - @author rbi: area=PageFormat @run main NullPaper */ @@ -46,9 +44,6 @@ */ -import java.awt.*; -import java.awt.event.*; -import java.awt.geom.*; import java.awt.print.*; // This test is a "main" test as applets would need Runtime permission @@ -154,7 +149,6 @@ public static synchronized void setTimeoutTo( int seconds ) public static synchronized void pass() { System.out.println( "The test passed." ); - System.out.println( "The test is over, hit Ctl-C to stop Java VM" ); //first check if this is executing in main thread if ( mainThread == Thread.currentThread() ) { @@ -180,7 +174,6 @@ public static synchronized void fail() public static synchronized void fail( String whyFailed ) { System.out.println( "The test failed: " + whyFailed ); - System.out.println( "The test is over, hit Ctl-C to stop Java VM" ); //check if this called from main thread if ( mainThread == Thread.currentThread() ) { diff --git a/test/jdk/java/awt/print/PageFormat/Orient.java b/test/jdk/java/awt/print/PageFormat/Orient.java index ac3bb1ed840..ea6facaf570 100644 --- a/test/jdk/java/awt/print/PageFormat/Orient.java +++ b/test/jdk/java/awt/print/PageFormat/Orient.java @@ -27,7 +27,7 @@ @summary Confirm that the you get three pages of output, one each in portrait, landscape, and reverse landscape orientations. - @author rbi: area=PageFormat + @key printer @run main/manual Orient */ diff --git a/test/jdk/java/awt/print/PageFormat/PageFormatFromAttributes.java b/test/jdk/java/awt/print/PageFormat/PageFormatFromAttributes.java index e552db507de..b5ac83969f2 100644 --- a/test/jdk/java/awt/print/PageFormat/PageFormatFromAttributes.java +++ b/test/jdk/java/awt/print/PageFormat/PageFormatFromAttributes.java @@ -25,6 +25,7 @@ * @test * @bug 4500750 6848799 8028584 * @summary Tests creating page format from attributes + * @key printer * @run main PageFormatFromAttributes */ import java.awt.print.*; diff --git a/test/jdk/java/awt/print/PageFormat/PageSetupDialog.java b/test/jdk/java/awt/print/PageFormat/PageSetupDialog.java index 98da138ac22..5284793ef01 100644 --- a/test/jdk/java/awt/print/PageFormat/PageSetupDialog.java +++ b/test/jdk/java/awt/print/PageFormat/PageSetupDialog.java @@ -28,7 +28,7 @@ * @bug 6358747 * @bug 6574633 * @summary Page setup dialog settings - * @author prr + * @key printer * @run main/manual PageSetupDialog */ diff --git a/test/jdk/java/awt/print/PageFormat/PrintContentCutOffTest.java b/test/jdk/java/awt/print/PageFormat/PrintContentCutOffTest.java index d2362cdc815..df07741c907 100644 --- a/test/jdk/java/awt/print/PageFormat/PrintContentCutOffTest.java +++ b/test/jdk/java/awt/print/PageFormat/PrintContentCutOffTest.java @@ -24,6 +24,7 @@ /** * @test + * @key printer * @bug 8295737 * @summary macOS: Print content cut off when width > height with portrait orientation * @run main/othervm/manual PrintContentCutOffTest diff --git a/test/jdk/java/awt/print/PageFormat/ReverseLandscapeTest.java b/test/jdk/java/awt/print/PageFormat/ReverseLandscapeTest.java index 2c6544f4af1..850123aa9a8 100644 --- a/test/jdk/java/awt/print/PageFormat/ReverseLandscapeTest.java +++ b/test/jdk/java/awt/print/PageFormat/ReverseLandscapeTest.java @@ -23,7 +23,7 @@ /* * @test - * @key headful + * @key headful printer * @bug 4254954 * @summary PageFormat would fail on solaris when setting orientation */ diff --git a/test/jdk/java/awt/print/PageFormat/SetOrient.html b/test/jdk/java/awt/print/PageFormat/SetOrient.html index e500872ff05..422d64e4610 100644 --- a/test/jdk/java/awt/print/PageFormat/SetOrient.html +++ b/test/jdk/java/awt/print/PageFormat/SetOrient.html @@ -27,6 +27,7 @@ @bug 4186119 @summary Confirm that the clip and transform of the Graphics2D is affected by the landscape orientation of the PageFormat. + @key printer @run applet/manual=yesno SetOrient.html --> diff --git a/test/jdk/java/awt/print/PageFormat/SmallPaperPrinting.java b/test/jdk/java/awt/print/PageFormat/SmallPaperPrinting.java index e03e9f283b2..e936cd047de 100644 --- a/test/jdk/java/awt/print/PageFormat/SmallPaperPrinting.java +++ b/test/jdk/java/awt/print/PageFormat/SmallPaperPrinting.java @@ -21,43 +21,56 @@ * questions. */ - import java.awt.*; - import java.awt.print.*; +import java.awt.Graphics; +import java.awt.print.PageFormat; +import java.awt.print.Paper; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; - public class SmallPaperPrinting - { - public static void main(String args[]) - { - System.out.println("----------------- Instructions --------------------"); - System.out.println("Arguments: (none) - paper width=1, height=.0001"); - System.out.println(" 1 - paper width=.0001, height=1"); - System.out.println(" 2 - paper width=-1, height=1"); - System.out.println("A passing test should catch a PrinterException"); - System.out.println("and should display \"Print error: (exception msg)\"."); - System.out.println("---------------------------------------------------\n"); - PrinterJob job = PrinterJob.getPrinterJob(); - PageFormat format = job.defaultPage(); - Paper paper = format.getPaper(); +/* + * @test + * @key printer + * @run main/othervm SmallPaperPrinting + * @run main/othervm SmallPaperPrinting 1 + * @run main/othervm SmallPaperPrinting 2 + */ + +public class SmallPaperPrinting +{ + public static void main(String args[]) { + System.out.println("----------------- Instructions --------------------"); + System.out.println("Arguments: (none) - paper width=1, height=.0001"); + System.out.println(" 1 - paper width=.0001, height=1"); + System.out.println(" 2 - paper width=-1, height=1"); + System.out.println("A passing test should catch a PrinterException"); + System.out.println("and should display \"Print error: (exception msg)\"."); + System.out.println("---------------------------------------------------\n"); + PrinterJob job = PrinterJob.getPrinterJob(); + PageFormat format = job.defaultPage(); + Paper paper = format.getPaper(); - double w = 1, h = .0001; // Generates ArithmeticException: / by zero. - if(args.length > 0 && args[0].equals("1")) { - w = .0001; h = 1; } // Generates IllegalArgumentException. - else if(args.length > 0 && args[0].equals("2")) { - w = -1; h = 1; } // Generates NegativeArraySizeException. - paper.setSize(w, h); - paper.setImageableArea(0, 0, w, h); - format.setPaper(paper); - job.setPrintable( - new Printable() { - public int print(Graphics g, PageFormat page_format, int page) { - return NO_SUCH_PAGE; - } - }, format); + double w = 1, h = .0001; // Generates ArithmeticException: / by zero. + if (args.length > 0 && args[0].equals("1")) { + w = .0001; h = 1; + } // Generates IllegalArgumentException. + else if (args.length > 0 && args[0].equals("2")) { + w = -1; h = 1; + } // Generates NegativeArraySizeException. + paper.setSize(w, h); + paper.setImageableArea(0, 0, w, h); + format.setPaper(paper); + job.setPrintable( + new Printable() { + public int print(Graphics g, PageFormat page_format, int page) { + return NO_SUCH_PAGE; + } + }, format); - try { - job.print(); } - catch(PrinterException e) { - System.err.println("Print error:\n" + e.getMessage()); // Passing test! - } + try { + job.print(); + } catch (PrinterException e) { + System.err.println("Print error:\n" + e.getMessage()); // Passing test! } } +} diff --git a/test/jdk/java/awt/print/PageFormat/ValidateCustom.java b/test/jdk/java/awt/print/PageFormat/ValidateCustom.java index e15eebf9bc4..2521609ee4f 100644 --- a/test/jdk/java/awt/print/PageFormat/ValidateCustom.java +++ b/test/jdk/java/awt/print/PageFormat/ValidateCustom.java @@ -24,7 +24,7 @@ /* * @test * @bug 4414987 - * @author Jennifer Godinez + * @key printer * @summary Displays width & height of validated custom paper size * @run main/manual ValidateCustom */ diff --git a/test/jdk/java/awt/print/PageFormat/WrongPaperForBookPrintingTest.java b/test/jdk/java/awt/print/PageFormat/WrongPaperForBookPrintingTest.java index 5c4410e0ee4..1015fab4ed6 100644 --- a/test/jdk/java/awt/print/PageFormat/WrongPaperForBookPrintingTest.java +++ b/test/jdk/java/awt/print/PageFormat/WrongPaperForBookPrintingTest.java @@ -22,7 +22,7 @@ */ /* @test - @key headful + @key printer @bug 8201818 @summary Printing attributes break page size set via "java.awt.print.Book" object diff --git a/test/jdk/java/awt/print/PageFormat/WrongPaperPrintingTest.java b/test/jdk/java/awt/print/PageFormat/WrongPaperPrintingTest.java index 77b46031487..d96d4a4c336 100644 --- a/test/jdk/java/awt/print/PageFormat/WrongPaperPrintingTest.java +++ b/test/jdk/java/awt/print/PageFormat/WrongPaperPrintingTest.java @@ -23,6 +23,7 @@ /* @test @bug 8167102 8181659 + @key printer @summary PrintRequestAttributeSet breaks page size set using PageFormat @run main/manual WrongPaperPrintingTest */ diff --git a/test/jdk/java/awt/print/PathPrecisionScaleFactor/PathPrecisionScaleFactorShapeTest.java b/test/jdk/java/awt/print/PathPrecisionScaleFactor/PathPrecisionScaleFactorShapeTest.java index 3b90d1e2068..9a626eae364 100644 --- a/test/jdk/java/awt/print/PathPrecisionScaleFactor/PathPrecisionScaleFactorShapeTest.java +++ b/test/jdk/java/awt/print/PathPrecisionScaleFactor/PathPrecisionScaleFactorShapeTest.java @@ -25,6 +25,7 @@ /** * @test * @bug 8262470 + * @key printer * @requires (os.family == "windows") * @summary Check thay shapes are properly painted with the precision scale factor * @run main/othervm/manual PathPrecisionScaleFactorShapeTest diff --git a/test/jdk/java/awt/print/PathPrecisionScaleFactor/PathPrecisionScaleFactorTextTest.java b/test/jdk/java/awt/print/PathPrecisionScaleFactor/PathPrecisionScaleFactorTextTest.java index 9b20ab4748a..f959ec9ca7c 100644 --- a/test/jdk/java/awt/print/PathPrecisionScaleFactor/PathPrecisionScaleFactorTextTest.java +++ b/test/jdk/java/awt/print/PathPrecisionScaleFactor/PathPrecisionScaleFactorTextTest.java @@ -25,6 +25,7 @@ /** * @test * @bug 8262470 + * @key printer * @requires (os.family == "windows") * @summary Check that a GlyphVector outline is printed with good quility on low dpi printers * @run main/othervm/manual PathPrecisionScaleFactorTextTest diff --git a/test/jdk/java/awt/print/PrinterJob/BannerTest.java b/test/jdk/java/awt/print/PrinterJob/BannerTest.java index e061e240400..e98bfaaf8d6 100644 --- a/test/jdk/java/awt/print/PrinterJob/BannerTest.java +++ b/test/jdk/java/awt/print/PrinterJob/BannerTest.java @@ -23,6 +23,7 @@ /* * @test * @bug 6575247 8170579 + * @key printer * @summary Verifies if Banner page is printed * @requires os.family == "solaris" * @run main/manual BannerTest diff --git a/test/jdk/java/awt/print/PrinterJob/Cancel/PrinterJobCancel.java b/test/jdk/java/awt/print/PrinterJob/Cancel/PrinterJobCancel.java index 0ad27cb5a53..20197224f56 100644 --- a/test/jdk/java/awt/print/PrinterJob/Cancel/PrinterJobCancel.java +++ b/test/jdk/java/awt/print/PrinterJob/Cancel/PrinterJobCancel.java @@ -25,7 +25,7 @@ * @test * @bug 4245280 * @summary PrinterJob not cancelled when PrinterJob.cancel() is used - * @author prr + * @key printer * @run main/manual PrinterJobCancel */ diff --git a/test/jdk/java/awt/print/PrinterJob/Collate2DPrintingTest.java b/test/jdk/java/awt/print/PrinterJob/Collate2DPrintingTest.java index 8d08da6a4a5..754030c4e9e 100644 --- a/test/jdk/java/awt/print/PrinterJob/Collate2DPrintingTest.java +++ b/test/jdk/java/awt/print/PrinterJob/Collate2DPrintingTest.java @@ -25,6 +25,7 @@ * @test * @bug 6362683 8012381 * @summary Collation should work. + * @key printer * @run main/manual Collate2DPrintingTest */ import java.awt.*; diff --git a/test/jdk/java/awt/print/PrinterJob/CompareImageable.java b/test/jdk/java/awt/print/PrinterJob/CompareImageable.java index 79a78c3b5a8..aec27d09d93 100644 --- a/test/jdk/java/awt/print/PrinterJob/CompareImageable.java +++ b/test/jdk/java/awt/print/PrinterJob/CompareImageable.java @@ -24,6 +24,7 @@ /* @test @bug 4748055 + @key printer @summary PASS if the values are same in both cases (2 and 3) below. @run main/manual CompareImageable */ diff --git a/test/jdk/java/awt/print/PrinterJob/CustomFont/CustomFont.java b/test/jdk/java/awt/print/PrinterJob/CustomFont/CustomFont.java index 2b6c91fc053..e12b7fe1689 100644 --- a/test/jdk/java/awt/print/PrinterJob/CustomFont/CustomFont.java +++ b/test/jdk/java/awt/print/PrinterJob/CustomFont/CustomFont.java @@ -25,7 +25,7 @@ @test @bug 4386025 8231243 @summary fonts not in win32 font directory print incorrectly. - @author prr: area=PrinterJob + @key printer @run main/manual CustomFont */ import java.io.*; diff --git a/test/jdk/java/awt/print/PrinterJob/CustomPrintService/PrintDialog.java b/test/jdk/java/awt/print/PrinterJob/CustomPrintService/PrintDialog.java index d18ee86878d..cf37cf0cfa7 100644 --- a/test/jdk/java/awt/print/PrinterJob/CustomPrintService/PrintDialog.java +++ b/test/jdk/java/awt/print/PrinterJob/CustomPrintService/PrintDialog.java @@ -30,7 +30,6 @@ * @bug 6870661 * @summary Verify that no native dialog is opened for a custom PrintService * @run main/manual PrintDialog - * @author reinhapa */ public class PrintDialog { diff --git a/test/jdk/java/awt/print/PrinterJob/CustomPrintService/SetPrintServiceTest.java b/test/jdk/java/awt/print/PrinterJob/CustomPrintService/SetPrintServiceTest.java index 9c3ebe7d921..5a7fb526e9d 100644 --- a/test/jdk/java/awt/print/PrinterJob/CustomPrintService/SetPrintServiceTest.java +++ b/test/jdk/java/awt/print/PrinterJob/CustomPrintService/SetPrintServiceTest.java @@ -28,7 +28,6 @@ * @test * @bug 6870661 * @summary tests setPrintService() with a custom implementation - * @author reinhapa */ public class SetPrintServiceTest { diff --git a/test/jdk/java/awt/print/PrinterJob/DeviceScale.java b/test/jdk/java/awt/print/PrinterJob/DeviceScale.java index 7320eda70c9..008b5d2f0fa 100644 --- a/test/jdk/java/awt/print/PrinterJob/DeviceScale.java +++ b/test/jdk/java/awt/print/PrinterJob/DeviceScale.java @@ -21,7 +21,7 @@ * questions. */ -/* @test 1.2 02/05/15 +/* @test @bug 4810363 4924441 @key printer @run main DeviceScale diff --git a/test/jdk/java/awt/print/PrinterJob/DlgAttrsBug.java b/test/jdk/java/awt/print/PrinterJob/DlgAttrsBug.java index dc31ffda1fd..93fecd486a3 100644 --- a/test/jdk/java/awt/print/PrinterJob/DlgAttrsBug.java +++ b/test/jdk/java/awt/print/PrinterJob/DlgAttrsBug.java @@ -23,6 +23,7 @@ /* * @test * @bug 8061258 + * @key printer * @summary PrinterJob's native Print Dialog does not reflect * specified Copies or Page Ranges * @run main/manual DlgAttrsBug diff --git a/test/jdk/java/awt/print/PrinterJob/DrawImage.java b/test/jdk/java/awt/print/PrinterJob/DrawImage.java index 977dc946a92..2fcc710719c 100644 --- a/test/jdk/java/awt/print/PrinterJob/DrawImage.java +++ b/test/jdk/java/awt/print/PrinterJob/DrawImage.java @@ -24,8 +24,8 @@ /** * @test * @bug 4329866 + * @key printer * @summary Confirm that no printing exception is generated. - * @author jgodinez * @run main/manual DrawImage */ diff --git a/test/jdk/java/awt/print/PrinterJob/DrawStringMethods.java b/test/jdk/java/awt/print/PrinterJob/DrawStringMethods.java index 37bb3e045a5..f5417ebae4d 100644 --- a/test/jdk/java/awt/print/PrinterJob/DrawStringMethods.java +++ b/test/jdk/java/awt/print/PrinterJob/DrawStringMethods.java @@ -24,6 +24,7 @@ /** * @test * @bug 4185019 + * @key printer * @summary Confirm that all of the drawString methods on Graphics2D * work for printer graphics objects. * @run main/manual DrawStringMethods diff --git a/test/jdk/java/awt/print/PrinterJob/EmptyFill.java b/test/jdk/java/awt/print/PrinterJob/EmptyFill.java index ddf8ebb0150..3da1689bc3d 100644 --- a/test/jdk/java/awt/print/PrinterJob/EmptyFill.java +++ b/test/jdk/java/awt/print/PrinterJob/EmptyFill.java @@ -66,11 +66,11 @@ public static void main(String arg[]) throws Exception { } ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); StreamPrintService svc = spfs[0].getPrintService(baos); - - PrinterJob pj = PrinterJob.getPrinterJob(); if (svc == null) { - return; + throw new RuntimeException("Could not create postscript stream"); } + + PrinterJob pj = PrinterJob.getPrinterJob(); pj.setPrintService(svc); pj.setPrintable(new EmptyFill()); pj.print(); diff --git a/test/jdk/java/awt/print/PrinterJob/GetMediasTest.java b/test/jdk/java/awt/print/PrinterJob/GetMediasTest.java index c70d377c6ef..f4ff1643b00 100644 --- a/test/jdk/java/awt/print/PrinterJob/GetMediasTest.java +++ b/test/jdk/java/awt/print/PrinterJob/GetMediasTest.java @@ -24,6 +24,7 @@ /** * @test * @bug 6653384 + * @key printer * @summary No exception should be thrown. * @run main GetMediasTest */ diff --git a/test/jdk/java/awt/print/PrinterJob/ImagePrinting/ImageTypes.java b/test/jdk/java/awt/print/PrinterJob/ImagePrinting/ImageTypes.java index c33dc0f6718..af655b75d36 100644 --- a/test/jdk/java/awt/print/PrinterJob/ImagePrinting/ImageTypes.java +++ b/test/jdk/java/awt/print/PrinterJob/ImagePrinting/ImageTypes.java @@ -25,7 +25,7 @@ * @test * @bug 4521945 7006865 * @summary Test printing images of different types. - * @author prr + * @key printer * @run main/manual ImageTypes */ diff --git a/test/jdk/java/awt/print/PrinterJob/ImagePrinting/PrintARGBImage.java b/test/jdk/java/awt/print/PrinterJob/ImagePrinting/PrintARGBImage.java index 4bef1cce0f5..e16dc17c24f 100644 --- a/test/jdk/java/awt/print/PrinterJob/ImagePrinting/PrintARGBImage.java +++ b/test/jdk/java/awt/print/PrinterJob/ImagePrinting/PrintARGBImage.java @@ -34,6 +34,7 @@ /* * @test * @bug 6581756 + * @key printer * @library ../../../regtesthelpers * @build PassFailJFrame * @summary Test printing of images which need to have src area clipped diff --git a/test/jdk/java/awt/print/PrinterJob/InitToBlack.java b/test/jdk/java/awt/print/PrinterJob/InitToBlack.java index a4d7dd0a958..7ca5846fd47 100644 --- a/test/jdk/java/awt/print/PrinterJob/InitToBlack.java +++ b/test/jdk/java/awt/print/PrinterJob/InitToBlack.java @@ -24,6 +24,7 @@ /** * @test * @bug 4184565 + * @key printer * @summary Confirm that the default foreground color on a printer * graphics object is black so that rendering will appear * without having to execute setColor first. diff --git a/test/jdk/java/awt/print/PrinterJob/InvalidPage.java b/test/jdk/java/awt/print/PrinterJob/InvalidPage.java index f84bd2c0d78..fd013032052 100644 --- a/test/jdk/java/awt/print/PrinterJob/InvalidPage.java +++ b/test/jdk/java/awt/print/PrinterJob/InvalidPage.java @@ -25,7 +25,7 @@ * @test InvalidPage.java * @bug 4671634 6506286 * @summary Invalid page format can crash win32 JRE - * @author prr + * @key printer * @run main/manual InvalidPage */ diff --git a/test/jdk/java/awt/print/PrinterJob/JobName/PrinterJobName.java b/test/jdk/java/awt/print/PrinterJob/JobName/PrinterJobName.java index a6c65445912..f1b99487788 100644 --- a/test/jdk/java/awt/print/PrinterJob/JobName/PrinterJobName.java +++ b/test/jdk/java/awt/print/PrinterJob/JobName/PrinterJobName.java @@ -25,7 +25,7 @@ * @test * @bug 4205601 * @summary setJobName should be used by PrinterJob - * @author prr + * @key printer * @run main/manual PrinterJobName */ diff --git a/test/jdk/java/awt/print/PrinterJob/LandscapeStackOverflow.java b/test/jdk/java/awt/print/PrinterJob/LandscapeStackOverflow.java index fc65dc9ddab..398939d125d 100644 --- a/test/jdk/java/awt/print/PrinterJob/LandscapeStackOverflow.java +++ b/test/jdk/java/awt/print/PrinterJob/LandscapeStackOverflow.java @@ -22,7 +22,7 @@ */ /* * @test - * @key headful printer + * @key printer * @bug 6842011 8158758 * @summary Test if StackOverflowError occurs during printing landscape with * scale and transform. diff --git a/test/jdk/java/awt/print/PrinterJob/Legal/PrintTest.java b/test/jdk/java/awt/print/PrinterJob/Legal/PrintTest.java index b4c708e2785..f5ee1c4d65a 100644 --- a/test/jdk/java/awt/print/PrinterJob/Legal/PrintTest.java +++ b/test/jdk/java/awt/print/PrinterJob/Legal/PrintTest.java @@ -24,6 +24,7 @@ /** * @test * @bug 4886069 8023045 + * @key printer * @summary Confirm that printer recognizes the Legal selection either by * prompting the user to put Legal paper or automatically selecting * the tray containing Legal Paper. The printout image should not diff --git a/test/jdk/java/awt/print/PrinterJob/LinearGradientPrintingTest.java b/test/jdk/java/awt/print/PrinterJob/LinearGradientPrintingTest.java index ab1ab17aa7f..456b77614a3 100644 --- a/test/jdk/java/awt/print/PrinterJob/LinearGradientPrintingTest.java +++ b/test/jdk/java/awt/print/PrinterJob/LinearGradientPrintingTest.java @@ -24,6 +24,7 @@ * @test * @bug 8162796 * @summary Verifies if LinearGradientPaint is printed in osx + * @key printer * @run main/manual LinearGradientPrintingTest */ import java.awt.BorderLayout; diff --git a/test/jdk/java/awt/print/PrinterJob/MultiMonPrintDlgTest.java b/test/jdk/java/awt/print/PrinterJob/MultiMonPrintDlgTest.java index 4086f663a5c..9da6e64fedc 100644 --- a/test/jdk/java/awt/print/PrinterJob/MultiMonPrintDlgTest.java +++ b/test/jdk/java/awt/print/PrinterJob/MultiMonPrintDlgTest.java @@ -37,6 +37,7 @@ /** * @test * @bug 8138749 + * @key printer multimon * @summary PrinterJob.printDialog() does not support multi-mon, * always displayed on primary * @run main/manual MultiMonPrintDlgTest diff --git a/test/jdk/java/awt/print/PrinterJob/MultiThread/MultiThreadTest.java b/test/jdk/java/awt/print/PrinterJob/MultiThread/MultiThreadTest.java index 8282a052ee1..609cc6f988b 100644 --- a/test/jdk/java/awt/print/PrinterJob/MultiThread/MultiThreadTest.java +++ b/test/jdk/java/awt/print/PrinterJob/MultiThread/MultiThreadTest.java @@ -24,6 +24,7 @@ /** * @test * @bug 4922036 + * @key printer * @summary Confirm that no Exception is thrown and 2 identical output is produced. * @run main/manual MultiThreadTest */ diff --git a/test/jdk/java/awt/print/PrinterJob/NumCopies.java b/test/jdk/java/awt/print/PrinterJob/NumCopies.java index c851e2403d0..119bcab6f7a 100644 --- a/test/jdk/java/awt/print/PrinterJob/NumCopies.java +++ b/test/jdk/java/awt/print/PrinterJob/NumCopies.java @@ -25,7 +25,7 @@ * @test * @bug 4258003 * @summary Checks the right number of copies are printed - * @author prr + * @key printer * @run main/manual NumCopies */ diff --git a/test/jdk/java/awt/print/PrinterJob/PageDialogMarginTest.java b/test/jdk/java/awt/print/PrinterJob/PageDialogMarginTest.java index de47e70f639..1931de988d1 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageDialogMarginTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PageDialogMarginTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 6801613 + * @key printer * @summary Verifies if cross-platform pageDialog and printDialog top margin * entry is working * @run main/manual PageDialogMarginTest diff --git a/test/jdk/java/awt/print/PrinterJob/PageDialogMarginValidation.java b/test/jdk/java/awt/print/PrinterJob/PageDialogMarginValidation.java index d71f84f1879..674266e7fc8 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageDialogMarginValidation.java +++ b/test/jdk/java/awt/print/PrinterJob/PageDialogMarginValidation.java @@ -23,6 +23,7 @@ /* * @test * @bug 6509729 + * @key printer * @summary Verifies pageDialog margin validation is correct * @run main/manual PageDialogMarginValidation */ diff --git a/test/jdk/java/awt/print/PrinterJob/PageDialogTest.java b/test/jdk/java/awt/print/PrinterJob/PageDialogTest.java index 8a8f9839ddf..eea118733de 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageDialogTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PageDialogTest.java @@ -24,6 +24,7 @@ /* @test @bug 6302514 + @key printer @run main/manual PageDialogTest @summary A toolkit modal dialog should not be blocked by Page/Print dialog. */ diff --git a/test/jdk/java/awt/print/PrinterJob/PageDlgApp.java b/test/jdk/java/awt/print/PrinterJob/PageDlgApp.java index e07e8ffd6cf..96d5f64486d 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageDlgApp.java +++ b/test/jdk/java/awt/print/PrinterJob/PageDlgApp.java @@ -31,6 +31,7 @@ /** * @test * @bug 8067059 + * @key printer * @run main/manual PageDlgApp * @summary Test if cancelling dialog returns null when * PrinterJob.pageDialog() with DialogSelectionType.NATIVE is called diff --git a/test/jdk/java/awt/print/PrinterJob/PageDlgPrnButton.java b/test/jdk/java/awt/print/PrinterJob/PageDlgPrnButton.java index 45a1c71a44a..2ede9c53dc4 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageDlgPrnButton.java +++ b/test/jdk/java/awt/print/PrinterJob/PageDlgPrnButton.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,208 +21,93 @@ * questions. */ -/** - * @test - * @bug 4956397 - * @run main/manual PageDlgPrnButton - */ - -import java.awt.print.PrinterJob; -import java.awt.print.PageFormat; -import java.awt.print.Printable; -import java.awt.print.PrinterException; - import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; -import java.awt.* ; - -public class PageDlgPrnButton implements Printable -{ - public static void main ( String args[] ) { +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; - String[] instructions = - {"For non-windows OS, this test PASSes.", - "You must have at least 2 printers available to perform this test.", - "This test brings up a native Windows page dialog.", - "Click on the Printer... button and change the selected printer. ", - "Test passes if the printout comes from the new selected printer.", - }; +import jtreg.SkippedException; - Sysout.createDialog( ); - Sysout.printInstructions( instructions ); +/* + * @test + * @bug 4956397 + * @key printer + * @requires os.family=="windows" + * @library /test/lib /java/awt/regtesthelpers + * @build PassFailJFrame jtreg.SkippedException + * @run main/manual PageDlgPrnButton + */ +public class PageDlgPrnButton implements Printable { + private static final String INSTRUCTIONS = + "This test brings up a native Windows page dialog.\n" + + "Click on the Printer... button and change the selected printer. \n" + + "Test passes if the printout comes from the new selected printer."; + + public static void main(String[] args) throws Exception { + final int serviceCount = PrinterJob.lookupPrintServices().length; + if (serviceCount == 0) { + throw new RuntimeException("Printer not configured or available."); + } + if (serviceCount < 2) { + throw new SkippedException("The test requires at least 2 printers."); + } - PageDlgPrnButton pdpb = new PageDlgPrnButton() ; - } + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(45) + .build(); - public PageDlgPrnButton() - { - try - { - pageDialogExample(); - } - catch(Exception e) - {e.printStackTrace(System.err);} + pageDialogExample(); + passFailJFrame.awaitAndCheck(); } - // This example just displays the page dialog - you cannot change // the printer (press the "Printer..." button and choose one if you like). - public void pageDialogExample() throws PrinterException - { + public static void pageDialogExample() throws PrinterException { PrinterJob job = PrinterJob.getPrinterJob(); PageFormat originalPageFormat = job.defaultPage(); PageFormat pageFormat = job.pageDialog(originalPageFormat); - if(originalPageFormat == pageFormat) return; - - job.setPrintable(this,pageFormat); - job.print(); + job.setPrintable(new PageDlgPrnButton(), pageFormat); + if (job.printDialog()) { + job.print(); + } } - - - public int print(Graphics g, PageFormat pageFormat, int pageIndex) - { + @Override + public int print(Graphics g, PageFormat pageFormat, int pageIndex) { final int boxWidth = 100; final int boxHeight = 100; - final Rectangle rect = new Rectangle(0,0,boxWidth,boxHeight); + final Rectangle rect = new Rectangle(0, 0, boxWidth, boxHeight); final double pageH = pageFormat.getImageableHeight(); final double pageW = pageFormat.getImageableWidth(); + final Graphics2D g2d = (Graphics2D) g; - if (pageIndex > 0) return (NO_SUCH_PAGE); - - final Graphics2D g2d = (Graphics2D)g; + if (pageIndex > 0) { + return NO_SUCH_PAGE; + } // Move the (x,y) origin to account for the left-hand and top margins g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); // Draw the page bounding box - g2d.drawRect(0,0,(int)pageW,(int)pageH); + g2d.drawRect(0, 0, (int) pageW, (int) pageH); // Select the smaller scaling factor so that the figure // fits on the page in both dimensions - final double scale = Math.min( (pageW/boxWidth), (pageH/boxHeight) ); + final double scale = Math.min((pageW / boxWidth), (pageH / boxHeight)); - if(scale < 1.0) g2d.scale(scale, scale); + if (scale < 1.0) { + g2d.scale(scale, scale); + } // Paint the scaled component on the printer g2d.fillRect(rect.x, rect.y, rect.width, rect.height); - return(PAGE_EXISTS); + return PAGE_EXISTS; } } - -class Sysout { - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - show(); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - } - - }// TestDialog class diff --git a/test/jdk/java/awt/print/PrinterJob/PageDlgStackOverflowTest.java b/test/jdk/java/awt/print/PrinterJob/PageDlgStackOverflowTest.java index ffe695d6f48..048b81f273d 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageDlgStackOverflowTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PageDlgStackOverflowTest.java @@ -28,6 +28,7 @@ /** * @test * @bug 8039412 + * @key printer * @run main/manual PageDlgStackOverflowTest * @summary Calling pageDialog() after printDialog with * DialogTypeSelection.NATIVE should not result in StackOverflowError diff --git a/test/jdk/java/awt/print/PrinterJob/PageFormatChange.java b/test/jdk/java/awt/print/PrinterJob/PageFormatChange.java index 2515e11e9ec..10aaaea89f1 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageFormatChange.java +++ b/test/jdk/java/awt/print/PrinterJob/PageFormatChange.java @@ -24,6 +24,7 @@ /** * @test * @bug 6359283 + * @key printer * @summary pagedialog needs to update based on change of printer. * @run main/manual PageFormatChange */ diff --git a/test/jdk/java/awt/print/PrinterJob/PageRanges.java b/test/jdk/java/awt/print/PrinterJob/PageRanges.java index 9bfd79eacce..accde99ae95 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageRanges.java +++ b/test/jdk/java/awt/print/PrinterJob/PageRanges.java @@ -24,6 +24,7 @@ /** * @test * @bug 6575331 + * @key printer * @summary The specified pages should be printed. * @run main/manual=yesno PageRanges */ diff --git a/test/jdk/java/awt/print/PrinterJob/PolylinePrintingTest.java b/test/jdk/java/awt/print/PrinterJob/PolylinePrintingTest.java index 14a04d5542f..7d8568c01f9 100644 --- a/test/jdk/java/awt/print/PrinterJob/PolylinePrintingTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PolylinePrintingTest.java @@ -23,6 +23,7 @@ /** * @bug 8041902 + * @key printer * @summary Test printing of wide poly lines. * @run main/manual=yesno PolylinePrintingTest */ diff --git a/test/jdk/java/awt/print/PrinterJob/PrintAWTImage.java b/test/jdk/java/awt/print/PrinterJob/PrintAWTImage.java index 2612ca6bdad..2397931b4fc 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintAWTImage.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintAWTImage.java @@ -23,6 +23,7 @@ /** * @test * @bug 4257262 6708509 + * @key printer * @summary Image should be sent to printer. * @run main/manual PrintAWTImage */ diff --git a/test/jdk/java/awt/print/PrinterJob/PrintAllFonts.java b/test/jdk/java/awt/print/PrinterJob/PrintAllFonts.java index 59ebf21ee5b..0c9f8afb769 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintAllFonts.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintAllFonts.java @@ -23,9 +23,11 @@ /** * + * test * @bug 4884389 7183516 + * @key printer * @summary Font specified with face name loses style on printing - * @run main/manual PrintRotatedText + * @run main/manual PrintAllFonts */ import java.awt.*; diff --git a/test/jdk/java/awt/print/PrinterJob/PrintAttributeUpdateTest.java b/test/jdk/java/awt/print/PrinterJob/PrintAttributeUpdateTest.java index 1b69e0b8b36..fd92f5deda8 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintAttributeUpdateTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintAttributeUpdateTest.java @@ -24,6 +24,7 @@ /* @test @bug 8042713 8170578 + @key printer @summary Print Dialog does not update attribute set with page range @run main/manual PrintAttributeUpdateTest */ diff --git a/test/jdk/java/awt/print/PrinterJob/PrintBadImage.java b/test/jdk/java/awt/print/PrinterJob/PrintBadImage.java index ad3b3fd5d83..48e4503db70 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintBadImage.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintBadImage.java @@ -25,7 +25,7 @@ * @test * @bug 4398853 * @summary Printing shouldn't hang on bad images - * @author prr + * @key printer * @run main/manual PrintBadImage */ diff --git a/test/jdk/java/awt/print/PrinterJob/PrintCompoundString.java b/test/jdk/java/awt/print/PrinterJob/PrintCompoundString.java index 82560d8964b..14443d76ae8 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintCompoundString.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintCompoundString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,226 +21,87 @@ * questions. */ -/** +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JOptionPane; + +/* * @test * @bug 4396835 * @summary Compound font string not printing. - * @author prr + * @key printer + * @library /java/awt/regtesthelpers + * @build PassFailJFrame * @run main/manual PrintCompoundString */ +public class PrintCompoundString implements Printable { + private static final String STR = "Test string compound printing \u2203\u2200\u2211"; + + private static final String INSTRUCTIONS = + "This test should print following text\n\n" + + STR +"\n\n" + + "If an exception is thrown, or the page doesn't print properly\n" + + "then the test fails"; + + public static void main(String[] args) throws Exception { + if (PrinterJob.lookupPrintServices().length == 0) { + throw new RuntimeException("Printer not configured or available."); + } + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .splitUI(PrintCompoundString::createTestUI) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(45) + .build() + .awaitAndCheck(); + } - -import java.awt.*; -import java.awt.event.*; -import java.awt.print.*; -import java.text.*; - -public class PrintCompoundString extends Frame implements ActionListener { - - private TextCanvas c; - - public static void main(String args[]) { - - String[] instructions = - { - "You must have a printer available to perform this test", - "This test should print a page which contains the same", - "text message as in the test window on the screen", - "You should also monitor the command line to see if any exceptions", - "were thrown", - "If an exception is thrown, or the page doesn't print properly", - "then the test fails", - }; - Sysout.createDialog( ); - Sysout.printInstructions( instructions ); - - PrintCompoundString f = new PrintCompoundString(); - f.show(); - } - - public PrintCompoundString() { - super("JDK 1.2 drawString Printing"); - - c = new TextCanvas(); - add("Center", c); - - Button printButton = new Button("Print"); - printButton.addActionListener(this); - add("South", printButton); - - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - System.exit(0); + private static JComponent createTestUI() { + JButton b = new JButton("Print"); + b.addActionListener((ae) -> { + try { + PrinterJob job = PrinterJob.getPrinterJob(); + job.setPrintable(new PrintCompoundString()); + if (job.printDialog()) { + job.print(); + } + } catch (PrinterException ex) { + ex.printStackTrace(); + String msg = "PrinterException: " + ex.getMessage(); + JOptionPane.showMessageDialog(b, msg, "Error occurred", + JOptionPane.ERROR_MESSAGE); + PassFailJFrame.forceFail(msg); } - }); - - pack(); - } - - public void actionPerformed(ActionEvent e) { - - PrinterJob pj = PrinterJob.getPrinterJob(); - - if (pj != null && pj.printDialog()) { - - pj.setPrintable(c); - try { - pj.print(); - } catch (PrinterException pe) { - } finally { - System.err.println("PRINT RETURNED"); - } - } - } - - class TextCanvas extends Panel implements Printable { - - String nullStr = null; - String emptyStr = new String(); - AttributedString nullAttStr = null; - AttributedString emptyAttStr = new AttributedString(emptyStr); - AttributedCharacterIterator nullIterator = null; - AttributedCharacterIterator emptyIterator = emptyAttStr.getIterator(); - - public int print(Graphics g, PageFormat pgFmt, int pgIndex) { - - if (pgIndex > 0) - return Printable.NO_SUCH_PAGE; - - Graphics2D g2d = (Graphics2D)g; - g2d.translate(pgFmt.getImageableX(), pgFmt.getImageableY()); - - paint(g); - - return Printable.PAGE_EXISTS; + }); + + Box main = Box.createHorizontalBox(); + main.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); + main.add(Box.createHorizontalGlue()); + main.add(b); + main.add(Box.createHorizontalGlue()); + return main; } - public void paint(Graphics g1) { - Graphics2D g = (Graphics2D)g1; - - String str = "Test string compound printing \u2203\u2200\u2211"; - g.drawString(str, 20, 40); + @Override + public int print(Graphics g, PageFormat pgFmt, int pgIndex) { + if (pgIndex > 0) { + return Printable.NO_SUCH_PAGE; + } - } + Graphics2D g2d = (Graphics2D) g; + g2d.translate(pgFmt.getImageableX(), pgFmt.getImageableY()); + g2d.drawString(STR, 20, 40); - public Dimension getPreferredSize() { - return new Dimension(450, 250); + return Printable.PAGE_EXISTS; } - } - } - -class Sysout - { - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - - }// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - show(); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - } - - }// TestDialog class diff --git a/test/jdk/java/awt/print/PrinterJob/PrintDialog.java b/test/jdk/java/awt/print/PrinterJob/PrintDialog.java index 9ab5d63f641..fa9569e1aa7 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintDialog.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintDialog.java @@ -25,7 +25,7 @@ @test PrintDialog.java @bug 4257903 @summary Confirm that the you see the print dialog. - @author prr: area=PrinterJob + @key printer @run main/manual PrintDialog */ diff --git a/test/jdk/java/awt/print/PrinterJob/PrintDialogCancel.java b/test/jdk/java/awt/print/PrinterJob/PrintDialogCancel.java index 4fe3d29fe5b..b2d3d3a2230 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintDialogCancel.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintDialogCancel.java @@ -25,7 +25,7 @@ @test @bug 4398231 @summary Confirm that the print dialog returns false when cancelled. - @author prr: area=PrinterJob + @key printer @run main/manual PrintDialogCancel */ diff --git a/test/jdk/java/awt/print/PrinterJob/PrintDlgPageable.java b/test/jdk/java/awt/print/PrinterJob/PrintDlgPageable.java index f6a74f9f965..6d1d8bcf6df 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintDlgPageable.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintDlgPageable.java @@ -23,6 +23,7 @@ /* * @test * @bug 4885375 + * @key printer * @summary Verifies if PageRanges To Field is populated based on Pageable * for COMMON print dialog * @run main/manual PrintDlgPageable diff --git a/test/jdk/java/awt/print/PrinterJob/PrintDlgSelectionAttribTest.java b/test/jdk/java/awt/print/PrinterJob/PrintDlgSelectionAttribTest.java index 98585478626..65adee3f4f9 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintDlgSelectionAttribTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintDlgSelectionAttribTest.java @@ -23,6 +23,7 @@ /* * @test * @bug 6529030 8159134 + * @key printer * @summary Verifies if Java Printing: Selection radiobutton gets enabled. * @requires (os.family == "windows") * @run main/manual PrintDlgSelectionAttribTest diff --git a/test/jdk/java/awt/print/PrinterJob/PrintFontStyle.java b/test/jdk/java/awt/print/PrinterJob/PrintFontStyle.java index 3d67246eac2..f9997d443a2 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintFontStyle.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintFontStyle.java @@ -21,6 +21,13 @@ * questions. */ +/* + * Not enabled as a test. Needs some work. + * test + * @key printer + * @run main/manual PrintFontStyle + */ + import java.awt.*; import java.awt.print.*; import java.awt.GraphicsEnvironment; diff --git a/test/jdk/java/awt/print/PrinterJob/PrintGlyphVectorTest.java b/test/jdk/java/awt/print/PrinterJob/PrintGlyphVectorTest.java index bd921b5162d..696cf1b7445 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintGlyphVectorTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintGlyphVectorTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 8029204 + * @key printer * @library ../../regtesthelpers * @build PassFailJFrame * @summary Tests GlyphVector is printed in the correct location diff --git a/test/jdk/java/awt/print/PrinterJob/PrintImage.java b/test/jdk/java/awt/print/PrinterJob/PrintImage.java index 7f632bfa94c..a3fe19ff5cf 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintImage.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,276 +21,152 @@ * questions. */ -/** - * @test %I %W +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; + +/* + * @test * @bug 4298489 * @summary Confirm that output is same as screen. - * @author jgodinez + * @key printer + * @requires os.family=="windows" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame * @run main/manual PrintImage */ -import java.awt.*; -import java.awt.print.*; -import java.awt.event.*; - public class PrintImage extends Frame implements ActionListener { - - private PrintImageCanvas printImageCanvas; - - private MenuItem print1Menu = new MenuItem("PrintTest1"); - private MenuItem print2Menu = new MenuItem("PrintTest2"); - private MenuItem exitMenu = new MenuItem("Exit"); - - public static void main(String[] argv) { - String[] instructions = - { "You must have a printer available to perform this test,", - "prefererably Canon LaserShot A309GII.", - "Printing must be done in Win 98 Japanese 2nd Edition.", - "", - "Passing test : Output of text image for PrintTest1 and PrintTest2 should be same as that on the screen.", - }; - - Sysout.createDialog( ); - Sysout.printInstructions( instructions ); - - new PrintImage(); - } - - public PrintImage() { - super("PrintImage"); - initPrintImage(); - } - - public void initPrintImage() { - - printImageCanvas = new PrintImageCanvas(this); - - initMenu(); - - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent ev) { - dispose(); - } - public void windowClosed(WindowEvent ev) { - System.exit(0); - } - }); - - setLayout(new BorderLayout()); - add(printImageCanvas, BorderLayout.CENTER); - pack(); - - setSize(500,500); - setVisible(true); + private final PrintImageCanvas printImageCanvas = new PrintImageCanvas(); + private final MenuItem print1Menu = new MenuItem("PrintTest1"); + private final MenuItem print2Menu = new MenuItem("PrintTest2"); + private static final String INSTRUCTIONS = + "Select PrintTest1 in the File menu.\n" + + "Print Dialog will appear.\n" + + "Click OK to start the first print job.\n" + + "\n" + + "Select PrintTest2 in the File menu.\n" + + "Page Setup Dialog will appear.\n" + + "Click OK.\n" + + "Print Dialog will appear.\n" + + "Click OK to start the second print job.\n" + + "\n" + + "The text in the printouts for PrintTest1 and PrintTest2 should be\n" + + "same as that on the screen.\n" + + "Press Pass if they are, otherwise press Fail."; + + public static void main(String[] argv) throws Exception { + if (PrinterJob.lookupPrintServices().length == 0) { + throw new RuntimeException("Printer not configured or available."); } - private void initMenu() { - MenuBar mb = new MenuBar(); - Menu me = new Menu("File"); - me.add(print1Menu); - me.add(print2Menu); - me.add("-"); - me.add(exitMenu); - mb.add(me); - this.setMenuBar(mb); - - print1Menu.addActionListener(this); - print2Menu.addActionListener(this); - exitMenu.addActionListener(this); - } + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .testUI(PrintImage::new) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(45) + .build() + .awaitAndCheck(); + } - public void actionPerformed(ActionEvent e) { - Object target = e.getSource(); - if( target.equals(print1Menu) ) { - printMain1(); - } - else if( target.equals(print2Menu) ) { - printMain2(); - } - else if( target.equals(exitMenu) ) { - dispose(); - } - } + public PrintImage() { + super("PrintImage"); + initPrintImage(); + } - private void printMain1(){ + public void initPrintImage() { + initMenu(); + setLayout(new BorderLayout()); + add(printImageCanvas, BorderLayout.CENTER); + setSize(500, 300); + } - PrinterJob printerJob = PrinterJob.getPrinterJob(); - PageFormat pageFormat = printerJob.defaultPage(); + private void initMenu() { + MenuBar mb = new MenuBar(); + Menu me = new Menu("File"); + me.add(print1Menu); + me.add(print2Menu); + mb.add(me); + setMenuBar(mb); - printerJob.setPrintable((Printable)printImageCanvas, pageFormat); + print1Menu.addActionListener(this); + print2Menu.addActionListener(this); + } - if(printerJob.printDialog()){ - try { - printerJob.print(); - } - catch(PrinterException p){ - } - } - else - printerJob.cancel(); + public void actionPerformed(ActionEvent e) { + Object target = e.getSource(); + if (target.equals(print1Menu)) { + printMain1(); + } else if (target.equals(print2Menu)) { + printMain2(); } + } - private void printMain2(){ - - PrinterJob printerJob = PrinterJob.getPrinterJob(); - PageFormat pageFormat = printerJob.pageDialog(printerJob.defaultPage()); - - printerJob.setPrintable((Printable)printImageCanvas, pageFormat); - - if(printerJob.printDialog()){ - try { - printerJob.print(); - } - catch(PrinterException p){ - } - } - else - printerJob.cancel(); + private void printMain1() { + PrinterJob printerJob = PrinterJob.getPrinterJob(); + PageFormat pageFormat = printerJob.defaultPage(); + + printerJob.setPrintable(printImageCanvas, pageFormat); + + if (printerJob.printDialog()) { + try { + printerJob.print(); + } catch (PrinterException e) { + PassFailJFrame.forceFail("Print Failed"); + e.printStackTrace(); + } + } else { + printerJob.cancel(); } + } -} - -class PrintImageCanvas extends Canvas implements Printable { - - private PrintImage pdsFrame; - - public PrintImageCanvas(PrintImage pds) { - pdsFrame = pds; + private void printMain2() { + PrinterJob printerJob = PrinterJob.getPrinterJob(); + PageFormat pageFormat = printerJob.pageDialog(printerJob.defaultPage()); + + printerJob.setPrintable(printImageCanvas, pageFormat); + + if (printerJob.printDialog()) { + try { + printerJob.print(); + } catch (PrinterException e) { + PassFailJFrame.forceFail("Print Failed"); + e.printStackTrace(); + } + } else { + printerJob.cancel(); } + } + private static class PrintImageCanvas extends Canvas implements Printable { + @Override public void paint(Graphics g) { - Font drawFont = new Font("MS Mincho",Font.ITALIC,50); - g.setFont(drawFont); - g.drawString("PrintSample!",100,150); + Font drawFont = new Font("MS Mincho", Font.ITALIC, 50); + g.setFont(drawFont); + g.setColor(new Color(0, 0, 0, 200)); + g.drawString("PrintSample!", 100, 150); } + @Override public int print(Graphics g, PageFormat pf, int pi) throws PrinterException { - - if(pi>=1) - return NO_SUCH_PAGE; - else{ - Graphics2D g2 = (Graphics2D)g; - g.setColor(new Color(0,0,0,200)); - - Font drawFont = new Font("MS Mincho",Font.ITALIC,50); - g.setFont(drawFont); - g.drawString("PrintSample!",100,150); - return PAGE_EXISTS; - } + if (pi > 0) { + return NO_SUCH_PAGE; + } + paint(g); + return PAGE_EXISTS; } -} - - -class Sysout { - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - show(); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); } +} - }// TestDialog class diff --git a/test/jdk/java/awt/print/PrinterJob/PrintLatinCJKTest.java b/test/jdk/java/awt/print/PrinterJob/PrintLatinCJKTest.java index f6221aa5706..5ffb34540ce 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintLatinCJKTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintLatinCJKTest.java @@ -27,6 +27,7 @@ * @library ../../regtesthelpers * @build PassFailJFrame * @summary JDK7 Printing: CJK and Latin Text in string overlap + * @key printer * @run main/manual PrintLatinCJKTest */ diff --git a/test/jdk/java/awt/print/PrinterJob/PrintNullString.java b/test/jdk/java/awt/print/PrinterJob/PrintNullString.java index 7e3101c6b30..e4323b232a7 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintNullString.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintNullString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,308 +21,164 @@ * questions. */ -/** +import java.awt.Button; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; + +import javax.swing.JOptionPane; + +/* * @test * @bug 4223328 * @summary Printer graphics must behave the same as screen graphics - * @author prr + * @key printer + * @library /java/awt/regtesthelpers + * @build PassFailJFrame * @run main/manual PrintNullString */ - - -import java.awt.*; -import java.awt.event.*; -import java.awt.print.*; -import java.text.*; - -public class PrintNullString extends Frame implements ActionListener { - - private TextCanvas c; - - public static void main(String args[]) { - - String[] instructions = - { - "You must have a printer available to perform this test", - "This test should print a page which contains the same", - "text messages as in the test window on the screen", - "The messages should contain only 'OK' and 'expected' messages", - "There should be no FAILURE messages.", - "You should also monitor the command line to see if any exceptions", - "were thrown", - "If the page fails to print, but there were no exceptions", - "then the problem is likely elsewhere (ie your printer)" - }; - Sysout.createDialog( ); - Sysout.printInstructions( instructions ); - - PrintNullString f = new PrintNullString(); - f.show(); - } - - public PrintNullString() { - super("JDK 1.2 drawString Printing"); - - c = new TextCanvas(); - add("Center", c); - - Button printButton = new Button("Print"); - printButton.addActionListener(this); - add("South", printButton); - - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - System.exit(0); - } - }); - - pack(); - } - - public void actionPerformed(ActionEvent e) { - - PrinterJob pj = PrinterJob.getPrinterJob(); - - if (pj != null && pj.printDialog()) { - - pj.setPrintable(c); - try { - pj.print(); - } catch (PrinterException pe) { - } finally { - System.err.println("PRINT RETURNED"); - } - } - } - - class TextCanvas extends Panel implements Printable { - - String nullStr = null; - String emptyStr = new String(); - AttributedString nullAttStr = null; - AttributedString emptyAttStr = new AttributedString(emptyStr); - AttributedCharacterIterator nullIterator = null; - AttributedCharacterIterator emptyIterator = emptyAttStr.getIterator(); - - public int print(Graphics g, PageFormat pgFmt, int pgIndex) { - - if (pgIndex > 0) - return Printable.NO_SUCH_PAGE; - - Graphics2D g2d = (Graphics2D)g; - g2d.translate(pgFmt.getImageableX(), pgFmt.getImageableY()); - - paint(g); - - return Printable.PAGE_EXISTS; - } - - public void paint(Graphics g1) { - Graphics2D g = (Graphics2D)g1; - - // API 1: null & empty drawString(String, int, int); - try { - g.drawString(nullStr, 20, 40); - g.drawString("FAILURE: No NPE for null String, int", 20, 40); - } catch (NullPointerException e) { - g.drawString("caught expected NPE for null String, int", 20, 40); - }/* catch (Exception e) { - g.drawString("FAILURE: unexpected exception for null String, int", - 20, 40); - }*/ - - //try { - g.drawString(emptyStr, 20, 60); - g.drawString("OK for empty String, int", 20, 60); - /*} catch (Exception e) { - g.drawString("FAILURE: unexpected exception for empty String, int", - 20, 60); - }*/ - - - // API 2: null & empty drawString(String, float, float); - try { - g.drawString(nullStr, 20.0f, 80.0f); - g.drawString("FAILURE: No NPE for null String, float", 20, 80); - } catch (NullPointerException e) { - g.drawString("caught expected NPE for null String, float", 20, 80); - } /*catch (Exception e) { - g.drawString("FAILURE: unexpected exception for null String, float", - 20, 80); - }*/ - //try { - g.drawString(emptyStr, 20.0f, 100.0f); - g.drawString("OK for empty String, float", 20.0f, 100.f); - /* } catch (Exception e) { - g.drawString("FAILURE: unexpected exception for empty String, float", - 20, 100); - }*/ - - // API 3: null & empty drawString(Iterator, int, int); - try { - g.drawString(nullIterator, 20, 120); - g.drawString("FAILURE: No NPE for null iterator, float", 20, 120); - } catch (NullPointerException e) { - g.drawString("caught expected NPE for null iterator, int", 20, 120); - } /*catch (Exception e) { - g.drawString("FAILURE: unexpected exception for null iterator, int", - 20, 120); - } */ - try { - g.drawString(emptyIterator, 20, 140); - g.drawString("FAILURE: No IAE for empty iterator, int", - 20, 140); - } catch (IllegalArgumentException e) { - g.drawString("caught expected IAE for empty iterator, int", - 20, 140); - } /*catch (Exception e) { - g.drawString("FAILURE: unexpected exception for empty iterator, int", - 20, 140); - } */ - - - // API 4: null & empty drawString(Iterator, float, int); - try { - g.drawString(nullIterator, 20.0f, 160.0f); - g.drawString("FAILURE: No NPE for null iterator, float", 20, 160); - } catch (NullPointerException e) { - g.drawString("caught expected NPE for null iterator, float", 20, 160); - } /*catch (Exception e) { - g.drawString("FAILURE: unexpected exception for null iterator, float", - 20, 160); - } */ - - try { - g.drawString(emptyIterator, 20, 180); - g.drawString("FAILURE: No IAE for empty iterator, float", - 20, 180); - } catch (IllegalArgumentException e) { - g.drawString("caught expected IAE for empty iterator, float", - 20, 180); - } /*catch (Exception e) { - g.drawString("FAILURE: unexpected exception for empty iterator, float", - 20, 180); - } */ - } - - public Dimension getPreferredSize() { - return new Dimension(450, 250); - } - } - -} - -class Sysout - { - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); +public class PrintNullString extends Frame { + private static final String INSTRUCTIONS = + "This test should print a page which contains the same\n" + + "text messages as in the test window on the screen.\n" + + "\n" + + "The messages should contain only 'OK' and 'expected' messages.\n" + + "Press Pass if it's the case; otherwise press Fail.\n" + + "\n" + + "If the page fails to print, but there were no exceptions\n" + + "then the problem is likely elsewhere (i.e. your printer)"; + + public static void main(String[] args) throws Exception { + if (PrinterJob.lookupPrintServices().length == 0) { + throw new RuntimeException("Printer not configured or available."); + } + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .testUI(PrintNullString::new) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(45) + .build() + .awaitAndCheck(); } - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); + public PrintNullString() { + super("PrintNullString"); + + TextCanvas c = new TextCanvas(); + add("Center", c); + + Button b = new Button("Print"); + add("South", b); + b.addActionListener(e -> { + PrinterJob pj = PrinterJob.getPrinterJob(); + if (pj.printDialog()) { + pj.setPrintable(c); + try { + pj.print(); + } catch (PrinterException ex) { + ex.printStackTrace(); + String msg = "PrinterException: " + ex.getMessage(); + JOptionPane.showMessageDialog(b, msg, "Error occurred", + JOptionPane.ERROR_MESSAGE); + PassFailJFrame.forceFail(msg); + } + } + }); + pack(); } - }// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); + private static class TextCanvas extends Panel implements Printable { + private final String nullStr = null; + private final String emptyStr = ""; + private final AttributedString emptyAttStr = new AttributedString(emptyStr); + private final AttributedCharacterIterator nullIterator = null; + private final AttributedCharacterIterator emptyIterator = emptyAttStr.getIterator(); + + @Override + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + paint(g2d); + } + + @Override + public int print(Graphics g, PageFormat pgFmt, int pgIndex) { + if (pgIndex > 0) { + return NO_SUCH_PAGE; + } - show(); - }// TestDialog() + Graphics2D g2d = (Graphics2D) g; + g2d.translate(pgFmt.getImageableX(), pgFmt.getImageableY()); + paint(g2d); - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); + return PAGE_EXISTS; + } - //Go down array of instruction strings + private void paint(Graphics2D g2d) { + // API 1: null & empty drawString(String, int, int); + try { + g2d.drawString(nullStr, 20, 40); + g2d.drawString("FAILURE: No NPE for null String, int", 20, 40); + } catch (NullPointerException e) { + g2d.drawString("caught expected NPE for null String, int", 20, 40); + } - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); + g2d.drawString(emptyStr, 20, 60); + g2d.drawString("OK for empty String, int", 20, 60); - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; + // API 2: null & empty drawString(String, float, float); + try { + g2d.drawString(nullStr, 20.0f, 80.0f); + g2d.drawString("FAILURE: No NPE for null String, float", 20, 80); + } catch (NullPointerException e) { + g2d.drawString("caught expected NPE for null String, float", 20, 80); + } - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } + g2d.drawString(emptyStr, 20.0f, 100.0f); + g2d.drawString("OK for empty String, float", 20.0f, 100.f); - instructionsText.append( printStr + "\n" ); + // API 3: null & empty drawString(Iterator, int, int); + try { + g2d.drawString(nullIterator, 20, 120); + g2d.drawString("FAILURE: No NPE for null iterator, float", 20, 120); + } catch (NullPointerException e) { + g2d.drawString("caught expected NPE for null iterator, int", 20, 120); + } - }// while + try { + g2d.drawString(emptyIterator, 20, 140); + g2d.drawString("FAILURE: No IAE for empty iterator, int", 20, 140); + } catch (IllegalArgumentException e) { + g2d.drawString("caught expected IAE for empty iterator, int", 20, 140); + } - }// for + // API 4: null & empty drawString(Iterator, float, int); + try { + g2d.drawString(nullIterator, 20.0f, 160.0f); + g2d.drawString("FAILURE: No NPE for null iterator, float", 20, 160); + } catch (NullPointerException e) { + g2d.drawString("caught expected NPE for null iterator, float", 20, 160); + } - }//printInstructions() + try { + g2d.drawString(emptyIterator, 20, 180); + g2d.drawString("FAILURE: No IAE for empty iterator, float", 20, 180); + } catch (IllegalArgumentException e) { + g2d.drawString("caught expected IAE for empty iterator, float", 20, 180); + } + } - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); + @Override + public Dimension getPreferredSize() { + return new Dimension(450, 250); + } } - - }// TestDialog class +} diff --git a/test/jdk/java/awt/print/PrinterJob/PrintParenString.java b/test/jdk/java/awt/print/PrinterJob/PrintParenString.java index dc6d544d126..25d88126c52 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintParenString.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintParenString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,226 +21,87 @@ * questions. */ -/** +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JOptionPane; + +/* * @test * @bug 4399442 * @summary Brackets should be quoted in Postscript output - * @author prr + * @key printer + * @library /java/awt/regtesthelpers + * @build PassFailJFrame * @run main/manual PrintParenString */ +public class PrintParenString implements Printable { + private static final String STR = "String containing unclosed parenthesis (."; + + private static final String INSTRUCTIONS = + "This test should print a page with following text\n\n" + + STR + "\n\n" + + "If an exception is thrown, or the page doesn't print properly\n" + + "then the test fails"; + + public static void main(String[] args) throws Exception { + if (PrinterJob.lookupPrintServices().length == 0) { + throw new RuntimeException("Printer not configured or available."); + } + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .splitUI(PrintParenString::createTestUI) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(45) + .build() + .awaitAndCheck(); + } - -import java.awt.*; -import java.awt.event.*; -import java.awt.print.*; -import java.text.*; - -public class PrintParenString extends Frame implements ActionListener { - - private TextCanvas c; - - public static void main(String args[]) { - - String[] instructions = - { - "You must have a printer available to perform this test", - "This test should print a page which contains the same", - "text message as in the test window on the screen", - "You should also monitor the command line to see if any exceptions", - "were thrown", - "If an exception is thrown, or the page doesn't print properly", - "then the test fails", - }; - Sysout.createDialog( ); - Sysout.printInstructions( instructions ); - - PrintParenString f = new PrintParenString(); - f.show(); - } - - public PrintParenString() { - super("JDK 1.2 drawString Printing"); - - c = new TextCanvas(); - add("Center", c); - - Button printButton = new Button("Print"); - printButton.addActionListener(this); - add("South", printButton); - - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - System.exit(0); + private static JComponent createTestUI() { + JButton b = new JButton("Print"); + b.addActionListener((ae) -> { + try { + PrinterJob job = PrinterJob.getPrinterJob(); + job.setPrintable(new PrintParenString()); + if (job.printDialog()) { + job.print(); + } + } catch (PrinterException ex) { + ex.printStackTrace(); + String msg = "PrinterException: " + ex.getMessage(); + JOptionPane.showMessageDialog(b, msg, "Error occurred", + JOptionPane.ERROR_MESSAGE); + PassFailJFrame.forceFail(msg); } - }); - - pack(); - } - - public void actionPerformed(ActionEvent e) { - - PrinterJob pj = PrinterJob.getPrinterJob(); - - if (pj != null && pj.printDialog()) { - - pj.setPrintable(c); - try { - pj.print(); - } catch (PrinterException pe) { - } finally { - System.err.println("PRINT RETURNED"); - } - } - } - - class TextCanvas extends Panel implements Printable { - - String nullStr = null; - String emptyStr = new String(); - AttributedString nullAttStr = null; - AttributedString emptyAttStr = new AttributedString(emptyStr); - AttributedCharacterIterator nullIterator = null; - AttributedCharacterIterator emptyIterator = emptyAttStr.getIterator(); - - public int print(Graphics g, PageFormat pgFmt, int pgIndex) { - - if (pgIndex > 0) - return Printable.NO_SUCH_PAGE; - - Graphics2D g2d = (Graphics2D)g; - g2d.translate(pgFmt.getImageableX(), pgFmt.getImageableY()); - - paint(g); - - return Printable.PAGE_EXISTS; + }); + + Box main = Box.createHorizontalBox(); + main.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); + main.add(Box.createHorizontalGlue()); + main.add(b); + main.add(Box.createHorizontalGlue()); + return main; } - public void paint(Graphics g1) { - Graphics2D g = (Graphics2D)g1; - - String str = "String containing unclosed parenthesis (."; - g.drawString(str, 20, 40); + @Override + public int print(Graphics g, PageFormat pgFmt, int pgIndex) { + if (pgIndex > 0) { + return Printable.NO_SUCH_PAGE; + } - } + Graphics2D g2d = (Graphics2D) g; + g2d.translate(pgFmt.getImageableX(), pgFmt.getImageableY()); + g2d.drawString(STR, 20, 40); - public Dimension getPreferredSize() { - return new Dimension(450, 250); + return Printable.PAGE_EXISTS; } - } - } - -class Sysout - { - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - - }// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - show(); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - } - - }// TestDialog class diff --git a/test/jdk/java/awt/print/PrinterJob/PrintRotatedText.java b/test/jdk/java/awt/print/PrinterJob/PrintRotatedText.java index 5f5a6fa69d6..deabc0e6999 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintRotatedText.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintRotatedText.java @@ -26,7 +26,7 @@ * @bug 4271596 * @bug 4460699 * @summary Rotated text printing - * @author prr + * @key printer * @run main/manual PrintRotatedText */ diff --git a/test/jdk/java/awt/print/PrinterJob/PrintTest.java b/test/jdk/java/awt/print/PrinterJob/PrintTest.java index 3c3febe414c..321293877ab 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintTest.java @@ -23,6 +23,7 @@ /* * @test * @bug 8151590 + * @key printer * @summary All radio button should be selected when we call * setDefaultSelection(JobAttributes.DefaultSelectionType.ALL); * @run main/manual PrintTest diff --git a/test/jdk/java/awt/print/PrinterJob/PrintTestLexmarkIQ.java b/test/jdk/java/awt/print/PrinterJob/PrintTestLexmarkIQ.java index cb82100efb0..a5c7110c5d5 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintTestLexmarkIQ.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintTestLexmarkIQ.java @@ -25,6 +25,7 @@ * @bug 6966350 8160882 * @summary Verifies if Empty pages are printed on Lexmark E352dn PS3 * with "1200 IQ" setting + * @key printer * @run main/manual PrintTestLexmarkIQ */ import java.awt.BorderLayout; diff --git a/test/jdk/java/awt/print/PrinterJob/PrintTextLayout.java b/test/jdk/java/awt/print/PrinterJob/PrintTextLayout.java index 2dfd10ccd32..9560c6b86ff 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintTextLayout.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintTextLayout.java @@ -25,7 +25,7 @@ * @test * @bug 4480930 * @summary TextLayout prints as filled shapes - * @author prr + * @key printer * @run main/manual PrintTextLayout */ diff --git a/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java b/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java index c7d9c984b64..95bf177aa2f 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java @@ -24,6 +24,7 @@ /** * @test * @bug 6425068 7157659 8132890 + * @key printer * @summary Confirm that text prints where we expect to the length we expect. * @run main/manual=yesno PrintTextTest */ diff --git a/test/jdk/java/awt/print/PrinterJob/PrintTranslatedFont.java b/test/jdk/java/awt/print/PrinterJob/PrintTranslatedFont.java index fefa737990b..de80a1e9ee7 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintTranslatedFont.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintTranslatedFont.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,237 +21,126 @@ * questions. */ -/** +import java.awt.Button; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.geom.AffineTransform; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; + +import javax.swing.JOptionPane; + +/* * @test * @bug 6359734 + * @key printer + * @library /java/awt/regtesthelpers + * @build PassFailJFrame * @summary Test that fonts with a translation print where they should. - * @author prr * @run main/manual PrintTranslatedFont */ +public class PrintTranslatedFont extends Frame { + private static final String INSTRUCTIONS = + "This test should print a page which contains the same\n" + + "content as the test window on the screen, in particular the lines\n" + + "should be immediately under the text\n\n" + + "If an exception is thrown, or the page doesn't print properly\n" + + "then the test fails"; + + public static void main(String[] args) throws Exception { + if (PrinterJob.lookupPrintServices().length == 0) { + throw new RuntimeException("Printer not configured or available."); + } + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .testUI(PrintTranslatedFont::new) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(45) + .build() + .awaitAndCheck(); + } - -import java.awt.*; -import java.awt.event.*; -import java.awt.geom.*; -import java.awt.print.*; -import java.text.*; - -public class PrintTranslatedFont extends Frame implements ActionListener { - - private TextCanvas c; - - public static void main(String args[]) { - - String[] instructions = - { - "You must have a printer available to perform this test", - "This test should print a page which contains the same", - "content as the test window on the screen, in particular the lines", - "should be immediately under the text", - "You should also monitor the command line to see if any exceptions", - "were thrown", - "If an exception is thrown, or the page doesn't print properly", - "then the test fails", - }; - Sysout.createDialog( ); - Sysout.printInstructions( instructions ); - - PrintTranslatedFont f = new PrintTranslatedFont(); - f.show(); - } - - public PrintTranslatedFont() { - super("JDK 1.2 drawString Printing"); - - c = new TextCanvas(); - add("Center", c); - - Button printButton = new Button("Print"); - printButton.addActionListener(this); - add("South", printButton); - - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - System.exit(0); + public PrintTranslatedFont() { + super("PrintTranslatedFont"); + + TextCanvas c = new TextCanvas(); + add("Center", c); + + Button b = new Button("Print"); + add("South", b); + b.addActionListener(e -> { + PrinterJob pj = PrinterJob.getPrinterJob(); + if (pj.printDialog()) { + pj.setPrintable(c); + try { + pj.print(); + } catch (PrinterException ex) { + ex.printStackTrace(); + String msg = "PrinterException: " + ex.getMessage(); + JOptionPane.showMessageDialog(b, msg, "Error occurred", + JOptionPane.ERROR_MESSAGE); + PassFailJFrame.forceFail(msg); + } } - }); - - pack(); - } - - public void actionPerformed(ActionEvent e) { + }); - PrinterJob pj = PrinterJob.getPrinterJob(); - - if (pj != null && pj.printDialog()) { - - pj.setPrintable(c); - try { - pj.print(); - } catch (PrinterException pe) { - } finally { - System.err.println("PRINT RETURNED"); - } - } - } - - class TextCanvas extends Panel implements Printable { - - public int print(Graphics g, PageFormat pgFmt, int pgIndex) { - - if (pgIndex > 0) - return Printable.NO_SUCH_PAGE; - - Graphics2D g2d = (Graphics2D)g; - g2d.translate(pgFmt.getImageableX(), pgFmt.getImageableY()); - - paint(g); - - return Printable.PAGE_EXISTS; + pack(); } - public void paint(Graphics g1) { - Graphics2D g = (Graphics2D)g1; - - Font f = new Font("Dialog", Font.PLAIN, 20); - int tx = 20; - int ty = 20; - AffineTransform at = AffineTransform.getTranslateInstance(tx, ty); - f = f.deriveFont(at); - g.setFont(f); - - FontMetrics fm = g.getFontMetrics(); - String str = "Basic ascii string"; - int sw = fm.stringWidth(str); - int posx = 20, posy = 40; - g.drawString(str, posx, posy); - g.drawLine(posx+tx, posy+ty+2, posx+tx+sw, posy+ty+2); - - posx = 20; posy = 70; - str = "Test string compound printing \u2203\u2200"; - sw = fm.stringWidth(str); - g.drawString(str, posx, posy); - g.drawLine(posx+tx, posy+ty+2, posx+tx+sw, posy+ty+2); - } + private static class TextCanvas extends Panel implements Printable { + @Override + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + paint(g2d); + } + + @Override + public int print(Graphics g, PageFormat pgFmt, int pgIndex) { + if (pgIndex > 0) { + return Printable.NO_SUCH_PAGE; + } - public Dimension getPreferredSize() { - return new Dimension(450, 250); + Graphics2D g2d = (Graphics2D) g; + g2d.translate(pgFmt.getImageableX(), pgFmt.getImageableY()); + paint(g2d); + return Printable.PAGE_EXISTS; + } + + private void paint(Graphics2D g2d) { + Font f = new Font("Dialog", Font.PLAIN, 20); + int tx = 20; + int ty = 20; + AffineTransform at = AffineTransform.getTranslateInstance(tx, ty); + f = f.deriveFont(at); + g2d.setFont(f); + + FontMetrics fm = g2d.getFontMetrics(); + String str = "Basic ascii string"; + int sw = fm.stringWidth(str); + int posx = 20; + int posy = 40; + g2d.drawString(str, posx, posy); + g2d.drawLine(posx + tx, posy + ty + 2, posx + tx + sw, posy + ty + 2); + + posx = 20; + posy = 70; + str = "Test string compound printing \u2203\u2200"; + sw = fm.stringWidth(str); + g2d.drawString(str, posx, posy); + g2d.drawLine(posx + tx, posy + ty + 2, posx + tx + sw, posy + ty + 2); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(450, 250); + } } - } - } - -class Sysout - { - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - - }// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - show(); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - } - - }// TestDialog class diff --git a/test/jdk/java/awt/print/PrinterJob/PrintVolatileImage.java b/test/jdk/java/awt/print/PrinterJob/PrintVolatileImage.java index 82a7c9ed83d..d594b5a31dd 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintVolatileImage.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintVolatileImage.java @@ -25,7 +25,7 @@ * @test * @bug 4511023 * @summary Image should be sent to printer, no exceptions thrown - * @author prr + * @key printer * @run main/manual PrintVolatileImage */ diff --git a/test/jdk/java/awt/print/PrinterJob/PrinterDialogsModalityTest/PrinterDialogsModalityTest.html b/test/jdk/java/awt/print/PrinterJob/PrinterDialogsModalityTest/PrinterDialogsModalityTest.html index 3b6b87f6b03..9cfb86bd479 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrinterDialogsModalityTest/PrinterDialogsModalityTest.html +++ b/test/jdk/java/awt/print/PrinterJob/PrinterDialogsModalityTest/PrinterDialogsModalityTest.html @@ -25,8 +25,8 @@ diff --git a/test/jdk/java/awt/print/PrinterJob/PrinterDialogsModalityTest/PrinterDialogsModalityTest.java b/test/jdk/java/awt/print/PrinterJob/PrinterDialogsModalityTest/PrinterDialogsModalityTest.java index 2178697b170..bb40832e36f 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrinterDialogsModalityTest/PrinterDialogsModalityTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PrinterDialogsModalityTest/PrinterDialogsModalityTest.java @@ -24,8 +24,8 @@ /* test @bug 4784285 4785920 + @key printer @summary check whether Print- and Page- dialogs are modal and correct window activated after their closing - @author son@sparc.spb.su: area=PrinterJob.modality @run applet/manual=yesno PrinterDialogsModalityTest.html */ diff --git a/test/jdk/java/awt/print/PrinterJob/PrinterJobDialogBugDemo.java b/test/jdk/java/awt/print/PrinterJob/PrinterJobDialogBugDemo.java index d06d08dcbe3..d7a18300bd7 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrinterJobDialogBugDemo.java +++ b/test/jdk/java/awt/print/PrinterJob/PrinterJobDialogBugDemo.java @@ -24,6 +24,7 @@ /** * @test * @bug 4775862 + * @key printer * @run main/manual PrinterJobDialogBugDemo */ import java.awt.BorderLayout; diff --git a/test/jdk/java/awt/print/PrinterJob/RadialGradientPrintingTest.java b/test/jdk/java/awt/print/PrinterJob/RadialGradientPrintingTest.java index 61c9faeda24..8cd538f1d62 100644 --- a/test/jdk/java/awt/print/PrinterJob/RadialGradientPrintingTest.java +++ b/test/jdk/java/awt/print/PrinterJob/RadialGradientPrintingTest.java @@ -23,6 +23,7 @@ /* * @test * @bug 8162796 + * @key printer * @summary Verifies if RadialGradientPaint is printed in osx * @run main/manual RadialGradientPrintingTest */ diff --git a/test/jdk/java/awt/print/PrinterJob/RemoveListener.java b/test/jdk/java/awt/print/PrinterJob/RemoveListener.java index 2a467a438a3..0818cd7e7f4 100644 --- a/test/jdk/java/awt/print/PrinterJob/RemoveListener.java +++ b/test/jdk/java/awt/print/PrinterJob/RemoveListener.java @@ -22,8 +22,9 @@ */ /* - * @test 1.1 01/05/17 + * @test * @bug 4459889 + * @key printer * @summary No NullPointerException should occur. * @run main RemoveListener */ diff --git a/test/jdk/java/awt/print/PrinterJob/SameService.java b/test/jdk/java/awt/print/PrinterJob/SameService.java index 4073b55fb92..611cea9ecdb 100644 --- a/test/jdk/java/awt/print/PrinterJob/SameService.java +++ b/test/jdk/java/awt/print/PrinterJob/SameService.java @@ -24,6 +24,7 @@ /** * @test * @bug 6446094 + * @key printer * @summary Don't re-create print services. * @run main SameService */ diff --git a/test/jdk/java/awt/print/PrinterJob/ScaledText/ScaledText.java b/test/jdk/java/awt/print/PrinterJob/ScaledText/ScaledText.java index a440db4f2f9..22da4431117 100644 --- a/test/jdk/java/awt/print/PrinterJob/ScaledText/ScaledText.java +++ b/test/jdk/java/awt/print/PrinterJob/ScaledText/ScaledText.java @@ -25,7 +25,7 @@ @test @bug 4291373 @summary Printing of scaled text is wrong / disappearing - @author prr: area=PrinterJob + @key printer @run main/manual ScaledText */ import java.awt.*; diff --git a/test/jdk/java/awt/print/PrinterJob/SecurityDialogTest.java b/test/jdk/java/awt/print/PrinterJob/SecurityDialogTest.java index c5d356c6118..dc103dc6f56 100644 --- a/test/jdk/java/awt/print/PrinterJob/SecurityDialogTest.java +++ b/test/jdk/java/awt/print/PrinterJob/SecurityDialogTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,209 +21,110 @@ * questions. */ -/** +import java.awt.Frame; +import java.awt.print.PageFormat; +import java.awt.print.PrinterJob; +import java.lang.reflect.InvocationTargetException; + +import javax.print.PrintService; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.SwingUtilities; + +/* * @test * @bug 4937672 5100706 6252456 - * @run main/othervm/manual -Djava.security.manager=allow SecurityDialogTest + * @key printer + * @summary Verifies "Print to file" option is disable if reading/writing files + * is not allowed by Security Manager. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual/othervm -Djava.security.manager=allow SecurityDialogTest */ - -import java.awt.* ; -import java.awt.print.* ; -import java.io.*; -import java.security.*; -import javax.print.*; -import javax.print.attribute.*; - public class SecurityDialogTest { + private static final String INSTRUCTIONS = + "This test brings up a native and cross-platform page and print dialogs.\n" + + "\n" + + "If the dialog has an option to save to file, the option ought " + + "to be disabled.\n" + + "\n" + + "Press the Pass button if the \"Print to file\" option was disabled in\n" + + "all the dialogs where it was present.\n" + + "Otherwise, press the Fail button.\n" + + "\n" + + "The dialogs should be displayed even when " + + "there is no queuePrintJob permission."; + + private static JLabel dialogType; + + public static void main(String[] args) throws Exception { + if (PrinterJob.lookupPrintServices().length == 0) { + throw new RuntimeException("Printer not configured or available."); + } + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .splitUIBottom(SecurityDialogTest::createTestUI) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(45) + .build(); - public static void main ( String args[] ) { - - String[] instructions = - { - "You must have a printer available to perform this test.", - "This test brings up a native and cross-platform page and", - "print dialogs.", - "The dialogs should be displayed even when ", - "there is no queuePrintJob permission.", - "If the dialog has an option to save to file, the option ought", - "to be disabled if there is no read/write file permission.", - "You should test this by trying different policy files." - }; - - Sysout.createDialog( ); - Sysout.printInstructions( instructions ); + displayDialogs(); - SecurityDialogTest pjc = new SecurityDialogTest() ; + passFailJFrame.awaitAndCheck(); } + private static JComponent createTestUI() { + dialogType = new JLabel(" "); - public SecurityDialogTest() { - - PrinterJob pj = PrinterJob.getPrinterJob() ; - - // Install a security manager which does not allow reading and - // writing of files. - //PrintTestSecurityManager ptsm = new PrintTestSecurityManager(); - SecurityManager ptsm = new SecurityManager(); - - try { - System.setSecurityManager(ptsm); - } catch (SecurityException e) { - System.out.println("Could not run test - security exception"); - } - - try { - PrintJob pjob = Toolkit.getDefaultToolkit().getPrintJob(new Frame(), "Printing", null, null); - Sysout.println("If the value of pjob is null, the test fails.\n"); - Sysout.println(" pjob = "+pjob); - } catch (SecurityException e) { - } - - PrintService[] services = PrinterJob.lookupPrintServices(); - for (int i=0; i 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); + private static void setDialogType(String type) + throws InterruptedException, InvocationTargetException { + SwingUtilities.invokeAndWait(() -> dialogType.setText(type)); } - - }// TestDialog class +} diff --git a/test/jdk/java/awt/print/PrinterJob/SetCopies/Test.java b/test/jdk/java/awt/print/PrinterJob/SetCopies/Test.java index 7b8d9ce7c00..b32d716bbee 100644 --- a/test/jdk/java/awt/print/PrinterJob/SetCopies/Test.java +++ b/test/jdk/java/awt/print/PrinterJob/SetCopies/Test.java @@ -24,6 +24,7 @@ /** * @test * @bug 4694495 + * @key printer * @summary Check that the dialog shows copies = 3. * @run main/manual Test */ diff --git a/test/jdk/java/awt/print/PrinterJob/SwingUIText.java b/test/jdk/java/awt/print/PrinterJob/SwingUIText.java index c1e47638023..5fcd5e39158 100644 --- a/test/jdk/java/awt/print/PrinterJob/SwingUIText.java +++ b/test/jdk/java/awt/print/PrinterJob/SwingUIText.java @@ -24,6 +24,7 @@ /** * @test * @bug 6488219 6560738 7158350 8017469 + * @key printer * @summary Test that text printed in Swing UI measures and looks OK. * @run main/manual=yesno PrintTextTest */ diff --git a/test/jdk/java/awt/print/PrinterJob/TestCheckSystemDefaultBannerOption.java b/test/jdk/java/awt/print/PrinterJob/TestCheckSystemDefaultBannerOption.java index b9e18d34393..ca07c05a6ef 100644 --- a/test/jdk/java/awt/print/PrinterJob/TestCheckSystemDefaultBannerOption.java +++ b/test/jdk/java/awt/print/PrinterJob/TestCheckSystemDefaultBannerOption.java @@ -23,6 +23,7 @@ /* * @test * @bug 8165947 8170579 + * @key printer * @summary Verifies System default banner page option is honoured by jdk * @requires os.family == "linux" * @run main/manual TestCheckSystemDefaultBannerOption diff --git a/test/jdk/java/awt/print/PrinterJob/TestMediaTraySelection.java b/test/jdk/java/awt/print/PrinterJob/TestMediaTraySelection.java index f75336c2c0d..6a5a91ac89e 100644 --- a/test/jdk/java/awt/print/PrinterJob/TestMediaTraySelection.java +++ b/test/jdk/java/awt/print/PrinterJob/TestMediaTraySelection.java @@ -24,6 +24,7 @@ * @bug 6357887 8165146 8234393 * @summary Verifies if selected printertray is used * @requires (os.family == "linux" | os.family == "mac") + * @key printer * @run main/manual TestMediaTraySelection */ diff --git a/test/jdk/java/awt/print/PrinterJob/TestPageDlgFrameAssociation.java b/test/jdk/java/awt/print/PrinterJob/TestPageDlgFrameAssociation.java index 32ee61ad1c6..5ca2cda4b60 100644 --- a/test/jdk/java/awt/print/PrinterJob/TestPageDlgFrameAssociation.java +++ b/test/jdk/java/awt/print/PrinterJob/TestPageDlgFrameAssociation.java @@ -23,6 +23,7 @@ /* * @test * @bug 7064425 6948907 + * @key printer * @summary Verifies if owner Frame is associated with page dialog of PrinterJob * @run main/manual TestPageDlgFrameAssociation */ diff --git a/test/jdk/java/awt/print/PrinterJob/TestPrintDlgFrameAssociation.java b/test/jdk/java/awt/print/PrinterJob/TestPrintDlgFrameAssociation.java index d1d54307ab5..e5d58c8baea 100644 --- a/test/jdk/java/awt/print/PrinterJob/TestPrintDlgFrameAssociation.java +++ b/test/jdk/java/awt/print/PrinterJob/TestPrintDlgFrameAssociation.java @@ -23,6 +23,7 @@ /* * @test * @bug 7064425 6948907 + * @key printer * @summary Verifies if owner Frame is associated with print dialog of PrinterJob * @run main/manual TestPrintDlgFrameAssociation */ diff --git a/test/jdk/java/awt/print/PrinterJob/TexturePaintPrintingTest.java b/test/jdk/java/awt/print/PrinterJob/TexturePaintPrintingTest.java index 8ac81c8bbad..3d8c6815f95 100644 --- a/test/jdk/java/awt/print/PrinterJob/TexturePaintPrintingTest.java +++ b/test/jdk/java/awt/print/PrinterJob/TexturePaintPrintingTest.java @@ -23,6 +23,7 @@ /* * @test * @bug 8040635 + * @key printer * @summary Verifies if TexturePaint is printed in osx * @run main/manual TexturePaintPrintingTest */ diff --git a/test/jdk/java/awt/print/PrinterJob/ThinLines.java b/test/jdk/java/awt/print/PrinterJob/ThinLines.java index 2d880a44006..f8e4e60b319 100644 --- a/test/jdk/java/awt/print/PrinterJob/ThinLines.java +++ b/test/jdk/java/awt/print/PrinterJob/ThinLines.java @@ -25,7 +25,7 @@ @test @bug 4190081 @summary Confirm that the you see "Z" shapes on the printed page. - @author prr/rbi: area=PrinterJob + @key printer @run main/manual ThinLines */ diff --git a/test/jdk/java/awt/print/PrinterJob/ValidatePage/ValidatePage.java b/test/jdk/java/awt/print/PrinterJob/ValidatePage/ValidatePage.java index 8c9f81b11df..ccf0bed43bb 100644 --- a/test/jdk/java/awt/print/PrinterJob/ValidatePage/ValidatePage.java +++ b/test/jdk/java/awt/print/PrinterJob/ValidatePage/ValidatePage.java @@ -24,8 +24,8 @@ /** * @test * @bug 4252108 6229507 + * @key printer * @summary PrinterJob.validatePage() is unimplemented. - * @author prr * @run main/manual ValidatePage */ diff --git a/test/jdk/java/awt/print/PrinterJob/XparColor.java b/test/jdk/java/awt/print/PrinterJob/XparColor.java index dd39578f2cb..9a85a78af55 100644 --- a/test/jdk/java/awt/print/PrinterJob/XparColor.java +++ b/test/jdk/java/awt/print/PrinterJob/XparColor.java @@ -24,6 +24,7 @@ /** * @test * @bug 4179262 + @ @key printer * @summary Confirm that transparent colors are printed correctly. The * printout should show transparent rings with increasing darkness toward * the center. diff --git a/test/jdk/java/awt/print/PrinterJob/raster/RasterTest.java b/test/jdk/java/awt/print/PrinterJob/raster/RasterTest.java index 56adc8552f7..29709429913 100644 --- a/test/jdk/java/awt/print/PrinterJob/raster/RasterTest.java +++ b/test/jdk/java/awt/print/PrinterJob/raster/RasterTest.java @@ -25,7 +25,7 @@ * @test * @bug 4242639 * @summary Printing quality problem on Canon and NEC - * @author prr + * @key printer * @run main/manual RasterTest */ import java.awt.*; diff --git a/test/jdk/java/awt/print/RemotePrinterStatusRefresh/RemotePrinterStatusRefresh.java b/test/jdk/java/awt/print/RemotePrinterStatusRefresh/RemotePrinterStatusRefresh.java index 3bfedb463a7..7768c54481a 100644 --- a/test/jdk/java/awt/print/RemotePrinterStatusRefresh/RemotePrinterStatusRefresh.java +++ b/test/jdk/java/awt/print/RemotePrinterStatusRefresh/RemotePrinterStatusRefresh.java @@ -23,6 +23,7 @@ /* * @test + * @key printer * @bug 8153732 8212202 8221263 8221412 8222108 8263311 * @requires (os.family == "Windows") * @summary Windows remote printer changes do not reflect in lookupPrintServices() diff --git a/test/jdk/java/awt/print/bug8023392/bug8023392.html b/test/jdk/java/awt/print/bug8023392/bug8023392.html index c51ae001e2e..178fba9b230 100644 --- a/test/jdk/java/awt/print/bug8023392/bug8023392.html +++ b/test/jdk/java/awt/print/bug8023392/bug8023392.html @@ -26,7 +26,7 @@ @test @bug 8023392 @summary Swing text components printed with spaces between chars - @author Anton Nashatyrev + @key printer @modules java.desktop/sun.swing @run applet/manual=yesno bug8023392.html --> diff --git a/test/jdk/java/awt/print/bug8023392/bug8023392.java b/test/jdk/java/awt/print/bug8023392/bug8023392.java index 071c9021ddf..d792562ea25 100644 --- a/test/jdk/java/awt/print/bug8023392/bug8023392.java +++ b/test/jdk/java/awt/print/bug8023392/bug8023392.java @@ -25,7 +25,7 @@ test @bug 8023392 8259232 @summary Swing text components printed with spaces between chars - @author Anton Nashatyrev + @key printer @run applet/manual=yesno bug8023392.html */ diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 741cee4d1d7..68cb22fecdd 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,6 +64,7 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; +import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.Timer; import javax.swing.text.JTextComponent; @@ -115,6 +116,13 @@ * or a list of windows if the test needs multiple windows, * or directly a single window, an array of windows or a list of windows. *

+ * For simple test UI, use {@code Builder.splitUI}, or explicitly + * {@code Builder.splitUIRight} or {@code Builder.splitUIBottom} with + * a {@code PanelCreator}. The framework will call the provided + * {@code createUIPanel} to create the component with test UI and + * will place it as the right or bottom component in a split pane + * along with instruction UI. + *

* Alternatively, use one of the {@code PassFailJFrame} constructors to * create an object, then create secondary test UI, register it * with {@code PassFailJFrame}, position it and make it visible. @@ -167,6 +175,14 @@ public final class PassFailJFrame { */ private static final String EMPTY_REASON = "(no reason provided)"; + /** + * List of windows or frames managed by the {@code PassFailJFrame} + * framework. These windows are automatically disposed of when the + * test is finished. + *

+ * Note: access to this field has to be synchronized by + * {@code PassFailJFrame.class}. + */ private static final List windowList = new ArrayList<>(); private static final CountDownLatch latch = new CountDownLatch(1); @@ -277,10 +293,33 @@ public PassFailJFrame(String title, String instructions, long testTimeOut, enableScreenCapture)); } - private PassFailJFrame(Builder builder) throws InterruptedException, - InvocationTargetException { - this(builder.title, builder.instructions, builder.testTimeOut, - builder.rows, builder.columns, builder.screenCapture); + /** + * Configures {@code PassFailJFrame} using the builder. + * It creates test UI specified using {@code testUI} or {@code splitUI} + * methods on EDT. + * @param builder the builder with the parameters + * @throws InterruptedException if the current thread is interrupted while + * waiting for EDT to complete a task + * @throws InvocationTargetException if an exception is thrown while + * running a task on EDT + */ + private PassFailJFrame(final Builder builder) + throws InterruptedException, InvocationTargetException { + invokeOnEDT(() -> createUI(builder)); + + if (!builder.splitUI && builder.panelCreator != null) { + JComponent content = builder.panelCreator.createUIPanel(); + String title = content.getName(); + if (title == null) { + title = "Test UI"; + } + JDialog dialog = new JDialog(frame, title, false); + dialog.addWindowListener(windowClosingHandler); + dialog.add(content, BorderLayout.CENTER); + dialog.pack(); + addTestWindow(dialog); + positionTestWindow(dialog, builder.position); + } if (builder.windowListCreator != null) { invokeOnEDT(() -> @@ -300,11 +339,10 @@ private PassFailJFrame(Builder builder) throws InterruptedException, if (builder.positionWindows != null) { positionInstructionFrame(builder.position); - invokeOnEDT(() -> { - builder.positionWindows - .positionTestWindows(unmodifiableList(builder.testWindows), - builder.instructionUIHandler); - }); + invokeOnEDT(() -> + builder.positionWindows + .positionTestWindows(unmodifiableList(builder.testWindows), + builder.instructionUIHandler)); } else if (builder.testWindows.size() == 1) { Window window = builder.testWindows.get(0); positionTestWindow(window, builder.position); @@ -342,16 +380,61 @@ private static void createUI(String title, String instructions, frame = new JFrame(title); frame.setLayout(new BorderLayout()); + frame.addWindowListener(windowClosingHandler); + + frame.add(createInstructionUIPanel(instructions, + testTimeOut, + rows, columns, + enableScreenCapture), + BorderLayout.CENTER); + frame.pack(); + frame.setLocationRelativeTo(null); + addTestWindow(frame); + } + + private static void createUI(Builder builder) { + frame = new JFrame(builder.title); + frame.setLayout(new BorderLayout()); + + frame.addWindowListener(windowClosingHandler); + + JComponent instructionUI = + createInstructionUIPanel(builder.instructions, + builder.testTimeOut, + builder.rows, builder.columns, + builder.screenCapture); + + if (builder.splitUI) { + JSplitPane splitPane = new JSplitPane( + builder.splitUIOrientation, + instructionUI, + builder.panelCreator.createUIPanel()); + frame.add(splitPane, BorderLayout.CENTER); + } else { + frame.add(instructionUI, BorderLayout.CENTER); + } + + frame.pack(); + frame.setLocationRelativeTo(null); + addTestWindow(frame); + } + + private static JComponent createInstructionUIPanel(String instructions, + long testTimeOut, + int rows, int columns, + boolean enableScreenCapture) { + JPanel main = new JPanel(new BorderLayout()); + JLabel testTimeoutLabel = new JLabel("", JLabel.CENTER); timeoutHandler = new TimeoutHandler(testTimeoutLabel, testTimeOut); - frame.add(testTimeoutLabel, BorderLayout.NORTH); + main.add(testTimeoutLabel, BorderLayout.NORTH); JTextComponent text = instructions.startsWith("") ? configureHTML(instructions, rows, columns) : configurePlainText(instructions, rows, columns); text.setEditable(false); - frame.add(new JScrollPane(text), BorderLayout.CENTER); + main.add(new JScrollPane(text), BorderLayout.CENTER); JButton btnPass = new JButton("Pass"); btnPass.addActionListener((e) -> { @@ -373,12 +456,10 @@ private static void createUI(String title, String instructions, buttonsPanel.add(createCapturePanel()); } - frame.addWindowListener(windowClosingHandler); + main.add(buttonsPanel, BorderLayout.SOUTH); + main.setMinimumSize(main.getPreferredSize()); - frame.add(buttonsPanel, BorderLayout.SOUTH); - frame.pack(); - frame.setLocationRelativeTo(null); - addTestWindow(frame); + return main; } private static JTextComponent configurePlainText(String instructions, @@ -434,6 +515,22 @@ public interface WindowListCreator { List createTestUI(); } + /** + * Creates a component (panel) with test UI + * to be hosted in a split pane or a frame. + */ + @FunctionalInterface + public interface PanelCreator { + /** + * Creates a component which hosts test UI. This component + * is placed into a split pane or into a frame to display the UI. + *

+ * This method is called by the framework on the EDT. + * @return a component (panel) with test UI + */ + JComponent createUIPanel(); + } + /** * Positions test UI windows. */ @@ -636,10 +733,12 @@ private static void captureScreen(CaptureType type) { break; case WINDOWS: - windowList.stream() - .filter(Window::isShowing) - .map(Window::getBounds) - .forEach(PassFailJFrame::captureScreen); + synchronized (PassFailJFrame.class) { + windowList.stream() + .filter(Window::isShowing) + .map(Window::getBounds) + .forEach(PassFailJFrame::captureScreen); + } break; default: @@ -952,6 +1051,9 @@ public static final class Builder { private List testWindows; private WindowListCreator windowListCreator; + private PanelCreator panelCreator; + private boolean splitUI; + private int splitUIOrientation; private PositionWindows positionWindows; private InstructionUI instructionUIHandler; @@ -1092,8 +1194,102 @@ private void checkWindowsLists() { } } - public Builder positionTestUI(PositionWindows positionWindows) { - this.positionWindows = positionWindows; + /** + * Adds a {@code PanelCreator} which the framework will use + * to create a component and place it into a dialog. + * + * @param panelCreator a {@code PanelCreator} to create a component + * with test UI + * @return this builder + * @throws IllegalStateException if split UI was enabled using + * a {@code splitUI} method + */ + public Builder testUI(PanelCreator panelCreator) { + if (splitUI) { + throw new IllegalStateException("Can't combine splitUI and " + + "testUI with panelCreator"); + } + this.panelCreator = panelCreator; + return this; + } + + /** + * Adds a {@code PanelCreator} which the framework will use + * to create a component with test UI and display it in a split pane. + *

+ * By default, horizontal orientation is used, + * and test UI is displayed to the right of the instruction UI. + * + * @param panelCreator a {@code PanelCreator} to create a component + * with test UI + * @return this builder + * + * @throws IllegalStateException if a {@code PanelCreator} is + * already set + * @throws IllegalArgumentException if {panelCreator} is {@code null} + */ + public Builder splitUI(PanelCreator panelCreator) { + return splitUIRight(panelCreator); + } + + /** + * Adds a {@code PanelCreator} which the framework will use + * to create a component with test UI and display it + * to the right of instruction UI. + * + * @param panelCreator a {@code PanelCreator} to create a component + * with test UI + * @return this builder + * + * @throws IllegalStateException if a {@code PanelCreator} is + * already set + * @throws IllegalArgumentException if {panelCreator} is {@code null} + */ + public Builder splitUIRight(PanelCreator panelCreator) { + return splitUI(panelCreator, JSplitPane.HORIZONTAL_SPLIT); + } + + /** + * Adds a {@code PanelCreator} which the framework will use + * to create a component with test UI and display it + * in the bottom of instruction UI. + * + * @param panelCreator a {@code PanelCreator} to create a component + * with test UI + * @return this builder + * + * @throws IllegalStateException if a {@code PanelCreator} is + * already set + * @throws IllegalArgumentException if {panelCreator} is {@code null} + */ + public Builder splitUIBottom(PanelCreator panelCreator) { + return splitUI(panelCreator, JSplitPane.VERTICAL_SPLIT); + } + + /** + * Enables split UI and stores the orientation of the split pane. + * + * @param panelCreator a {@code PanelCreator} to create a component + * with test UI + * @param splitUIOrientation orientation of the split pane + * @return this builder + * + * @throws IllegalStateException if a {@code PanelCreator} is + * already set + * @throws IllegalArgumentException if {panelCreator} is {@code null} + */ + private Builder splitUI(PanelCreator panelCreator, + int splitUIOrientation) { + if (panelCreator == null) { + throw new IllegalArgumentException("A PanelCreator cannot be null"); + } + if (this.panelCreator != null) { + throw new IllegalStateException("A PanelCreator is already set"); + } + + splitUI = true; + this.splitUIOrientation = splitUIOrientation; + this.panelCreator = panelCreator; return this; } @@ -1131,7 +1327,8 @@ private void validate() { } if (position == null - && (testWindows != null || windowListCreator != null)) { + && (testWindows != null || windowListCreator != null + || (!splitUI && panelCreator != null))) { position = Position.HORIZONTAL; } @@ -1139,7 +1336,7 @@ private void validate() { if (positionWindows != null) { if (testWindows == null && windowListCreator == null) { throw new IllegalStateException("To position windows, " - + "provide an a list of windows to the builder"); + + "provide a list of windows to the builder"); } instructionUIHandler = new InstructionUIHandler(); } @@ -1178,6 +1375,11 @@ public Position getPosition() { } } + /** + * Creates a builder for configuring {@code PassFailJFrame}. + * + * @return the builder for configuring {@code PassFailJFrame} + */ public static Builder builder() { return new Builder(); } diff --git a/test/jdk/java/foreign/TestMismatch.java b/test/jdk/java/foreign/TestMismatch.java index ed0faeef0e7..a33eab9a7fa 100644 --- a/test/jdk/java/foreign/TestMismatch.java +++ b/test/jdk/java/foreign/TestMismatch.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as @@ -24,6 +24,7 @@ /* * @test * @enablePreview + * @bug 8323552 * @run testng TestMismatch */ @@ -45,7 +46,7 @@ public class TestMismatch { - // stores a increasing sequence of values into the memory of the given segment + // stores an increasing sequence of values into the memory of the given segment static MemorySegment initializeSegment(MemorySegment segment) { for (int i = 0 ; i < segment.byteSize() ; i++) { segment.set(ValueLayout.JAVA_BYTE, i, (byte)i); @@ -279,6 +280,32 @@ public void testThreadAccess() throws Exception { } } + @Test + public void testSameSegment() { + var segment = MemorySegment.ofArray(new byte[]{ + 1,2,3,4, 1,2,3,4, 1,4}); + + long match = MemorySegment.mismatch( + segment, 0L, 4L, + segment, 4L, 8L); + assertEquals(match, -1); + + long noMatch = MemorySegment.mismatch( + segment, 0L, 4L, + segment, 1L, 5L); + assertEquals(noMatch, 0); + + long noMatchEnd = MemorySegment.mismatch( + segment, 0L, 2L, + segment, 8L, 10L); + assertEquals(noMatchEnd, 1); + + long same = MemorySegment.mismatch( + segment, 0L, 8L, + segment, 0L, 8L); + assertEquals(same, -1); + } + enum SegmentKind { NATIVE(i -> Arena.ofAuto().allocate(i, 1)), ARRAY(i -> MemorySegment.ofArray(new byte[i])); diff --git a/test/jdk/java/io/ByteArrayOutputStream/WriteToReleasesCarrier.java b/test/jdk/java/io/ByteArrayOutputStream/WriteToReleasesCarrier.java new file mode 100644 index 00000000000..c0607fd9494 --- /dev/null +++ b/test/jdk/java/io/ByteArrayOutputStream/WriteToReleasesCarrier.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8330748 + * @summary Test ByteArrayOutputStream.writeTo releases carrier thread + * @requires vm.continuations + * @modules java.base/java.lang:+open + * @run main WriteToReleasesCarrier + */ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.lang.reflect.Constructor; +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.LockSupport; + +public class WriteToReleasesCarrier { + public static void main(String[] args) throws Exception { + byte[] bytes = "Hello".getBytes(StandardCharsets.UTF_8); + + var baos = new ByteArrayOutputStream(); + baos.write(bytes); + + var target = new ParkingOutputStream(); + + try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) { + Thread.Builder builder = virtualThreadBuilder(scheduler); + var started = new CountDownLatch(1); + var vthread1 = builder.start(() -> { + started.countDown(); + try { + baos.writeTo(target); + } catch (IOException ioe) { } + }); + try { + started.await(); + await(vthread1, Thread.State.WAITING); + + // carrier should be released, use it for another thread + var executed = new AtomicBoolean(); + var vthread2 = builder.start(() -> { + executed.set(true); + }); + vthread2.join(); + if (!executed.get()) { + throw new RuntimeException("Second virtual thread did not run"); + } + } finally { + LockSupport.unpark(vthread1); + vthread1.join(); + } + } + + if (!Arrays.equals(target.toByteArray(), bytes)) { + throw new RuntimeException("Expected bytes not written"); + } + } + + /** + * Waits for a thread to get to the expected state. + */ + private static void await(Thread thread, Thread.State expectedState) throws Exception { + Thread.State state = thread.getState(); + while (state != expectedState) { + Thread.sleep(10); + state = thread.getState(); + } + } + + /** + * An OutputStream that parks when writing. + */ + static class ParkingOutputStream extends OutputStream { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + @Override + public void write(int i) { + LockSupport.park(); + baos.write(i); + } + + @Override + public void write(byte[] b, int off, int len) { + LockSupport.park(); + baos.write(b, off, len); + } + + byte[] toByteArray() { + return baos.toByteArray(); + } + } + + /** + * Returns a builder to create virtual threads that use the given scheduler. + */ + static Thread.Builder.OfVirtual virtualThreadBuilder(Executor scheduler) throws Exception { + Class clazz = Class.forName("java.lang.ThreadBuilders$VirtualThreadBuilder"); + Constructor ctor = clazz.getDeclaredConstructor(Executor.class); + ctor.setAccessible(true); + return (Thread.Builder.OfVirtual) ctor.newInstance(scheduler); + } +} diff --git a/test/jdk/java/io/Serializable/concurrentClassDescLookup/ConcurrentClassDescLookup.java b/test/jdk/java/io/Serializable/concurrentClassDescLookup/ConcurrentClassDescLookup.java index 48cbd1b0ffe..196a27b52ba 100644 --- a/test/jdk/java/io/Serializable/concurrentClassDescLookup/ConcurrentClassDescLookup.java +++ b/test/jdk/java/io/Serializable/concurrentClassDescLookup/ConcurrentClassDescLookup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ */ import java.io.*; +import java.util.concurrent.CountDownLatch; class Good implements Serializable { private static final long serialVersionUID = 6319710844400051132L; @@ -51,19 +52,20 @@ class Bad implements Serializable { class SuccessfulLookup extends Thread { Class cl; long suid; - Object barrier; + final CountDownLatch lookupLatch; boolean ok; - SuccessfulLookup(Class cl, long suid, Object barrier) { + SuccessfulLookup(Class cl, long suid, CountDownLatch lookupLatch) { this.cl = cl; this.suid = suid; - this.barrier = barrier; + this.lookupLatch = lookupLatch; } public void run() { - synchronized (barrier) { - try { barrier.wait(); } catch (InterruptedException ex) {} - } + lookupLatch.countDown(); // let others know we are ready + try { + lookupLatch.await(); // await for others + } catch (InterruptedException ex) {} for (int i = 0; i < 100; i++) { if (ObjectStreamClass.lookup(cl).getSerialVersionUID() != suid) { return; @@ -75,18 +77,19 @@ public void run() { class FailingLookup extends Thread { Class cl; - final Object barrier; + final CountDownLatch lookupLatch; boolean ok; - FailingLookup(Class cl, Object barrier) { + FailingLookup(Class cl, CountDownLatch lookupLatch) { this.cl = cl; - this.barrier = barrier; + this.lookupLatch = lookupLatch; } public void run() { - synchronized (barrier) { - try { barrier.wait(); } catch (InterruptedException ex) {} - } + lookupLatch.countDown(); // let others know we are ready + try { + lookupLatch.await(); // await for others + } catch (InterruptedException ex) {} for (int i = 0; i < 100; i++) { try { ObjectStreamClass.lookup(cl); @@ -102,39 +105,36 @@ public class ConcurrentClassDescLookup { public static void main(String[] args) throws Exception { ClassLoader loader = ConcurrentClassDescLookup.class.getClassLoader(); Class cl = Class.forName("Good", false, loader); - Object barrier = new Object(); - SuccessfulLookup[] slookups = new SuccessfulLookup[50]; + int numSuccessfulLookups = 50; + CountDownLatch sLookupLatch = new CountDownLatch(numSuccessfulLookups); + SuccessfulLookup[] slookups = new SuccessfulLookup[numSuccessfulLookups]; for (int i = 0; i < slookups.length; i++) { - slookups[i] = - new SuccessfulLookup(cl, 6319710844400051132L, barrier); + slookups[i] = new SuccessfulLookup(cl, 6319710844400051132L, sLookupLatch); slookups[i].start(); } - Thread.sleep(1000); - synchronized (barrier) { - barrier.notifyAll(); - } + System.out.println("awaiting completion of " + slookups.length + " SuccessfulLookup"); for (int i = 0; i < slookups.length; i++) { slookups[i].join(); if (!slookups[i].ok) { throw new Error(); } } - + System.out.println("all " + slookups.length + " SuccessfulLookup completed"); cl = Class.forName("Bad", false, loader); - FailingLookup[] flookups = new FailingLookup[50]; + int numFailingLookups = 50; + CountDownLatch fLookupLatch = new CountDownLatch(numFailingLookups); + FailingLookup[] flookups = new FailingLookup[numFailingLookups]; for (int i = 0; i < flookups.length; i++) { - flookups[i] = new FailingLookup(cl, barrier); + flookups[i] = new FailingLookup(cl, fLookupLatch); flookups[i].start(); } - Thread.sleep(1000); - synchronized (barrier) { - barrier.notifyAll(); - } - for (int i = 0; i < slookups.length; i++) { + System.out.println("awaiting completion of " + flookups.length + " FailingLookup"); + for (int i = 0; i < flookups.length; i++) { flookups[i].join(); if (!flookups[i].ok) { throw new Error(); } } + System.out.println("all " + flookups.length + " FailingLookup completed"); } } diff --git a/test/jdk/java/lang/Thread/virtual/Reflection.java b/test/jdk/java/lang/Thread/virtual/Reflection.java index bfca37a5e43..4dd34e6c726 100644 --- a/test/jdk/java/lang/Thread/virtual/Reflection.java +++ b/test/jdk/java/lang/Thread/virtual/Reflection.java @@ -32,6 +32,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; @@ -146,15 +147,19 @@ void testInvokeStatic6() throws Exception { try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) { Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler); ThreadFactory factory = builder.factory(); + + var ready = new CountDownLatch(1); Thread vthread = factory.newThread(() -> { + ready.countDown(); try { parkMethod.invoke(null); // blocks } catch (Exception e) { } }); vthread.start(); + try { - // give thread time to be scheduled - Thread.sleep(100); + // wait for thread to run + ready.await(); // unpark with another virtual thread, runs on same carrier thread Thread unparker = factory.newThread(() -> LockSupport.unpark(vthread)); @@ -321,17 +326,27 @@ void testNewInstance6() throws Exception { try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) { Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler); ThreadFactory factory = builder.factory(); + + var ready = new CountDownLatch(1); Thread vthread = factory.newThread(() -> { + ready.countDown(); try { ctor.newInstance(); } catch (Exception e) { } }); vthread.start(); - Thread.sleep(100); // give thread time to be scheduled + try { + // wait for thread to run + ready.await(); - // unpark with another virtual thread, runs on same carrier thread - factory.newThread(() -> LockSupport.unpark(vthread)).start(); + // unpark with another virtual thread, runs on same carrier thread + Thread unparker = factory.newThread(() -> LockSupport.unpark(vthread)); + unparker.start(); + unparker.join(); + } finally { + LockSupport.unpark(vthread); // in case test fails + } } } diff --git a/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java b/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java index 91ea4b932ca..06aa479717b 100644 --- a/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java +++ b/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.FileStore; import java.nio.file.attribute.PosixFileAttributeView; import jdk.test.lib.compiler.CompilerUtils; @@ -47,6 +48,7 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import org.testng.SkipException; import static java.nio.file.attribute.PosixFilePermissions.*; import static jdk.test.lib.process.ProcessTools.*; @@ -207,15 +209,15 @@ private static boolean isWriteableDirectory(Path p) { @Test public void testDumpDirNotWritable() throws Exception { - if (!Files.getFileStore(Paths.get(".")) - .supportsFileAttributeView(PosixFileAttributeView.class)) { + FileStore fs; + try { + fs = Files.getFileStore(Paths.get(".")); + } catch (IOException e) { + throw new SkipException("WARNING: IOException occurred: " + e + ", Skipping testDumpDirNotWritable test."); + } + if (!fs.supportsFileAttributeView(PosixFileAttributeView.class)) { // No easy way to setup readonly directory without POSIX - // We would like to skip the test with a cause with - // throw new SkipException("Posix not supported"); - // but jtreg will report failure so we just pass the test - // which we can look at if jtreg changed its behavior - System.out.println("WARNING: POSIX is not supported. Skipping testDumpDirNotWritable test."); - return; + throw new SkipException("WARNING: POSIX is not supported. Skipping testDumpDirNotWritable test."); } Path testDir = Path.of("readOnly"); @@ -227,8 +229,7 @@ public void testDumpDirNotWritable() throws Exception { if (isWriteableDirectory(dumpDir)) { // Skipping the test: it's allowed to write into read-only directory // (e.g. current user is super user). - System.out.println("WARNING: The dump directory is writeable. Skipping testDumpDirNotWritable test."); - return; + throw new SkipException("WARNING: The dump directory is writeable. Skipping testDumpDirNotWritable test."); } ProcessBuilder pb = createLimitedTestJavaProcessBuilder( diff --git a/test/jdk/java/lang/management/ClassLoadingMXBean/TestVerboseClassLoading.java b/test/jdk/java/lang/management/ClassLoadingMXBean/TestVerboseClassLoading.java new file mode 100644 index 00000000000..c951578fac5 --- /dev/null +++ b/test/jdk/java/lang/management/ClassLoadingMXBean/TestVerboseClassLoading.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8338139 + * @summary Basic unit test of ClassLoadingMXBean.set/isVerbose() when + * related unified logging is enabled. + * + * @run main/othervm -Xlog:class+load=trace:file=vm.log TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=debug:file=vm.log TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=info:file=vm.log TestVerboseClassLoading false + * + * @run main/othervm -Xlog:class+load=trace TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=debug TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=info TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=warning TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=error TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=off TestVerboseClassLoading false + * + * @run main/othervm -Xlog:class+load*=trace TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=debug TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=info TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=warning TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load*=error TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load*=off TestVerboseClassLoading false + * + * @run main/othervm -Xlog:class+load*=info,class+load=trace TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=info,class+load=debug TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=info,class+load=info TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=info,class+load=warning TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load*=info,class+load=error TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load*=info,class+load=off TestVerboseClassLoading false + * + * @run main/othervm -Xlog:all=trace:file=vm.log TestVerboseClassLoading false + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.ClassLoadingMXBean; + +public class TestVerboseClassLoading { + + public static void main(String[] args) throws Exception { + ClassLoadingMXBean mxBean = ManagementFactory.getClassLoadingMXBean(); + boolean expected = Boolean.parseBoolean(args[0]); + boolean initial = mxBean.isVerbose(); + if (expected != initial) { + throw new Error("Initial verbosity setting was unexpectedly " + initial); + } + mxBean.setVerbose(false); + if (mxBean.isVerbose()) { + throw new Error("Verbosity was still enabled"); + } + mxBean.setVerbose(true); + if (!mxBean.isVerbose()) { + throw new Error("Verbosity was still disabled"); + } + // Turn off again as a double-check and also to avoid excessive logging + mxBean.setVerbose(false); + if (mxBean.isVerbose()) { + throw new Error("Verbosity was still enabled"); + } + } +} diff --git a/test/jdk/java/lang/management/MemoryMXBean/TestVerboseMemory.java b/test/jdk/java/lang/management/MemoryMXBean/TestVerboseMemory.java new file mode 100644 index 00000000000..7d34c45036b --- /dev/null +++ b/test/jdk/java/lang/management/MemoryMXBean/TestVerboseMemory.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8338139 + * @summary Basic unit test of TestVerboseMemory.set/isVerbose() when + * related unified logging is enabled. + * + * @run main/othervm -Xlog:gc=trace:file=vm.log TestVerboseMemory false + * @run main/othervm -Xlog:gc=debug:file=vm.log TestVerboseMemory false + * @run main/othervm -Xlog:gc=info:file=vm.log TestVerboseMemory false + * + * @run main/othervm -Xlog:gc=off TestVerboseMemory false + * @run main/othervm -Xlog:gc=error TestVerboseMemory false + * @run main/othervm -Xlog:gc=warning TestVerboseMemory false + * + * @run main/othervm -Xlog:gc=info TestVerboseMemory true + * @run main/othervm -Xlog:gc=trace TestVerboseMemory true + * @run main/othervm -Xlog:gc=debug TestVerboseMemory true + * + * @run main/othervm -Xlog:gc*=info TestVerboseMemory true + * @run main/othervm -Xlog:gc*=debug TestVerboseMemory true + * @run main/othervm -Xlog:gc*=trace TestVerboseMemory true + * + * @run main/othervm -Xlog:gc=info,gc+init=off TestVerboseMemory true + * @run main/othervm -Xlog:gc=off,gc+init=info TestVerboseMemory false + * @run main/othervm -Xlog:gc,gc+init TestVerboseMemory true + * + * @run main/othervm -Xlog:all=trace:file=vm.log TestVerboseMemory false + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; + +public class TestVerboseMemory { + + public static void main(String[] args) throws Exception { + MemoryMXBean mxBean = ManagementFactory.getMemoryMXBean(); + boolean expected = Boolean.parseBoolean(args[0]); + boolean initial = mxBean.isVerbose(); + if (expected != initial) { + throw new Error("Initial verbosity setting was unexpectedly " + initial); + } + mxBean.setVerbose(false); + if (mxBean.isVerbose()) { + throw new Error("Verbosity was still enabled"); + } + mxBean.setVerbose(true); + if (!mxBean.isVerbose()) { + throw new Error("Verbosity was still disabled"); + } + // Turn off again as a double-check and also to avoid excessive logging + mxBean.setVerbose(false); + if (mxBean.isVerbose()) { + throw new Error("Verbosity was still enabled"); + } + } +} diff --git a/test/jdk/java/net/MulticastSocket/IPMulticastIF.java b/test/jdk/java/net/MulticastSocket/IPMulticastIF.java index 566e3603fa6..3909f6d6276 100644 --- a/test/jdk/java/net/MulticastSocket/IPMulticastIF.java +++ b/test/jdk/java/net/MulticastSocket/IPMulticastIF.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,9 +63,25 @@ public Object[][] positive() throws Exception { InetAddress.getLoopbackAddress()); List list = new ArrayList<>(); NetworkConfiguration nc = NetworkConfiguration.probe(); + // retains only network interface whose bound addresses match addrs.stream().forEach(a -> nc.multicastInterfaces(true) - .map(nif -> new Object[] { new InetSocketAddress(a, 0), nif }) - .forEach(list::add) ); + .filter(nif -> nif.inetAddresses().toList().contains(a)) + .map(nif -> new Object[] { new InetSocketAddress(a, 0), nif }) + .forEach(list::add) ); + // any network interface should work with the wildcard address + nc.multicastInterfaces(true) + .map(nif -> new Object[] {new InetSocketAddress(0), nif}) + .forEach(list::add); + return list.stream().toArray(Object[][]::new); + } + + @DataProvider(name = "interfaces") + public Object[][] interfaces() throws Exception { + List list = new ArrayList<>(); + NetworkConfiguration nc = NetworkConfiguration.probe(); + nc.multicastInterfaces(true) + .map(nif -> new Object[] {nif}) + .forEach(list::add); return list.stream().toArray(Object[][]::new); } @@ -82,8 +98,8 @@ public void testSetGetInterfaceBound(InetSocketAddress bindAddr, NetworkInterfac } } - @Test(dataProvider = "scenarios") - public void testSetGetInterfaceUnbound(InetSocketAddress ignore, NetworkInterface nif) + @Test(dataProvider = "interfaces") + public void testSetGetInterfaceUnbound(NetworkInterface nif) throws Exception { out.println(format("\n\n--- testSetGetInterfaceUnbound nif=[%s]", nif)); @@ -106,8 +122,8 @@ public void testSetGetOptionBound(InetSocketAddress bindAddr, NetworkInterface n } } - @Test(dataProvider = "scenarios") - public void testSetGetOptionUnbound(InetSocketAddress ignore, NetworkInterface nif) + @Test(dataProvider = "interfaces") + public void testSetGetOptionUnbound(NetworkInterface nif) throws Exception { out.println(format("\n\n--- testSetGetOptionUnbound nif=[%s]", nif)); @@ -139,8 +155,8 @@ public void testGetInterfaceBound(InetSocketAddress bindAddr) } @Test - public void testGettInterfaceUnbound() throws Exception { - out.println("\n\n--- testGettInterfaceUnbound "); + public void testGetInterfaceUnbound() throws Exception { + out.println("\n\n--- testGetInterfaceUnbound "); try (MulticastSocket ms = new MulticastSocket()) { assertPlaceHolder(ms.getNetworkInterface()); } diff --git a/test/jdk/java/net/httpclient/ForbiddenHeadTest.java b/test/jdk/java/net/httpclient/ForbiddenHeadTest.java index 0c39b44d7f5..1498aa118b3 100644 --- a/test/jdk/java/net/httpclient/ForbiddenHeadTest.java +++ b/test/jdk/java/net/httpclient/ForbiddenHeadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -205,18 +205,18 @@ static final void printFailedTests(ITestContext context) { @DataProvider(name = "all") public Object[][] allcases() { List result = new ArrayList<>(); - for (var client : List.of(authClient, noAuthClient)) { + for (boolean useAuth : List.of(true, false)) { for (boolean async : List.of(true, false)) { for (int code : List.of(UNAUTHORIZED, PROXY_UNAUTHORIZED)) { var srv = code == PROXY_UNAUTHORIZED ? "/proxy" : "/server"; for (var auth : List.of("/auth", "/noauth")) { var pcode = code; if (auth.equals("/noauth")) { - if (client == authClient) continue; + if (useAuth) continue; pcode = FORBIDDEN; } for (var uri : List.of(httpURI, httpsURI, http2URI, https2URI)) { - result.add(new Object[]{uri + srv + auth, pcode, async, client}); + result.add(new Object[]{uri + srv + auth, pcode, async, useAuth}); } } } @@ -237,12 +237,13 @@ protected PasswordAuthentication getPasswordAuthentication() { static final AtomicLong sleepCount = new AtomicLong(); @Test(dataProvider = "all") - void test(String uriString, int code, boolean async, HttpClient client) throws Throwable { + void test(String uriString, int code, boolean async, boolean useAuth) throws Throwable { checkSkip(); + HttpClient client = useAuth ? authClient : noAuthClient; var name = String.format("test(%s, %d, %s, %s)", uriString, code, async ? "async" : "sync", client.authenticator().isPresent() ? "authClient" : "noAuthClient"); out.printf("%n---- starting %s ----%n", name); - assert client.authenticator().isPresent() ? client == authClient : client == noAuthClient; + assert client.authenticator().isPresent() == useAuth; uriString = uriString + "/ForbiddenTest"; for (int i=0; i 1) out.printf("---- ITERATION %d%n",i); @@ -380,14 +381,17 @@ public void setup() throws Exception { public void teardown() throws Exception { authClient = noAuthClient = null; Thread.sleep(100); - AssertionError fail = TRACKER.check(500); - - proxy.stop(); - authproxy.stop(); - httpTestServer.stop(); - httpsTestServer.stop(); - http2TestServer.stop(); - https2TestServer.stop(); + AssertionError fail = TRACKER.check(1500); + try { + proxy.stop(); + authproxy.stop(); + httpTestServer.stop(); + httpsTestServer.stop(); + http2TestServer.stop(); + https2TestServer.stop(); + } finally { + if (fail != null) throw fail; + } } static class TestProxySelector extends ProxySelector { diff --git a/test/jdk/java/net/httpclient/ProxySelectorTest.java b/test/jdk/java/net/httpclient/ProxySelectorTest.java index bb3ddc84017..fd8f85fa6d7 100644 --- a/test/jdk/java/net/httpclient/ProxySelectorTest.java +++ b/test/jdk/java/net/httpclient/ProxySelectorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -377,15 +377,18 @@ public void teardown() throws Exception { client = null; Thread.sleep(100); AssertionError fail = TRACKER.check(500); - - proxy.stop(); - authproxy.stop(); - httpTestServer.stop(); - proxyHttpTestServer.stop(); - authProxyHttpTestServer.stop(); - httpsTestServer.stop(); - http2TestServer.stop(); - https2TestServer.stop(); + try { + proxy.stop(); + authproxy.stop(); + httpTestServer.stop(); + proxyHttpTestServer.stop(); + authProxyHttpTestServer.stop(); + httpsTestServer.stop(); + http2TestServer.stop(); + https2TestServer.stop(); + } finally { + if (fail != null) throw fail; + } } class TestProxySelector extends ProxySelector { diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLTubeTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLTubeTest.java index ac251f9ba7d..114110344a4 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLTubeTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/SSLTubeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -85,16 +85,17 @@ private static class SSLLoopbackSubscriber implements FlowTube { ExecutorService exec, CountDownLatch allBytesReceived) throws IOException { SSLServerSocketFactory fac = ctx.getServerSocketFactory(); + InetAddress loopback = InetAddress.getLoopbackAddress(); SSLServerSocket serv = (SSLServerSocket) fac.createServerSocket(); serv.setReuseAddress(false); - serv.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + serv.bind(new InetSocketAddress(loopback, 0)); SSLParameters params = serv.getSSLParameters(); params.setApplicationProtocols(new String[]{"proto2"}); serv.setSSLParameters(params); int serverPort = serv.getLocalPort(); - clientSock = new Socket("localhost", serverPort); + clientSock = new Socket(loopback, serverPort); serverSock = (SSLSocket) serv.accept(); this.buffer = new LinkedBlockingQueue<>(); this.allBytesReceived = allBytesReceived; @@ -107,6 +108,7 @@ private static class SSLLoopbackSubscriber implements FlowTube { } public void start() { + System.out.println("Starting: server listening at: " + serverSock.getLocalSocketAddress()); thread1.start(); thread2.start(); thread3.start(); @@ -144,6 +146,7 @@ private void clientReader() { publisher.submit(List.of(bb)); } } catch (Throwable e) { + System.out.println("clientReader got exception: " + e); e.printStackTrace(); Utils.close(clientSock); } @@ -176,6 +179,7 @@ private void clientWriter() { clientSubscription.request(1); } } catch (Throwable e) { + System.out.println("clientWriter got exception: " + e); e.printStackTrace(); } } @@ -212,6 +216,7 @@ private void serverLoopback() { is.close(); os.close(); serverSock.close(); + System.out.println("serverLoopback exiting normally"); return; } os.write(bb, 0, n); @@ -219,7 +224,10 @@ private void serverLoopback() { loopCount.addAndGet(n); } } catch (Throwable e) { + System.out.println("serverLoopback got exception: " + e); e.printStackTrace(); + } finally { + System.out.println("serverLoopback exiting at count: " + loopCount.get()); } } diff --git a/test/jdk/java/nio/channels/AsyncCloseAndInterrupt.java b/test/jdk/java/nio/channels/AsyncCloseAndInterrupt.java index e88a874b82b..205454ca0cd 100644 --- a/test/jdk/java/nio/channels/AsyncCloseAndInterrupt.java +++ b/test/jdk/java/nio/channels/AsyncCloseAndInterrupt.java @@ -129,6 +129,7 @@ private static void initFile() throws Exception { return; } fifoFile = new File("x.fifo"); + fifoFile.deleteOnExit(); if (fifoFile.exists()) { if (!fifoFile.delete()) throw new IOException("Cannot delete existing fifo " + fifoFile); diff --git a/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java b/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java index 1ba742b6552..cdc5882fefd 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Disconnect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.nio.*; import java.nio.channels.*; import java.io.IOException; + import jdk.test.lib.net.IPSupport; public class Disconnect { @@ -42,43 +43,61 @@ public static void main(String[] args) throws IOException { // test with default protocol family try (DatagramChannel dc = DatagramChannel.open()) { - test(dc); - test(dc); + InetAddress lo = InetAddress.getLoopbackAddress(); + System.out.println("Testing with default family and " + lo); + test(dc, lo); + test(dc, lo); } if (IPSupport.hasIPv4()) { // test with IPv4 only try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) { - test(dc); - test(dc); + InetAddress lo4 = InetAddress.ofLiteral("127.0.0.1"); + System.out.println("Testing with INET family and " + lo4); + test(dc, lo4); + test(dc, lo4); } } if (IPSupport.hasIPv6()) { // test with IPv6 only try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET6)) { - test(dc); - test(dc); + InetAddress lo6 = InetAddress.ofLiteral("::1"); + System.out.println("Testing with INET6 family and " + lo6); + test(dc, lo6); + test(dc, lo6); } } } + static int getLocalPort(DatagramChannel ch) throws IOException { + return ((InetSocketAddress) ch.getLocalAddress()).getPort(); + } + /** * Connect DatagramChannel to a server, write a datagram and disconnect. Invoke * a second or subsequent time with the same DatagramChannel instance to check * that disconnect works as expected. */ - static void test(DatagramChannel dc) throws IOException { + static void test(DatagramChannel dc, InetAddress lo) throws IOException { try (DatagramChannel server = DatagramChannel.open()) { - server.bind(new InetSocketAddress(0)); + server.bind(new InetSocketAddress(lo, 0)); - InetAddress lh = InetAddress.getLocalHost(); - dc.connect(new InetSocketAddress(lh, server.socket().getLocalPort())); + SocketAddress dcbound = dc.getLocalAddress(); + dc.connect(new InetSocketAddress(lo, server.socket().getLocalPort())); + System.out.println("dc bound to " + dcbound + " and connected from " + + dc.getLocalAddress() + " to " + dc.getRemoteAddress()); dc.write(ByteBuffer.wrap("hello".getBytes())); - ByteBuffer bb = ByteBuffer.allocate(100); - server.receive(bb); + if (getLocalPort(dc) != getLocalPort(server)) { + ByteBuffer bb = ByteBuffer.allocate(100); + server.receive(bb); + } else { + // some systems may allow dc and server to bind to the same port. + // when that happen the datagram may never be received + System.out.println("Server and clients are bound to the same port: skipping receive"); + } dc.disconnect(); diff --git a/test/jdk/java/nio/channels/DatagramChannel/Loopback.java b/test/jdk/java/nio/channels/DatagramChannel/Loopback.java index a61a4d0b177..5562378b83f 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Loopback.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Loopback.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,7 +118,8 @@ static void test(ProtocolFamily family, InetAddress group, NetworkInterface ni) // send datagram to multicast group System.out.format("send %s -> %s%n", dc.getLocalAddress(), target); - ByteBuffer src = ByteBuffer.wrap("hello".getBytes("UTF-8")); + String str = "hello " + System.nanoTime(); + ByteBuffer src = ByteBuffer.wrap(str.getBytes("UTF-8")); dc.send(src, target); // receive datagram sent to multicast group @@ -142,6 +143,7 @@ static void test(ProtocolFamily family, InetAddress group, NetworkInterface ni) System.out.format("send %s -> %s%n", dc.getLocalAddress(), target); src.clear(); dc.send(src, target); + src.flip(); // test that we don't receive the datagram sent to multicast group dc.configureBlocking(false); @@ -157,10 +159,16 @@ static void test(ProtocolFamily family, InetAddress group, NetworkInterface ni) } else { sel.selectedKeys().clear(); SocketAddress sender = dc.receive(dst); + if (src.mismatch(dst) != -1) { + System.out.println("src: " + src + "not equal to dst: " + dst); + dst.clear(); + continue; + } if (sender != null) { System.out.format("received %s from %s%n", dst, sender); senderPort = ((InetSocketAddress) sender).getPort(); - assertTrue(senderPort != localPort, "Unexpected message"); + assertTrue(senderPort != localPort, + "Unexpected message: localPort=" + localPort); } } } diff --git a/test/jdk/java/nio/channels/DatagramChannel/StressNativeSignal.java b/test/jdk/java/nio/channels/DatagramChannel/StressNativeSignal.java index b21d68ab1a9..d6d2f083eca 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, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,68 +26,111 @@ * @summary Attempt to provoke error 316 on OS X in NativeSignal.signal() */ -import java.io.*; -import java.net.*; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.StandardSocketOptions; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; +import java.util.concurrent.CountDownLatch; public class StressNativeSignal { private UDPThread udpThread; private ServerSocketThread serverSocketThread; StressNativeSignal() { - try { - serverSocketThread = new ServerSocketThread(); + serverSocketThread = initServerSocketThread(); + if (serverSocketThread != null) { serverSocketThread.start(); + } - udpThread = new UDPThread(); + udpThread = initUDPThread(); + if (udpThread != null) { 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; } - public static void main(String[] args) throws Throwable { - StressNativeSignal test = new StressNativeSignal(); + private ServerSocketThread initServerSocketThread() { + ServerSocketThread aServerSocketThread = null; try { - Thread.sleep(3000); + aServerSocketThread = new ServerSocketThread(); + } catch (Exception z) { - z.printStackTrace(System.err); + System.err.println("failed to create and start a ServerSocketThread"); + z.printStackTrace(); } + return aServerSocketThread; + } + public static void main(String[] args) throws Throwable { + StressNativeSignal test = new StressNativeSignal(); + test.waitForTestThreadsToStart(); test.shutdown(); } public void shutdown() { - udpThread.terminate(); - try { - udpThread.join(); - } catch (Exception z) { - z.printStackTrace(System.err); + if ((udpThread != null) && udpThread.isAlive()) { + udpThread.terminate(); + try { + udpThread.join(); + } catch (Exception z) { + z.printStackTrace(System.err); + } + } else { + System.out.println("UDPThread test scenario was not run"); } - serverSocketThread.terminate(); - try { - serverSocketThread.join(); - } catch (Exception z) { - z.printStackTrace(System.err); + if ((serverSocketThread != null) && (serverSocketThread.isAlive())) { + serverSocketThread.terminate(); + try { + serverSocketThread.join(); + } catch (Exception z) { + z.printStackTrace(System.err); + } + } else { + System.out.println("ServerSocketThread test scenario was not run"); + } + } + + public void waitForTestThreadsToStart() { + if ((udpThread != null) && udpThread.isAlive()) { + udpThread.waitTestThreadStart(); + } + if ((serverSocketThread != null) && (serverSocketThread.isAlive())) { + serverSocketThread.waitTestThreadStart(); } } public class ServerSocketThread extends Thread { private volatile boolean shouldTerminate; private ServerSocket socket; + private final CountDownLatch threadStarted = new CountDownLatch(1); + + public ServerSocketThread () throws Exception { + socket = new ServerSocket(1122); + } public void run() { + try { - socket = new ServerSocket(1122); + threadStarted.countDown(); Socket client = socket.accept(); - BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream())); - shouldTerminate = false; - while (!shouldTerminate) { - String msg = reader.readLine(); - } + client.close(); + throw new RuntimeException("Unexpected return from accept call"); } catch (Exception z) { + System.err.println("ServerSocketThread: caught exception " + z.getClass().getName()); if (!shouldTerminate) { z.printStackTrace(System.err); } @@ -103,40 +146,61 @@ public void terminate() { // ignore } } + + public void waitTestThreadStart() { + try { + threadStarted.await(); + } catch (Exception z) { + z.printStackTrace(System.err); + // ignore + } + } } public class UDPThread extends Thread { private DatagramChannel channel; private volatile boolean shouldTerminate; + private final CountDownLatch threadStarted = new CountDownLatch(1); + + public UDPThread () throws Exception { + + channel = DatagramChannel.open(); + channel.setOption(StandardSocketOptions.SO_RCVBUF, 6553600); + channel.bind(new InetSocketAddress(19870)); + } @Override public void run() { - try { - channel = DatagramChannel.open(); - channel.setOption(StandardSocketOptions.SO_RCVBUF, 6553600); - channel.bind(new InetSocketAddress(19870)); - } catch (IOException z) { - z.printStackTrace(System.err); - } ByteBuffer buf = ByteBuffer.allocate(6553600); - shouldTerminate = false; - while (!shouldTerminate) { + threadStarted.countDown(); + do { try { buf.rewind(); channel.receive(buf); } catch (IOException z) { + System.err.println("UDPThread: caught exception " + z.getClass().getName()); if (!shouldTerminate) { z.printStackTrace(System.err); } } - } + } while (!shouldTerminate); } public void terminate() { shouldTerminate = true; try { channel.close(); + } catch (Exception z) { + System.err.println("UDPThread: caught exception " + z.getClass().getName()); + z.printStackTrace(System.err); + // ignore + } + } + + public void waitTestThreadStart() { + try { + threadStarted.await(); } catch (Exception z) { z.printStackTrace(System.err); // ignore diff --git a/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java b/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java index db3c042275f..415e1e52aad 100644 --- a/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java +++ b/test/jdk/java/nio/channels/FileChannel/BlockDeviceSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,41 +24,49 @@ /* @test * @bug 8054029 8313368 * @requires (os.family == "linux") - * @summary Block devices should not report size=0 on Linux - * @run main/manual BlockDeviceSize + * @summary FileChannel.size() should be equal to RandomAccessFile.size() and > 0 for block devs on Linux + * @library /test/lib */ import java.io.RandomAccessFile; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.channels.FileChannel; import java.nio.file.AccessDeniedException; import java.nio.file.NoSuchFileException; +import java.util.List; + import static java.nio.file.StandardOpenOption.*; +import jtreg.SkippedException; public class BlockDeviceSize { - private static final String BLK_FNAME = "/dev/sda1"; - private static final Path BLK_PATH = Paths.get(BLK_FNAME); + private static final List BLK_FNAMES = List.of("/dev/sda1", "/dev/nvme0n1", "/dev/xvda1") ; public static void main(String[] args) throws Throwable { - try (FileChannel ch = FileChannel.open(BLK_PATH, READ); - RandomAccessFile file = new RandomAccessFile(BLK_FNAME, "r")) { + for (String blkFname: BLK_FNAMES) { + Path blkPath = Path.of(blkFname); + try (FileChannel ch = FileChannel.open(blkPath, READ); + RandomAccessFile file = new RandomAccessFile(blkFname, "r")) { + + long size1 = ch.size(); + long size2 = file.length(); + if (size1 != size2) { + throw new RuntimeException("size differs when retrieved" + + " in different ways: " + size1 + " != " + size2); + } + if (size1 <= 0) { + throw new RuntimeException("size() for a block device size returns zero or a negative value"); + } + System.out.println("OK"); - long size1 = ch.size(); - long size2 = file.length(); - if (size1 != size2) { - throw new RuntimeException("size differs when retrieved" + - " in different ways: " + size1 + " != " + size2); + } catch (NoSuchFileException nsfe) { + System.err.println("File " + blkFname + " not found." + + " Skipping test"); + } catch (AccessDeniedException ade) { + throw new SkippedException("Access to " + blkFname + " is denied." + + " Run test as root.", ade); } - System.out.println("OK"); - } catch (NoSuchFileException nsfe) { - System.err.println("File " + BLK_FNAME + " not found." + - " Skipping test"); - } catch (AccessDeniedException ade) { - throw new RuntimeException("Access to " + BLK_FNAME + " is denied." - + " Run test as root.", ade); } } } diff --git a/test/jdk/java/nio/channels/FileChannel/Transfer.java b/test/jdk/java/nio/channels/FileChannel/Transfer.java index 453230fff95..51adba60b06 100644 --- a/test/jdk/java/nio/channels/FileChannel/Transfer.java +++ b/test/jdk/java/nio/channels/FileChannel/Transfer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* @test - * @bug 4434723 4482726 4559072 4795550 5081340 5103988 6984545 + * @bug 4434723 4482726 4559072 4795550 5081340 5103988 6984545 8325382 * @summary Test FileChannel.transferFrom and transferTo (use -Dseed=X to set PRNG seed) * @library .. * @library /test/lib @@ -48,11 +48,13 @@ import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.channels.spi.SelectorProvider; +import java.nio.file.Files; import java.util.Random; import java.util.concurrent.TimeUnit; import jdk.test.lib.RandomFactory; +import org.testng.Assert; import org.testng.annotations.Test; public class Transfer { @@ -158,6 +160,33 @@ public void testReadableByteChannel() throws Exception { } } + @Test + public void transferToNoThrow() throws IOException { // for bug 8325382 + File source = File.createTempFile("before", "after"); + source.deleteOnExit(); + + CharSequence csq = "Reality is greater than the sum of its parts."; + Files.writeString(source.toPath(), csq); + final long length = csq.length(); + Assert.assertEquals(source.length(), length); + + File target = File.createTempFile("before", "after"); + target.deleteOnExit(); + + try (FileInputStream in = new FileInputStream(source); + FileOutputStream out = new FileOutputStream(target); + FileChannel chSource = in.getChannel(); + FileChannel chTarget = out.getChannel()) { + // The count of bytes requested to transfer must exceed + // FileChannelImpl.MAPPED_TRANSFER_THRESHOLD which is + // currently 16384 + long n = chSource.transferTo(length, 16385, chTarget); + + // At the end of the input so no bytes should be transferred + Assert.assertEquals(n, 0); + } + } + @Test public void xferTest02() throws Exception { // for bug 4482726 byte[] srcData = new byte[5000]; diff --git a/test/jdk/java/nio/channels/Selector/LotsOfInterrupts.java b/test/jdk/java/nio/channels/Selector/LotsOfInterrupts.java new file mode 100644 index 00000000000..98470dec160 --- /dev/null +++ b/test/jdk/java/nio/channels/Selector/LotsOfInterrupts.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=platform + * @bug 8323782 + * @summary Stress test Thread.interrupt on a target Thread doing a selection operation + * @run main LotsOfInterrupts 200000 + */ + +/* + * @test id=virtual + * @run main/othervm -DthreadFactory=virtual LotsOfInterrupts 200000 + */ + +import java.nio.channels.Selector; +import java.time.Instant; +import java.util.concurrent.Phaser; +import java.util.concurrent.ThreadFactory; + +public class LotsOfInterrupts { + + public static void main(String[] args) throws Exception { + int iterations; + if (args.length > 0) { + iterations = Integer.parseInt(args[0]); + } else { + iterations = 500_000; + } + + ThreadFactory factory; + String value = System.getProperty("threadFactory"); + if ("virtual".equals(value)) { + factory = Thread.ofVirtual().factory(); + } else { + factory = Thread.ofPlatform().factory(); + } + + var phaser = new Phaser(2); + + Thread thread = factory.newThread(() -> { + try (Selector sel = Selector.open()) { + for (int i = 0; i < iterations; i++) { + phaser.arriveAndAwaitAdvance(); + sel.select(); + + // clear interrupt status and consume wakeup + Thread.interrupted(); + sel.selectNow(); + } + } catch (Throwable ex) { + ex.printStackTrace(); + } + }); + thread.start(); + + long lastTimestamp = System.currentTimeMillis(); + for (int i = 0; i < iterations; i++) { + phaser.arriveAndAwaitAdvance(); + thread.interrupt(); + + long currentTime = System.currentTimeMillis(); + if ((currentTime - lastTimestamp) > 500) { + System.out.format("%s %d iterations remaining ...%n", Instant.now(), (iterations - i)); + lastTimestamp = currentTime; + } + } + + thread.join(); + } +} diff --git a/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java b/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java index 8d8673355ef..c7eed1f27a0 100644 --- a/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java +++ b/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,28 +25,110 @@ * @bug 6548464 * @summary SocketChannel.open(SocketAddress) leaks file descriptor if * connection cannot be established + * @requires vm.flagless * @build OpenLeak - * @run main/othervm -Djava.security.manager=allow OpenLeak + * @run junit/othervm OpenLeak */ +import java.io.IOException; +import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.nio.channels.SocketChannel; +import java.nio.channels.UnresolvedAddressException; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertThrows; + public class OpenLeak { - public static void main(String[] args) throws Exception { - InetAddress lh = InetAddress.getLocalHost(); - InetSocketAddress isa = new InetSocketAddress(lh, 12345); + static final String OS_NAME = System.getProperty("os.name").toLowerCase(Locale.ROOT); + static final boolean IS_WINDOWS_2016 = OS_NAME.contains("windows") && OS_NAME.contains("2016"); + + // On Windows Server 2016 trying to connect to port 47 consumes the + // whole connect timeout - which makes the test fail in timeout. + // We skip this part of the test on Windows Server 2016 + static final boolean TEST_WITH_RESERVED_PORT = !IS_WINDOWS_2016; + + private static final int MAX_LOOP = 250000; - System.setSecurityManager( new SecurityManager() ); - for (int i=0; i<100000; i++) { - try { - SocketChannel.open(isa); - throw new RuntimeException("This should not happen"); - } catch (SecurityException x) { } + + // Try to find a suitable port to provoke a "Connection Refused" + // error. + private static InetSocketAddress findSuitableRefusedAddress(InetSocketAddress isa) + throws IOException { + if (!TEST_WITH_RESERVED_PORT) return null; + var addr = isa.getAddress(); + try (SocketChannel sc1 = SocketChannel.open(isa)) { + // If we manage to connect, let's try to use some other + // port. + // port 51 is reserved too - there should be nothing there... + isa = new InetSocketAddress(addr, 51); + try (SocketChannel sc2 = SocketChannel.open(isa)) { + } + // OK, last attempt... + // port 61 is reserved too - there should be nothing there... + isa = new InetSocketAddress(addr, 61); + try (SocketChannel sc3 = SocketChannel.open(isa)) { + } + System.err.println("Could not find a suitable port"); + return null; + } catch (ConnectException x) { } + return isa; + } + + private static InetSocketAddress createUnresolved(InetSocketAddress isa, InetSocketAddress def) { + var sa = isa == null ? def : isa; + return InetSocketAddress.createUnresolved(sa.getHostString(), sa.getPort()); + } + + // Builds a list of test cases + static List testCases() throws Exception { + InetAddress lo = InetAddress.getLoopbackAddress(); + + // Try to find a suitable port that will cause a + // Connection Refused exception + // port 47 is reserved - there should be nothing there... + InetSocketAddress def = new InetSocketAddress(lo, 47); + InetSocketAddress isa = findSuitableRefusedAddress(def); + InetSocketAddress sa = createUnresolved(isa, def); + + final List cases = new ArrayList<>(); + cases.add(new Object[]{sa, UnresolvedAddressException.class}); + if (isa != null) { + cases.add(new Object[]{isa, ConnectException.class}); + } + return cases; + } + + @ParameterizedTest + @MethodSource("testCases") + public void test(SocketAddress sa, Class expectedException) throws Exception { + System.err.printf("%nExpecting %s for %s%n", expectedException, sa); + + int i = 0; + try { + for (i = 0; i < MAX_LOOP; i++) { + Throwable x = + assertThrows(expectedException, () -> SocketChannel.open(sa)); + if (i < 5 || i >= MAX_LOOP - 5) { + // print a message for the first five and last 5 exceptions + System.err.println(x); + } + } + } catch (Throwable t) { + System.err.println("Failed at " + i + " with " + t); + throw t; + } } } diff --git a/test/jdk/java/nio/charset/Charset/AliasesCopy.java b/test/jdk/java/nio/charset/Charset/AliasesCopy.java new file mode 100644 index 00000000000..66ee830c5f6 --- /dev/null +++ b/test/jdk/java/nio/charset/Charset/AliasesCopy.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * 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 8319817 + * @summary Check that aliases cannot be mutated + * @run junit AliasesCopy + */ + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.util.Set; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; + +public class AliasesCopy { + private static final Set ALIASES_SET = Set.of("foo-alias"); + private static final String[] ALIASES_ARRAY = ALIASES_SET.toArray(String[]::new); + + @Test + public void aliasesCopy() { + final FooCharset cs = new FooCharset(ALIASES_ARRAY); + ALIASES_ARRAY[0] = "bar-alias"; + assertIterableEquals(ALIASES_SET, cs.aliases()); + } + + private static final class FooCharset extends Charset { + private FooCharset(String[] aliases) { + super("foo", aliases); + } + + @Override + public CharsetEncoder newEncoder() { + throw new RuntimeException("not implemented"); + } + + @Override + public CharsetDecoder newDecoder() { + throw new RuntimeException("not implemented"); + } + + @Override + public boolean contains(Charset cs) { + throw new RuntimeException("not implemented"); + } + } +} diff --git a/test/jdk/java/nio/charset/StandardCharsets/Standard.java b/test/jdk/java/nio/charset/StandardCharsets/Standard.java index 44c4e86a4f6..4db24b1986a 100644 --- a/test/jdk/java/nio/charset/StandardCharsets/Standard.java +++ b/test/jdk/java/nio/charset/StandardCharsets/Standard.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. * 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,102 +23,123 @@ /* * @test - * @bug 4884238 - * @summary Test standard charset name constants. + * @bug 4884238 8310047 + * @summary Test standard charset name constants and class qualities. * @author Mike Duigou - * @run main Standard + * @run junit Standard */ import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.io.*; -import java.nio.charset.*; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; +import java.util.List; +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.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class Standard { - private final static String standardCharsets[] = { - "US-ASCII", "ISO-8859-1", "UTF-8", - "UTF-16BE", "UTF-16LE", "UTF-16" }; + // These are the charsets StandardCharsets.java is expected to contain. + private static final String[] expectedCharsets = { + "US-ASCII", "ISO-8859-1", "UTF-8", + "UTF-16BE", "UTF-16LE", "UTF-16" + }; - public static void realMain(String[] args) { - check(StandardCharsets.US_ASCII instanceof Charset); - check(StandardCharsets.ISO_8859_1 instanceof Charset); - check(StandardCharsets.UTF_8 instanceof Charset); - check(StandardCharsets.UTF_16BE instanceof Charset); - check(StandardCharsets.UTF_16LE instanceof Charset); - check(StandardCharsets.UTF_16 instanceof Charset); + private static final Field[] standardCharsetFields = + StandardCharsets.class.getFields(); - check("US-ASCII".equals(StandardCharsets.US_ASCII.name())); - check("ISO-8859-1".equals(StandardCharsets.ISO_8859_1.name())); - check("UTF-8".equals(StandardCharsets.UTF_8.name())); - check("UTF-16BE".equals(StandardCharsets.UTF_16BE.name())); - check("UTF-16LE".equals(StandardCharsets.UTF_16LE.name())); - check("UTF-16".equals(StandardCharsets.UTF_16.name())); + /** + * Validates that the Charset constants from the data provider + * are of type Charset. + */ + @ParameterizedTest + @MethodSource("charsetProvider") + public void typeTest(Charset charset) { + // Doubly checked, as it is validated when passed as a param + assertTrue(charset instanceof Charset); + } + + /** + * Validates that calling .name() on a Charset constant is equal + * to the matching String value from the data provider. + */ + @ParameterizedTest + @MethodSource("charsetProvider") + public void nameMethodTest(Charset charset, String charString) { + assertEquals(charset.name(), charString); + } - check(Charset.forName("US-ASCII") == StandardCharsets.US_ASCII); - check(Charset.forName("ISO-8859-1") == StandardCharsets.ISO_8859_1); - check(Charset.forName("UTF-8") == StandardCharsets.UTF_8); - check(Charset.forName("UTF-16BE") == StandardCharsets.UTF_16BE); - check(Charset.forName("UTF-16LE") == StandardCharsets.UTF_16LE); - check(Charset.forName("UTF-16") == StandardCharsets.UTF_16); + /** + * Validates that calling Charset.forName() on a String is equal + * to the matching Charset constant from the data provider. + */ + @ParameterizedTest + @MethodSource("charsetProvider") + public void forNameMethodTest(Charset charset, String charString) { + assertEquals(Charset.forName(charString), charset); + } - Set charsets = new HashSet<>(); - Field standardCharsetFields[] = StandardCharsets.class.getFields(); + /** + * Validates the qualities of a StandardCharsets field are as expected: + * The field is final, static, public, and one can access + * the underlying value of the field. + */ + @ParameterizedTest + @MethodSource("charsetFields") + public void charsetModifiersTest(Field charsetField) throws IllegalAccessException { + // Check modifiers + assertEquals(StandardCharsets.class, charsetField.getDeclaringClass()); + assertTrue(Modifier.isFinal(charsetField.getModifiers())); + assertTrue(Modifier.isStatic(charsetField.getModifiers())); + assertTrue(Modifier.isPublic(charsetField.getModifiers())); + // Check that the value can be accessed, and it is a Charset + Object valueOfField = charsetField.get(null); + assertTrue(valueOfField instanceof Charset); + } - for(Field charsetField : standardCharsetFields) { - check(StandardCharsets.class == charsetField.getDeclaringClass()); - check(Modifier.isFinal(charsetField.getModifiers())); - check(Modifier.isStatic(charsetField.getModifiers())); - check(Modifier.isPublic(charsetField.getModifiers())); - Object value; + /** + * Validates that the Charsets contained in StandardCharsets are equal + * to the expected Charsets list defined in the test. This test should fail if + * either the actual or expected (standard) Charsets are modified, and + * the others are not. + */ + @Test + public void correctCharsetsTest() { + // Grab the value from each Standard Charset field + List actualCharsets = charsetFields().map(field -> { try { - value = charsetField.get(null); - } catch(IllegalAccessException failure) { - unexpected(failure); - continue; + return ((Charset) field.get(null)).name(); + } catch (IllegalAccessException e) { + throw new RuntimeException("Can not test correctCharsetsTest() due to %s", e); } - check(value instanceof Charset); - charsets.add(((Charset)value).name()); - } - - check(charsets.containsAll(Arrays.asList(standardCharsets))); - charsets.removeAll(Arrays.asList(standardCharsets)); - check(charsets.isEmpty()); + }).toList(); + assertEquals(actualCharsets, Arrays.asList(expectedCharsets)); } - //--------------------- Infrastructure --------------------------- - static volatile int passed = 0, failed = 0; - static void pass() { passed++; } - static void fail() { failed++; Thread.dumpStack(); } - static void fail(String msg) { System.out.println(msg); fail(); } - static void unexpected(Throwable t) { failed++; t.printStackTrace(); } - static void check(boolean cond) { if (cond) pass(); else fail(); } - static void equal(Object x, Object y) { - if (x == null ? y == null : x.equals(y)) pass(); - else {System.out.println(x + " not equal to " + y); fail();}} - static void equal2(Object x, Object y) {equal(x, y); equal(y, x);} - public static void main(String[] args) throws Throwable { - try { realMain(args); } catch (Throwable t) { unexpected(t); } - - System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); - if (failed > 0) throw new Exception("Some tests failed"); + /** + * Provides the constant Charset and associated String value of + * the standard charsets. + */ + private static Stream charsetProvider() { + return Stream.of( + Arguments.of(StandardCharsets.US_ASCII, "US-ASCII"), + Arguments.of(StandardCharsets.ISO_8859_1, "ISO-8859-1"), + Arguments.of(StandardCharsets.UTF_8, "UTF-8"), + Arguments.of(StandardCharsets.UTF_16BE, "UTF-16BE"), + Arguments.of(StandardCharsets.UTF_16LE, "UTF-16LE"), + Arguments.of(StandardCharsets.UTF_16, "UTF-16") + ); } - static byte[] serializedForm(Object obj) { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - new ObjectOutputStream(baos).writeObject(obj); - return baos.toByteArray(); - } catch (IOException e) { throw new Error(e); }} - static Object readObject(byte[] bytes) - throws IOException, ClassNotFoundException { - InputStream is = new ByteArrayInputStream(bytes); - return new ObjectInputStream(is).readObject();} - @SuppressWarnings("unchecked") - static T serialClone(T obj) { - try { return (T) readObject(serializedForm(obj)); } - catch (Exception e) { throw new Error(e); }} + private static Stream charsetFields() { + return Arrays.stream(standardCharsetFields); + } } diff --git a/test/jdk/java/nio/file/Files/CopyAndMove.java b/test/jdk/java/nio/file/Files/CopyAndMove.java index d871b1873a4..7e819932188 100644 --- a/test/jdk/java/nio/file/Files/CopyAndMove.java +++ b/test/jdk/java/nio/file/Files/CopyAndMove.java @@ -22,7 +22,8 @@ */ /* @test - * @bug 4313887 6838333 6917021 7006126 6950237 8006645 8201407 8264744 8267820 + * @bug 4313887 6838333 6917021 7006126 6950237 8006645 8073061 8201407 8264744 + * 8267820 * @summary Unit test for java.nio.file.Files copy and move methods (use -Dseed=X to set PRNG seed) * @library .. /test/lib * @build jdk.test.lib.Platform jdk.test.lib.RandomFactory @@ -35,8 +36,8 @@ import java.nio.ByteBuffer; import java.nio.file.*; import static java.nio.file.Files.*; -import static java.nio.file.StandardCopyOption.*; import static java.nio.file.LinkOption.*; +import static java.nio.file.StandardCopyOption.*; import java.nio.file.attribute.*; import java.util.*; import java.util.concurrent.TimeUnit; @@ -814,6 +815,25 @@ static void testCopyFileToFile(Path dir1, Path dir2, boolean supportsLinks) delete(target); + /** + * Test: ensure target not deleted if source permissions are zero + */ + source = createSourceFile(dir1); + if (getFileStore(source).supportsFileAttributeView("posix")) { + Files.setPosixFilePermissions(source, Set.of()); + target = getTargetFile(dir2); + createFile(target); + try { + Files.copy(source, target, REPLACE_EXISTING); + throw new RuntimeException("AccessDeniedException not thrown"); + } catch (AccessDeniedException expected) { + } + if (!Files.exists(target)) + throw new RuntimeException("target deleted"); + delete(target); + } + delete(source); + // -- directory -- /* diff --git a/test/jdk/java/nio/file/Files/CopyMoveVariations.java b/test/jdk/java/nio/file/Files/CopyMoveVariations.java new file mode 100644 index 00000000000..e206448adbc --- /dev/null +++ b/test/jdk/java/nio/file/Files/CopyMoveVariations.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8073061 + * @requires (os.family == "linux") | (os.family == "mac") + * @summary Test Files.copy and Files.move with numerous parameters + * @run junit CopyMoveVariations + */ + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.AccessDeniedException; +import java.nio.file.CopyOption; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; +import static java.nio.file.LinkOption.*; +import static java.nio.file.StandardCopyOption.*; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.*; + +public class CopyMoveVariations { + enum OpType { + COPY, + MOVE + } + + enum PathType { + FILE, + DIR, + LINK + } + + private static final boolean SUPPORTS_POSIX_PERMISSIONS; + + static { + Path currentDir = null; + try { + currentDir = Files.createTempFile(Path.of("."), "this", "that"); + SUPPORTS_POSIX_PERMISSIONS = + Files.getFileStore(currentDir).supportsFileAttributeView("posix"); + } catch (IOException cause) { + throw new UncheckedIOException(cause); + } finally { + if (currentDir != null) { + try { + Files.delete(currentDir); + } catch (IOException ignore) { + } + } + } + } + + private static boolean supportsPosixPermissions() { + return SUPPORTS_POSIX_PERMISSIONS; + } + + private static Stream params() { + List list = new ArrayList(); + + boolean[] falseAndTrue = new boolean[] {false, true}; + for (PathType type : PathType.values()) { + String[] modes = new String[] { + "---------", "r--r--r--", "-w--w--w-", "rw-rw-rw-" + }; + for (String mode : modes) { + for (boolean replaceExisting : falseAndTrue) { + for (boolean targetExists : falseAndTrue) { + list.add(Arguments.of(type, mode, replaceExisting, + targetExists)); + } + } + } + } + + return list.stream(); + } + + @ParameterizedTest + @EnabledIf("supportsPosixPermissions") + @MethodSource("params") + void copyFollow(PathType type, String mode, boolean replaceExisting, + boolean targetExists) throws IOException { + op(OpType.COPY, type, mode, replaceExisting, targetExists, true); + } + + @ParameterizedTest + @EnabledIf("supportsPosixPermissions") + @MethodSource("params") + void copyNoFollow(PathType type, String mode, boolean replaceExisting, + boolean targetExists) throws IOException { + op(OpType.COPY, type, mode, replaceExisting, targetExists, false); + } + + @ParameterizedTest + @EnabledIf("supportsPosixPermissions") + @MethodSource("params") + void move(PathType type, String mode, boolean replaceExisting, + boolean targetExists) throws IOException { + op(OpType.MOVE, type, mode, replaceExisting, targetExists, false); + } + + void op(OpType op, PathType type, String mode, boolean replaceExisting, + boolean targetExists, boolean followLinks) throws IOException { + + Path source = null; + Path target = null; + Path linkTarget = null; + Path currentDir = Path.of("."); + try { + switch (type) { + case FILE -> + source = Files.createTempFile(currentDir, "file", "dat"); + case DIR -> + source = Files.createTempDirectory(currentDir, "dir"); + case LINK -> { + linkTarget = Files.createTempFile(currentDir, "link", "target"); + Path link = Path.of("link"); + source = Files.createSymbolicLink(link, linkTarget); + } + } + + Set perms = + PosixFilePermissions.fromString(mode); + if (op == OpType.COPY && type == PathType.LINK && followLinks) + Files.setPosixFilePermissions(linkTarget, perms); + else + Files.setPosixFilePermissions(source, perms); + + if (targetExists) + target = Files.createTempFile(currentDir, "file", "target"); + else + target = Path.of("target"); + + Set optionSet = new HashSet(); + if (replaceExisting) + optionSet.add(REPLACE_EXISTING); + if (op == OpType.COPY && !followLinks) + optionSet.add(NOFOLLOW_LINKS); + CopyOption[] options = optionSet.toArray(new CopyOption[0]); + + final Path src = source; + final Path dst = target; + if (type == PathType.FILE) { + if (op == OpType.COPY) { + try { + Files.copy(source, target, options); + assert Files.exists(target); + } catch (AccessDeniedException ade) { + assertTrue(mode.charAt(0) != 'r'); + } catch (FileAlreadyExistsException faee) { + assertTrue(targetExists && !replaceExisting); + } + if (targetExists && mode.charAt(0) == '-') + assertTrue(Files.exists(target)); + } else if (!replaceExisting && targetExists) { + assertThrows(FileAlreadyExistsException.class, + () -> Files.move(src, dst, options)); + } else { + Files.move(source, target, options); + assert Files.exists(target); + } + } else if (type == PathType.DIR) { + if (op == OpType.COPY) { + try { + Files.copy(source, target, options); + assert Files.exists(target); + } catch (AccessDeniedException ade) { + assertTrue(mode.charAt(0) != 'r'); + } catch (FileAlreadyExistsException faee) { + assertTrue(targetExists && !replaceExisting); + } + if (targetExists && mode.charAt(0) == '-') + assertTrue(Files.exists(target)); + } else { + try { + Files.move(source, target, options); + assert Files.exists(target); + } catch (AccessDeniedException ade) { + assertTrue(mode.charAt(1) != 'w'); + } catch (FileAlreadyExistsException faee) { + assertTrue(targetExists && !replaceExisting); + } + } + } else if (type == PathType.LINK) { + if (op == OpType.COPY) { + try { + Files.copy(source, target, options); + assert Files.exists(target); + } catch (AccessDeniedException ade) { + assertTrue(mode.charAt(0) != 'r'); + } catch (FileAlreadyExistsException faee) { + assertTrue(targetExists && !replaceExisting); + } + } else { + try { + Files.move(source, target, options); + assert Files.exists(target); + } catch (AccessDeniedException ade) { + assertTrue(mode.charAt(0) != 'r'); + } catch (FileAlreadyExistsException faee) { + assertTrue(targetExists && !replaceExisting); + } + } + } else { + assert false; + } + } finally { + try { + if (source != null) + Files.deleteIfExists(source); + } catch (IOException x) { + } + try { + if (target != null) + Files.deleteIfExists(target); + } catch (IOException x) { + } + try { + if (linkTarget != null) + Files.deleteIfExists(linkTarget); + } catch (IOException x) { + } + } + } +} diff --git a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java index e8d1b328d52..de4881d613f 100644 --- a/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java +++ b/test/jdk/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,13 +21,23 @@ * questions. */ -/* @test - * @bug 8011536 8151430 8316304 +/* @test id=tmp + * @bug 8011536 8151430 8316304 8334339 * @summary Basic test for creationTime attribute on platforms/file systems - * that support it. + * that support it, tests using /tmp directory. * @library ../.. /test/lib * @build jdk.test.lib.Platform - * @run main CreationTime + * @comment We see this failing with "UnsatisfiedLinkError: Native Library ...libCreationTimeHelper.so already loaded in another classloader". Thus run as othervm + * @run main/othervm CreationTime + */ + +/* @test id=cwd + * @summary Basic test for creationTime attribute on platforms/file systems + * that support it, tests using the test scratch directory, the test + * scratch directory maybe at diff disk partition to /tmp on linux. + * @library ../.. /test/lib + * @build jdk.test.lib.Platform + * @run main/native CreationTime . */ import java.nio.file.Path; @@ -37,6 +47,7 @@ import java.io.IOException; import jdk.test.lib.Platform; +import jtreg.SkippedException; public class CreationTime { @@ -67,8 +78,14 @@ static void test(Path top) throws IOException { FileTime creationTime = creationTime(file); Instant now = Instant.now(); if (Math.abs(creationTime.toMillis()-now.toEpochMilli()) > 10000L) { - err.println("File creation time reported as: " + creationTime); - throw new RuntimeException("Expected to be close to: " + now); + System.out.println("creationTime.toMillis() == " + creationTime.toMillis()); + // If the file system doesn't support birth time, then skip this test + if (creationTime.toMillis() == 0) { + throw new SkippedException("birth time not support for: " + file); + } else { + err.println("File creation time reported as: " + creationTime); + throw new RuntimeException("Expected to be close to: " + now); + } } /** @@ -94,7 +111,7 @@ static void test(Path top) throws IOException { // Creation time updates are not supported on Linux supportsCreationTimeWrite = false; } - System.out.println("supportsCreationTimeRead == " + supportsCreationTimeRead); + System.out.println(top + " supportsCreationTimeRead == " + supportsCreationTimeRead); /** * If the creation-time attribute is supported then change the file's @@ -126,7 +143,12 @@ static void test(Path top) throws IOException { public static void main(String[] args) throws IOException { // create temporary directory to run tests - Path dir = TestUtil.createTemporaryDirectory(); + Path dir; + if (args.length == 0) { + dir = TestUtil.createTemporaryDirectory(); + } else { + dir = TestUtil.createTemporaryDirectory(args[0]); + } try { test(dir); } finally { diff --git a/test/jdk/java/rmi/reliability/benchmark/bench/Makefile b/test/jdk/java/rmi/reliability/benchmark/bench/Makefile index f0600d4df30..805d6216373 100644 --- a/test/jdk/java/rmi/reliability/benchmark/bench/Makefile +++ b/test/jdk/java/rmi/reliability/benchmark/bench/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2000, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -47,4 +47,3 @@ all: .classes clean: rm -f *.class .classes - diff --git a/test/jdk/java/rmi/reliability/benchmark/bench/rmi/Makefile b/test/jdk/java/rmi/reliability/benchmark/bench/rmi/Makefile index bb44d94f154..c142b3a2d05 100644 --- a/test/jdk/java/rmi/reliability/benchmark/bench/rmi/Makefile +++ b/test/jdk/java/rmi/reliability/benchmark/bench/rmi/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -72,4 +72,3 @@ altroot.clean: clean: altroot.clean rm -f *.class .classes - diff --git a/test/jdk/java/text/Format/NumberFormat/BigDecimalCompatibilityTest.java b/test/jdk/java/text/Format/NumberFormat/BigDecimalCompatibilityTest.java index 2af23a4c82d..66fc44e368f 100644 --- a/test/jdk/java/text/Format/NumberFormat/BigDecimalCompatibilityTest.java +++ b/test/jdk/java/text/Format/NumberFormat/BigDecimalCompatibilityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * 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,58 +24,85 @@ /* * @test * @bug 4018937 - * @summary Confirm that DecimalFormat.parse() parses BigDecimal and BigInteger as expected. + * @summary Confirm that DecimalFormat.parse() parses BigDecimal and BigInteger + * string values as expected. Specifically, ensure a ParseException is + * not thrown as well as the parsed value being numerically correct. + * Tests large String values with combinations of multipliers and exponents. + * @run junit BigDecimalCompatibilityTest */ -import java.math.*; -import java.text.*; -import java.util.*; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Locale; +import java.util.stream.Stream; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +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.assertEquals; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; public class BigDecimalCompatibilityTest { - static boolean err = false; + private static DecimalFormat df = new DecimalFormat(); + // Save JVM default Locale + private static final Locale savedLocale = Locale.getDefault(); - static final String[] input_data = { - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" - }; - static final String[] exponents = { - "E-100", "E100", "E-900", "E900", "" - }; - static final int[] multipliers = { - -1, 1, -100, 100, -9999, 9999 - }; + // ---- Used for the test data (start) ---- - public static void main(String[] args) throws Exception { - Locale loc = Locale.getDefault(); - Locale.setDefault(Locale.US); + // Both ArrayList composed of Arguments(String longString, int multiplier) + private static final ArrayList bigIntegers = new ArrayList(); + private static final ArrayList bigDecimals = new ArrayList(); - testBigDecimal(); - testBigInteger(); + // Long string data to generate combinations of test values + private static final String[] inputData = { + "0".repeat(400), + "1234567890".repeat(40)}; - Locale.setDefault(loc); + // Variety of exponents to test parse() against + private static final String[] exponents = { + "E-100", "E100", "E-900", "E900", "" + }; - if (err) { - throw new RuntimeException("Error: Unexpected value"); - } - } + // Variety of multipliers that DecimalFormat can apply + private static final int[] multipliers = { + -1, 1, -100, 100, -9999, 9999 + }; + // ---- Used for the test data (end) ---- - static private void testBigDecimal() { - DecimalFormat df = new DecimalFormat(); - df.setParseBigDecimal(true); - df.setMaximumFractionDigits(Integer.MAX_VALUE); + // Set JVM default Locale to US and populate the test arrayLists + @BeforeAll + static void initAll() { + Locale.setDefault(Locale.US); + buildTestData(); + } - for (int i = 0; i < input_data.length; i++) { - for (int j = 0; j < input_data.length; j++) { - for (int k = 0; k < input_data.length; k++) { - for (int l = 0; l < input_data.length; l++) { - for (int m = 0; m < exponents.length; m++) { - String s = input_data[i] + input_data[j] + '.' + - input_data[k] + input_data[l] + - exponents[m]; - for (int n = 0; n < multipliers.length; n++) { - test(df, s, multipliers[n]); - test(df, '-'+s, multipliers[n]); + /* + * Uses inputData and exponents to build long string + * decimal and integer values and populate bigDecimals and bigIntegers + * accordingly. Attaches a multiplier value as well to the test data. + */ + private static void buildTestData() { + for (String longString1 : inputData) { + for (String longString2 : inputData) { + String bigInteger = longString1 + longString2; + for (int multiplier : multipliers) { + bigIntegers.add(Arguments.of(bigInteger, multiplier)); + bigIntegers.add(Arguments.of('-' + bigInteger, multiplier)); + } + for (String longString3 : inputData) { + for (String longString4 : inputData) { + for (String exponent : exponents) { + String bigDecimal = longString1 + longString2 + '.' + + longString3 + longString4 + exponent; + for (int multiplier : multipliers) { + bigDecimals.add(Arguments.of(bigDecimal, multiplier)); + bigDecimals.add(Arguments.of('-' + bigDecimal, multiplier)); } } } @@ -84,51 +111,70 @@ static private void testBigDecimal() { } } - static private void testBigInteger() { - DecimalFormat df = new DecimalFormat(); - df.setParseBigDecimal(true); - df.setMaximumFractionDigits(Integer.MAX_VALUE); + // Restore JVM default Locale + @AfterAll + static void tearDownAll() { + Locale.setDefault(savedLocale); + } - for (int i = 0; i < input_data.length; i++) { - for (int j = 0; j < input_data.length; j++) { - String s = input_data[i] + input_data[j]; - for (int k = 0; k < multipliers.length; k++) { - test(df, s, multipliers[k]); - test(df, '-'+s, multipliers[k]); - } - } - } + // Tests strings with length 1600+. See test() for specific details. + @ParameterizedTest + @MethodSource("bigDecimalProvider") + public void bigDecimalParseTest(String longString, int multiplier) { + test(longString, multiplier); + } + + // Returns 960 arrangements of bigDecimal string values and multipliers + // In the form of (String, int). + private static Stream bigDecimalProvider() { + return bigDecimals.stream(); + } + + // Tests strings with length 800+. See test() for specific details. + @ParameterizedTest + @MethodSource("bigIntegerProvider") + public void bigIntegerParseTest(String longString, int multiplier) { + test(longString, multiplier); + } + + // Returns 48 arrangements of bigInteger string values and multipliers + // In the form of (String, int). + private static Stream bigIntegerProvider() { + return bigIntegers.stream(); } - static void test(DecimalFormat df, String s, int multiplier) { + /* + * Tests that parsing a large BigDecimal/BigInteger string value + * will not throw a ParseException with setParseBigDecimal as true. + * Parses with a variety of multiplier values. Then ensures that the parsed + * value is the expected number. + */ + private static void test(String longString, int multiplier) { + // Reset DecimalFormat for a clean test + df = new DecimalFormat(); + df.setParseBigDecimal(true); + // wide enough to support the long string test data + df.setMaximumFractionDigits(Integer.MAX_VALUE); df.setMultiplier(multiplier); - Number num = null; - try { - num = df.parse(s); - } - catch (ParseException e) { - err = true; - System.err.println("Failed: Exception occurred: " + e.getMessage()); - return; - } + // Check parse and returned value. This was originally intended to ensure + // a ParseException is not thrown + Number parsedValue = assertDoesNotThrow(()-> df.parse(longString), + "Should not throw an Exception"); + BigDecimal expectedValue = getExpected(longString, multiplier); + assertEquals(expectedValue, parsedValue, "With multiplier: " + multiplier); + } - BigDecimal bd = new BigDecimal(s); + // Utility to get a numerically correct value of a long string. + // Dependent on BigDecimal implementation + private static BigDecimal getExpected(String longString, int multiplier) { + BigDecimal expected = new BigDecimal(longString); try { - bd = bd.divide(new BigDecimal(multiplier)); + expected = expected.divide(new BigDecimal(multiplier)); } catch (ArithmeticException e) { - bd = bd.divide(new BigDecimal(multiplier), RoundingMode.HALF_EVEN); - } - check(num, bd, multiplier); - } - - static void check(Number got, BigDecimal expected, int multiplier) { - if (!got.equals(expected)) { - err = true; - System.err.println("Failed: got:" + got + - ", expected: " + expected + - ", multiplier=" + multiplier); + expected = expected.divide(new BigDecimal(multiplier), RoundingMode.HALF_EVEN); } + return expected; } } diff --git a/test/jdk/java/text/Format/NumberFormat/Bug4208135.java b/test/jdk/java/text/Format/NumberFormat/Bug4208135.java index 1d641226ab7..301b90c89f3 100644 --- a/test/jdk/java/text/Format/NumberFormat/Bug4208135.java +++ b/test/jdk/java/text/Format/NumberFormat/Bug4208135.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * 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,105 +23,164 @@ /* * @test - * @summary Confirm that the decimal separator is shown when explicitly requested. + * @summary Confirm that the decimal separator is shown when explicitly requested + * (or not shown if not requested). Tests against double, long, BigDecimal, + * and BigInteger with a combination of different patterns. * @bug 4208135 + * @run junit Bug4208135 */ -import java.math.*; -import java.text.*; -import java.util.*; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.text.DecimalFormat; +import java.util.Locale; +import java.util.stream.Stream; -public class Bug4208135 { +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; - static DecimalFormat df; +import static org.junit.jupiter.api.Assertions.assertEquals; - static boolean err = false; +public class Bug4208135 { - static public void main(String[] args){ + private static DecimalFormat df; + // Save JVM default Locale + private static final Locale savedLocale = Locale.getDefault(); - Locale defaultLoc = Locale.getDefault(); + // Set JVM default locale to US + @BeforeAll + static void init() { Locale.setDefault(Locale.US); + } - df = new DecimalFormat(); + // Restore JVM default locale + @AfterAll + static void tearDown() { + Locale.setDefault(savedLocale); + } + + // Confirm that decimal separator shown when formatting a number + @ParameterizedTest + @MethodSource("fractionalDigitsWithSeparatorProvider") + public void fractionalDigitsWithSeparatorTest(Number num, String expected) { + df = getDF("0.#E0", true); + String actualFormatted = df.format(num); + assertEquals(expected, actualFormatted, getErrMsg("0.#E0", true)); + } + + // Combination of numbers and a fractional exponent pattern with a separator + private static Stream fractionalDigitsWithSeparatorProvider() { + return Stream.of( + Arguments.of(0.0, "0.E0"), + Arguments.of(10.0, "1.E1"), + Arguments.of(1000.0, "1.E3"), + Arguments.of(0L, "0.E0"), + Arguments.of(10L, "1.E1"), + Arguments.of(1000L, "1.E3"), + Arguments.of(new BigDecimal("0.0"), "0.E0"), + Arguments.of(new BigDecimal("10.0"), "1.E1"), + Arguments.of(new BigDecimal("1000.0"), "1.E3"), + Arguments.of(new BigInteger("00"), "0.E0"), + Arguments.of(new BigInteger("10"), "1.E1"), + Arguments.of(new BigInteger("1000"), "1.E3") + ); + } + + // Confirm that decimal separator not shown when formatting a number + @ParameterizedTest + @MethodSource("fractionalDigitsNoSeparatorProvider") + public void fractionalDigitsNoSeparatorTest(Number num, String expected) { + df = getDF("0.#E0", false); + String actualFormatted = df.format(num); + assertEquals(expected, actualFormatted, getErrMsg("0.#E0", false)); + } - df.applyPattern("0.#E0"); - - df.setDecimalSeparatorAlwaysShown(true); - checkFormat(0.0, "0.E0"); - checkFormat(10.0, "1.E1"); - checkFormat(1000.0, "1.E3"); - checkFormat(0L, "0.E0"); - checkFormat(10L, "1.E1"); - checkFormat(1000L, "1.E3"); - checkFormat(new BigDecimal("0.0"), "0.E0"); - checkFormat(new BigDecimal("10.0"), "1.E1"); - checkFormat(new BigDecimal("1000.0"), "1.E3"); - checkFormat(new BigInteger("00"), "0.E0"); - checkFormat(new BigInteger("10"), "1.E1"); - checkFormat(new BigInteger("1000"), "1.E3"); - - df.setDecimalSeparatorAlwaysShown(false); - checkFormat(0.0, "0E0"); - checkFormat(10.0, "1E1"); - checkFormat(1000.0, "1E3"); - checkFormat(0L, "0E0"); - checkFormat(10L, "1E1"); - checkFormat(1000L, "1E3"); - checkFormat(new BigDecimal("0.0"), "0E0"); - checkFormat(new BigDecimal("10.0"), "1E1"); - checkFormat(new BigDecimal("1000.0"), "1E3"); - checkFormat(new BigInteger("0"), "0E0"); - checkFormat(new BigInteger("10"), "1E1"); - checkFormat(new BigInteger("1000"), "1E3"); - - df.applyPattern("0.###"); - - df.setDecimalSeparatorAlwaysShown(true); - checkFormat(0.0, "0."); - checkFormat(10.0, "10."); - checkFormat(1000.0, "1000."); - checkFormat(0L, "0."); - checkFormat(10L, "10."); - checkFormat(1000L, "1000."); - checkFormat(new BigDecimal("0.0"), "0."); - checkFormat(new BigDecimal("10.0"), "10."); - checkFormat(new BigDecimal("1000.0"), "1000."); - checkFormat(new BigInteger("0"), "0."); - checkFormat(new BigInteger("10"), "10."); - checkFormat(new BigInteger("1000"), "1000."); - - df.setDecimalSeparatorAlwaysShown(false); - checkFormat(0.0, "0"); - checkFormat(10.0, "10"); - checkFormat(1000.0, "1000"); - checkFormat(0L, "0"); - checkFormat(10L, "10"); - checkFormat(1000L, "1000"); - checkFormat(new BigDecimal("0.0"), "0"); - checkFormat(new BigDecimal("10.0"), "10"); - checkFormat(new BigDecimal("1000.0"), "1000"); - checkFormat(new BigInteger("0"), "0"); - checkFormat(new BigInteger("10"), "10"); - checkFormat(new BigInteger("1000"), "1000"); - - Locale.setDefault(defaultLoc); - - if (err) { - throw new RuntimeException("Wrong format/parse with DecimalFormat"); - } + // Combination of numbers and a fractional exponent pattern with no separator + private static Stream fractionalDigitsNoSeparatorProvider() { + return Stream.of( + Arguments.of(0.0, "0E0"), + Arguments.of(10.0, "1E1"), + Arguments.of(1000.0, "1E3"), + Arguments.of(0L, "0E0"), + Arguments.of(10L, "1E1"), + Arguments.of(1000L, "1E3"), + Arguments.of(new BigDecimal("0.0"), "0E0"), + Arguments.of(new BigDecimal("10.0"), "1E1"), + Arguments.of(new BigDecimal("1000.0"), "1E3"), + Arguments.of(new BigInteger("00"), "0E0"), + Arguments.of(new BigInteger("10"), "1E1"), + Arguments.of(new BigInteger("1000"), "1E3") + ); + } + + // Confirm that decimal separator shown when formatting a number + @ParameterizedTest + @MethodSource("noFractionalDigitsWithSeparatorProvider") + public void noFractionalDigitsWithSeparatorTest(Number num, String expected) { + df = getDF("0.###", true); + String actualFormatted = df.format(num); + assertEquals(expected, actualFormatted, getErrMsg("0.###", true)); + } + + // Combination of numbers and a non-fractional exponent pattern with a separator + private static Stream noFractionalDigitsWithSeparatorProvider() { + return Stream.of( + Arguments.of(0.0, "0."), + Arguments.of(10.0, "10."), + Arguments.of(1000.0, "1000."), + Arguments.of(0L, "0."), + Arguments.of(10L, "10."), + Arguments.of(1000L, "1000."), + Arguments.of(new BigDecimal("0.0"), "0."), + Arguments.of(new BigDecimal("10.0"), "10."), + Arguments.of(new BigDecimal("1000.0"), "1000."), + Arguments.of(new BigInteger("00"), "0."), + Arguments.of(new BigInteger("10"), "10."), + Arguments.of(new BigInteger("1000"), "1000.") + ); + } + + // Confirm that decimal separator not shown when formatting a number + @ParameterizedTest + @MethodSource("noFractionalDigitsNoSeparatorProvider") + public void noFractionalDigitsNoSeparatorTest(Number num, String expected) { + df = getDF("0.###", false); + String actualFormatted = df.format(num); + assertEquals(expected, actualFormatted, getErrMsg("0.###", false)); + } + + // Combination of numbers and a non-fractional exponent pattern with no separator + private static Stream noFractionalDigitsNoSeparatorProvider() { + return Stream.of( + Arguments.of(0.0, "0"), + Arguments.of(10.0, "10"), + Arguments.of(1000.0, "1000"), + Arguments.of(0L, "0"), + Arguments.of(10L, "10"), + Arguments.of(1000L, "1000"), + Arguments.of(new BigDecimal("0.0"), "0"), + Arguments.of(new BigDecimal("10.0"), "10"), + Arguments.of(new BigDecimal("1000.0"), "1000"), + Arguments.of(new BigInteger("00"), "0"), + Arguments.of(new BigInteger("10"), "10"), + Arguments.of(new BigInteger("1000"), "1000") + ); + } + + // Creates clean DF and sets the pattern and separatorShown value + private static DecimalFormat getDF(String pattern, boolean separatorShown) { + df = new DecimalFormat(); + df.applyPattern(pattern); + df.setDecimalSeparatorAlwaysShown(separatorShown); + return df; } - static void checkFormat(Number num, String expected) { - String got = df.format(num); - if (!got.equals(expected)) { - err = true; - System.err.println(" DecimalFormat format(" + - num.getClass().getName() + - ") error:" + - "\n\tnumber: " + num + - "\n\tSeparatorShown? : " + df.isDecimalSeparatorAlwaysShown() + - "\n\tgot: " + got + - "\n\texpected: " + expected); - } + // Utility to get a helpful error message when values are not as expected + private static String getErrMsg(String pattern, boolean separatorShown) { + return String.format("Fails with pattern= %s, with separatorShown = %s", + pattern, separatorShown); } } diff --git a/test/jdk/java/text/Format/NumberFormat/Bug4838107.java b/test/jdk/java/text/Format/NumberFormat/Bug4838107.java index 452660b1ab2..e672bbfcf14 100644 --- a/test/jdk/java/text/Format/NumberFormat/Bug4838107.java +++ b/test/jdk/java/text/Format/NumberFormat/Bug4838107.java @@ -24,228 +24,259 @@ /* * @test * @bug 4838107 8008577 - * @summary Confirm that DecimalFormat can format a number with negative exponent number correctly. + * @summary Confirm that DecimalFormat can format a number with a negative + * exponent number correctly. Tests also involve using a DecimalFormat + * with a custom pattern or a custom minus sign. * @run junit/othervm -Djava.locale.providers=COMPAT,SPI Bug4838107 */ -import java.math.*; -import java.util.*; -import java.text.*; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; +import java.util.stream.Stream; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +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.assertEquals; import static org.junit.jupiter.api.Assertions.fail; +/* + * This bug is about exponential formatting. But I added test cases for: + * - Double and BigDecimal numbers which don't have exponent parts. + * - Long and BigInteger numbers which don't support exponential + * notation. + * because there are few test cases for suffix and prefix. + * And also, I added test cases to guarantee further formatting and + * parsing using the same DecimalFormat instance will not change the + * Number's value anymore. + */ public class Bug4838107 { - static DecimalFormat df; - static DecimalFormatSymbols dfs; - static boolean err = false; + // Save JVM default Locale + private static final Locale savedLocale = Locale.getDefault(); - static public void main(String[] args) { - Locale defaultLoc = Locale.getDefault(); + // Set JVM default Locale to US + @BeforeAll + static void init() { Locale.setDefault(Locale.US); - - /** - * This bug is about exponential formatting. But I added test cases for: - * - Double and BigDecimal numbers which don't have exponent parts. - * - Long and BigInteger numbers which don't support exponential - * notation. - * because there are few test cases for suffix and prefix. - * And also, I added test cases to guarantee further formatting and - * parsing using the same DecimalFormat instance will not change the - * Number's value anymore. - */ - - test_double(); - test_long(); - test_BigDecimal(); - test_BigInteger(); - - Locale.setDefault(defaultLoc); - - if (err) { - throw new RuntimeException("Wrong format with DecimalFormat"); - } } - static void test_double() { - df = new DecimalFormat(); - dfs = df.getDecimalFormatSymbols(); - - /* Test with default pattern */ - test(1234D, "1,234"); - test(0.1234, "0.123"); // rounded - test(-1234D, "-1,234"); - test(-0.1234, "-0.123"); // rounded - - test(Double.POSITIVE_INFINITY, "\u221e"); - test(Double.NEGATIVE_INFINITY, "-\u221e"); - test(Double.NaN, "\ufffd"); // without prefix and suffix - test(0.0, "0"); - test(-0.0, "-0"); // with the minus sign - - /* Specify a pattern and the minus sign. */ - prepareFormatter("

#.###E00", 'm'); - test(1234D, "

1.234E03"); - test(0.1234, "

1.234Em01"); - test(-1234D, "m

1.234E03"); - test(-0.1234, "m

1.234Em01"); - - prepareFormatter("

#.###E00;#.###E00", 'm'); - test(1234D, "

1.234E03"); - test(0.1234, "

1.234Em01"); - test(-1234D, "1.234E03"); - test(-0.1234, "1.234Em01"); - - prepareFormatter("#.###E00;

#.###E00", 'm'); - test(1234D, "1.234E03"); - test(0.1234, "1.234Em01"); - test(-1234D, "

1.234E03"); - test(-0.1234, "

1.234Em01"); - - prepareFormatter("

#.###E00;

-#.###E00", 'm'); - test(1234D, "

1.234E03"); - test(0.1234, "

1.234Em01"); - test(-1234D, "

m1.234E03"); - test(-0.1234, "

m1.234Em01"); - - test(Double.POSITIVE_INFINITY, "

\u221e"); - test(Double.NEGATIVE_INFINITY, "

m\u221e"); - test(Double.NaN, "\ufffd"); // without prefix and suffix - test(0.0, "

0E00"); - test(-0.0, "

m0E00"); // with the minus sign + // Restore the original JVM default locale + @AfterAll + static void tearDown() { + Locale.setDefault(savedLocale); } - static void test_BigDecimal() { - df = new DecimalFormat(); - dfs = df.getDecimalFormatSymbols(); - - /* Test with default pattern */ - test(new BigDecimal("123456789012345678901234567890"), - "123,456,789,012,345,678,901,234,567,890"); - test(new BigDecimal("0.000000000123456789012345678901234567890"), - "0"); - test(new BigDecimal("-123456789012345678901234567890"), - "-123,456,789,012,345,678,901,234,567,890"); - test(new BigDecimal("-0.000000000123456789012345678901234567890"), - "-0"); - - test(new BigDecimal("0"), "0"); - test(new BigDecimal("-0"), "0"); - - /* Specify a pattern and the minus sign. */ - prepareFormatter("

#.####################E00;

-#.####################E00", 'm'); - test(new BigDecimal("123456789012345678901234567890"), - "

1.23456789012345678901E29"); - test(new BigDecimal("0.000000000123456789012345678901234567890"), - "

1.23456789012345678901Em10"); - test(new BigDecimal("-123456789012345678901234567890"), - "

m1.23456789012345678901E29"); - test(new BigDecimal("-0.000000000123456789012345678901234567890"), - "

m1.23456789012345678901Em10"); - - test(new BigDecimal("0"), "

0E00"); - test(new BigDecimal("-0"), "

0E00"); + // Check that negative exponent number recognized for doubles + @ParameterizedTest + @MethodSource("doubles") + public void doubleTest(Number num, String str, DecimalFormat df) { + test(num, str, df); } - static void test_long() { - df = new DecimalFormat(); - dfs = df.getDecimalFormatSymbols(); - - /* Test with default pattern */ - test(123456789L, "123,456,789"); - test(-123456789L, "-123,456,789"); - - test(0L, "0"); - test(-0L, "0"); - - /* Specify a pattern and the minus sign. */ - prepareFormatter("

#,###;

-#,###", 'm'); - test(123456789L, "

123,456,789"); - test(-123456789L, "

m123,456,789"); - - test(0L, "

0"); - test(-0L, "

0"); + // Provides a double to be formatted, which is compared to the expected String. + // Additionally, provides a DecimalFormat to do the formatting (can have a custom + // pattern and minus sign). Given in the form (double, String, DecimalFormat). + private static Stream doubles() { + DecimalFormat defaultDf = new DecimalFormat(); + DecimalFormat customDf1 = getDecimalFormat("

#.###E00", 'm'); + DecimalFormat customDf2 = getDecimalFormat("

#.###E00;#.###E00", 'm'); + DecimalFormat customDf3 = getDecimalFormat("#.###E00;

#.###E00", 'm'); + DecimalFormat customDf4 = getDecimalFormat("

#.###E00;

-#.###E00", 'm'); + return Stream.of( + // Test with default pattern + Arguments.of(1234D, "1,234", defaultDf), + Arguments.of(0.1234, "0.123", defaultDf), // rounded + Arguments.of(-1234D, "-1,234", defaultDf), + Arguments.of(-0.1234, "-0.123", defaultDf), // rounded + Arguments.of(Double.POSITIVE_INFINITY, "\u221e", defaultDf), + Arguments.of(Double.NEGATIVE_INFINITY, "-\u221e", defaultDf), + Arguments.of(Double.NaN, "\ufffd", defaultDf), // without prefix and suffix + Arguments.of(0.0, "0", defaultDf), + Arguments.of(-0.0, "-0", defaultDf), // with the minus sign + // Test with a pattern and the minus sign + Arguments.of(1234D, "

1.234E03", customDf1), + Arguments.of(0.1234, "

1.234Em01", customDf1), + Arguments.of(-1234D, "m

1.234E03", customDf1), + Arguments.of(-0.1234, "m

1.234Em01", customDf1), + Arguments.of(1234D, "

1.234E03", customDf2), + Arguments.of(0.1234, "

1.234Em01", customDf2), + Arguments.of(-1234D, "1.234E03", customDf2), + Arguments.of(-0.1234, "1.234Em01", customDf2), + Arguments.of(1234D, "1.234E03", customDf3), + Arguments.of(0.1234, "1.234Em01", customDf3), + Arguments.of(-1234D, "

1.234E03", customDf3), + Arguments.of(-0.1234, "

1.234Em01", customDf3), + Arguments.of(1234D, "

1.234E03", customDf4), + Arguments.of(0.1234, "

1.234Em01", customDf4), + Arguments.of(-1234D, "

m1.234E03", customDf4), + Arguments.of(-0.1234, "

m1.234Em01", customDf4), + Arguments.of(Double.POSITIVE_INFINITY, "

\u221e", customDf4), + Arguments.of(Double.NEGATIVE_INFINITY, "

m\u221e", customDf4), + Arguments.of(Double.NaN, "\ufffd", customDf4), // without prefix and suffix + Arguments.of(0.0, "

0E00", customDf4), + Arguments.of(-0.0, "

m0E00", customDf4) // with the minus sign + ); } - static void test_BigInteger() { - df = new DecimalFormat(); - dfs = df.getDecimalFormatSymbols(); + // Check that negative exponent number recognized for longs + @ParameterizedTest + @MethodSource("longs") + public void longTest(Number num, String str, DecimalFormat df) { + test(num, str, df); + } - /* Test with default pattern */ - test(new BigInteger("123456789012345678901234567890"), - "123,456,789,012,345,678,901,234,567,890"); - test(new BigInteger("-123456789012345678901234567890"), - "-123,456,789,012,345,678,901,234,567,890"); + // Same as doubles() data provider, but with long values + // Given in the form (long, String, DecimalFormat). + private static Stream longs() { + DecimalFormat defaultDf = new DecimalFormat(); + DecimalFormat customDf = getDecimalFormat( + "

#,###;

-#,###", 'm'); + return Stream.of( + // Test with default pattern + Arguments.of(123456789L, "123,456,789", defaultDf), + Arguments.of(-123456789L, "-123,456,789", defaultDf), + Arguments.of(0L, "0", defaultDf), + Arguments.of(-0L, "0", defaultDf), + // Test with a pattern and the minus sign + Arguments.of(123456789L, "

123,456,789", customDf), + Arguments.of(-123456789L, "

m123,456,789", customDf), + Arguments.of(0L, "

0", customDf), + Arguments.of(-0L, "

0", customDf) + ); + } - test(new BigInteger("0"), "0"); - test(new BigInteger("-0"), "0"); + // Check that negative exponent number recognized for bigDecimals + @ParameterizedTest + @MethodSource("bigDecimals") + public void bigDecimalTest(Number num, String str, DecimalFormat df) { + test(num, str, df); + } - /* Specify a pattern and the minus sign. */ - prepareFormatter("

#,###;

-#,###", 'm'); - test(new BigInteger("123456789012345678901234567890"), - "

123,456,789,012,345,678,901,234,567,890"); - test(new BigInteger("-123456789012345678901234567890"), - "

m123,456,789,012,345,678,901,234,567,890"); + // Same as doubles() data provider, but with BigDecimal values + // Given in the form (BigDecimal, String, DecimalFormat). + private static Stream bigDecimals() { + DecimalFormat defaultDf = new DecimalFormat(); + DecimalFormat customDf = getDecimalFormat( + "

#.####################E00;

-#.####################E00", 'm'); + return Stream.of( + // Test with default pattern + Arguments.of(new BigDecimal("123456789012345678901234567890"), + "123,456,789,012,345,678,901,234,567,890", defaultDf), + Arguments.of(new BigDecimal("0.000000000123456789012345678901234567890"), + "0", defaultDf), + Arguments.of(new BigDecimal("-123456789012345678901234567890"), + "-123,456,789,012,345,678,901,234,567,890", defaultDf), + Arguments.of(new BigDecimal("-0.000000000123456789012345678901234567890"), + "-0", defaultDf), + Arguments.of(new BigDecimal("0"), "0", defaultDf), + Arguments.of(new BigDecimal("-0"), "0", defaultDf), + // Test with a pattern and the minus sign + Arguments.of(new BigDecimal("123456789012345678901234567890"), + "

1.23456789012345678901E29", customDf), + Arguments.of(new BigDecimal("0.000000000123456789012345678901234567890"), + "

1.23456789012345678901Em10", customDf), + Arguments.of(new BigDecimal("-123456789012345678901234567890"), + "

m1.23456789012345678901E29", customDf), + Arguments.of(new BigDecimal("-0.000000000123456789012345678901234567890"), + "

m1.23456789012345678901Em10", customDf), + Arguments.of(new BigDecimal("0"), "

0E00", customDf), + Arguments.of(new BigDecimal("-0"), "

0E00", customDf) + ); + } - test(new BigInteger("0"), "

0"); - test(new BigInteger("-0"), "

0"); + // Check that negative exponent number recognized for bigIntegers + @ParameterizedTest + @MethodSource("bigIntegers") + public void bigIntegerTest(Number num, String str, DecimalFormat df) { + test(num, str, df); } - static void prepareFormatter(String pattern, char minusSign) { - dfs = df.getDecimalFormatSymbols(); - df.applyPattern(pattern); - dfs.setMinusSign(minusSign); - df.setDecimalFormatSymbols(dfs); + // Same as doubles() data provider, but with BigInteger values + // Given in the form (BigInteger, String, DecimalFormat). + private static Stream bigIntegers() { + DecimalFormat defaultDf = new DecimalFormat(); + DecimalFormat customDf = getDecimalFormat( + "

#,###;

-#,###", 'm'); + return Stream.of( + // Test with default pattern + Arguments.of(new BigInteger("123456789012345678901234567890"), + "123,456,789,012,345,678,901,234,567,890", defaultDf), + Arguments.of(new BigInteger("-123456789012345678901234567890"), + "-123,456,789,012,345,678,901,234,567,890", defaultDf), + Arguments.of(new BigInteger("0"), "0", defaultDf), + Arguments.of(new BigInteger("-0"), "0", defaultDf), + // Test with a pattern and the minus sign + Arguments.of(new BigInteger("123456789012345678901234567890"), + "

123,456,789,012,345,678,901,234,567,890", customDf), + Arguments.of(new BigInteger("-123456789012345678901234567890"), + "

m123,456,789,012,345,678,901,234,567,890", customDf), + Arguments.of(new BigInteger("0"), "

0", customDf), + Arguments.of(new BigInteger("-0"), "

0", customDf) + ); } - static void test(Number num, String str) { + // Check that the formatted value is correct and also check that + // it can be round-tripped via parse() and format() + private static void test(Number num, String str, DecimalFormat df) { String formatted = df.format(num); - if (!formatted.equals(str)) { - err = true; - System.err.println(" DecimalFormat format(" + - num.getClass().getName() + - ") error: \n\tnumber: " + num + - "\n\tminus sign: " + dfs.getMinusSign() + - "\n\tgot: " + formatted + - "\n\texpected: " + str); - return; - } + assertEquals(str, formatted, String.format("DecimalFormat format(%s) " + + "Error: number: %s, minus sign: %s", num.getClass().getName(), num, df.getDecimalFormatSymbols().getMinusSign())); if (num instanceof BigDecimal || num instanceof BigInteger) { df.setParseBigDecimal(true); } + testRoundTrip(formatted, str, num, df); + } + + // Test that a parsed value can be round-tripped via format() and parse() + private static void testRoundTrip(String formatted, String str, + Number num, DecimalFormat df) { Number parsed1 = null, parsed2 = null; try { parsed1 = df.parse(formatted); formatted = df.format(parsed1); parsed2 = df.parse(formatted); - if (!parsed1.equals(parsed2)) { - err = true; - System.err.println(" DecimalFormat roundtrip parse(" + - num.getClass().getName() + - ") error: \n\toriginal number: " + str + - "\n\tparsed number: " + parsed1 + - " (" + parsed1.getClass().getName() + ")" + - "\n\tformatted number: " + formatted + - "\n\tre-parsed number: " + parsed2 + - " (" + parsed2.getClass().getName() + ")" + - "\n\tminus sign: " + dfs.getMinusSign()); - } + assertEquals(parsed2, parsed1, """ + DecimalFormat round trip parse(%s) error: + original number: %s + parsed number: %s + (%s) + formatted number: %s + re-parsed number: %s + (%s) + minus sign: %s + """.formatted(num.getClass().getName(), str, parsed1, parsed1.getClass().getName(), + formatted, parsed2, parsed2.getClass().getName(), df.getDecimalFormatSymbols().getMinusSign())); } catch (Exception e) { - err = true; - System.err.println(" DecimalFormat parse(" + - num.getClass().getName() + - ") threw an Exception: " + e.getMessage() + - "\n\toriginal number: " + str + - "\n\tparsed number : " + parsed1 + - " (" + parsed1.getClass().getName() + ")" + - "\n\tformatted number: " + formatted + - "\n\tre-parsed number: " + parsed2 + - " (" + parsed2.getClass().getName() + ")" + - "\n\tminus sign: " + dfs.getMinusSign()); + fail(""" + DecimalFormat parse(%s) threw an Exception: %s + original number: %s + parsed number: %s + (%s) + formatted number: %s + re-parsed number: %s + (%s) + minus sign: %s + """.formatted(num.getClass().getName(), e.getMessage(), str, parsed1, parsed1.getClass().getName(), + formatted, parsed2, parsed2.getClass().getName(), df.getDecimalFormatSymbols().getMinusSign())); } } + + // Set up custom DecimalFormat with DecimalFormatSymbols + private static DecimalFormat getDecimalFormat(String pattern, char minusSign) { + DecimalFormat df = new DecimalFormat(); + DecimalFormatSymbols dfs = df.getDecimalFormatSymbols(); + df.applyPattern(pattern); + dfs.setMinusSign(minusSign); + df.setDecimalFormatSymbols(dfs); + return df; + } } diff --git a/test/jdk/java/text/Format/NumberFormat/Bug4944439.java b/test/jdk/java/text/Format/NumberFormat/Bug4944439.java index 0e85a98119d..561052e9a95 100644 --- a/test/jdk/java/text/Format/NumberFormat/Bug4944439.java +++ b/test/jdk/java/text/Format/NumberFormat/Bug4944439.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * 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,87 +25,97 @@ * @test * @bug 4944439 * @summary Confirm that numbers where all digits after the decimal separator are 0 - * and which are between Long.MIN_VALUE and Long.MAX_VALUE are returned as Long(not double). + * and which are between Long.MIN_VALUE and Long.MAX_VALUE are returned + * as Long(not double). + * @run junit Bug4944439 */ -import java.math.BigDecimal; -import java.math.BigInteger; import java.text.DecimalFormat; +import java.util.ArrayList; import java.util.Locale; +import java.util.stream.Stream; -public class Bug4944439 { - - static boolean err = false; - static DecimalFormat df; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; - public static void main(String[] args) throws Exception { - - Locale defaultLoc = Locale.getDefault(); - Locale.setDefault(Locale.US); +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; - df = new DecimalFormat(); - String s = "-9223372036854775809"; // Long.MIN_VALUE-1 - check_Double(s); +public class Bug4944439 { - test(Long.MIN_VALUE, Long.MIN_VALUE+10); - test(-10, 10); - test(Long.MAX_VALUE-10, Long.MAX_VALUE-1); + // Save JVM default locale + private static final Locale savedLocale = Locale.getDefault(); + private static final DecimalFormat df = new DecimalFormat(); - s = "9223372036854775807.00"; // Long.MAX_VALUE - check_Long(s); - s = "9223372036854775808"; // Long.MAX_VALUE+1 - check_Double(s); + // Set JVM default locale to US for testing + @BeforeAll + static void initAll() { + Locale.setDefault(Locale.US); + } - s = "-0.0"; - check_Double(s); - s = "0.0"; - check_Long(s); + // Restore JVM default locale + @AfterAll + static void tearDownAll() { + Locale.setDefault(savedLocale); + } - Locale.setDefault(defaultLoc); + // Check return type and value returned by DecimalFormat.parse() for longs + @ParameterizedTest + @MethodSource("longs") + public void parseLongTest(String s) { + // This was originally intended to ensure a ParseException is not thrown + Number parsedNumber = assertDoesNotThrow(() -> df.parse(s), + "DecimalFormat.parse(\"%s\") should not throw an Exception"); + assertInstanceOf(Long.class, parsedNumber, + "DecimalFormat.parse(\"%s\") did not return Long"); + // Grab integer portion of value + Long expectedVal = Long.valueOf(s.substring(0, s.indexOf('.'))); + assertEquals(parsedNumber, expectedVal, + "DecimalFormat.parse(\"%s\") returned numerically incorrect value"); + } - if (err) { - throw new RuntimeException("Wrong parsing with DecimalFormat"); - } + // Test some values between Long.MIN_VALUE and Long.MAX_VALUE + private static Stream longs() { + ArrayList longs = new ArrayList<>(); + addLongData(Long.MIN_VALUE, Long.MIN_VALUE+10, longs); + addLongData(-10, 10, longs); + addLongData(Long.MAX_VALUE-10, Long.MAX_VALUE-1, longs); + longs.add("9223372036854775807.00"); + longs.add("0.0"); + return longs.stream(); } - private static void test(long from, long to) throws Exception { + // Utility to add values between parameters(long, to) to testLongs ArrayList + private static void addLongData(long from, long to, ArrayList testLongs){ for (long l = from; l <= to; l++) { - check_Long(Long.toString(l) + ".00"); + testLongs.add(l + ".00"); } } - private static void check_Long(String s) throws Exception { - Number number = df.parse(s); - if (!(number instanceof Long)) { - err = true; - System.err.println("Failed: DecimalFormat.parse(\"" + s + - "\") should return a Long, but returned a " + - number.getClass().getName()); - } - - int index = s.indexOf('.'); - Long l = Long.valueOf(s.substring(0, index)); - if (!l.equals(number)) { - err = true; - System.err.println("Failed: DecimalFormat.parse(" + s + - ") should return a Long(" + l + "), but returned " + number); - } + // Check return type and value returned by DecimalFormat.parse() for doubles + @ParameterizedTest + @MethodSource("doubles") + public void parseDoubleTest(String s) { + // This was originally intended to ensure a ParseException is not thrown + Number parsedNumber = assertDoesNotThrow(() -> df.parse(s), + "DecimalFormat.parse(\"%s\") should not throw an Exception"); + assertInstanceOf(Double.class, parsedNumber, + "DecimalFormat.parse(\"%s\") did not return Double"); + Double expectedVal = Double.valueOf(s); + assertEquals(parsedNumber, expectedVal, + "DecimalFormat.parse(\"%s\") returned numerically incorrect value"); } - private static void check_Double(String s) throws Exception { - Number number = df.parse(s); - if (!(number instanceof Double)) { - err = true; - System.err.println("Failed: DecimalFormat.parse(\"" + s + - "\") should return a Double, but returned a " + - number.getClass().getName()); - } - - Double d = Double.valueOf(s); - if (!d.equals(number)) { - err = true; - System.err.println("Failed: DecimalFormat.parse(" + s + - ") should return a Double(" + d + "), but returned " + number); - } + // Check values not between Long.MIN_VALUE and Long.MAX_VALUE + private static Stream doubles() { + return Stream.of( + "-9223372036854775809", // Long.MIN_VALUE-1 + "9223372036854775808", // Long.MAX_VALUE+1 + "-0.0" + ); } } diff --git a/test/jdk/java/text/Format/NumberFormat/Bug4990596.java b/test/jdk/java/text/Format/NumberFormat/Bug4990596.java index 2b311fb1b5f..36c0259ae56 100644 --- a/test/jdk/java/text/Format/NumberFormat/Bug4990596.java +++ b/test/jdk/java/text/Format/NumberFormat/Bug4990596.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. * 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,20 +21,32 @@ * questions. */ -/** +/* * @test * @bug 4990596 - * @summary Make sure that any subclass of Number can be formatted using DecimalFormat.format(). + * @summary Make sure that any subclass of Number can be formatted using + * DecimalFormat.format() without throwing an exception. + * @run junit Bug4990596 */ import java.text.DecimalFormat; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + public class Bug4990596 { - public static void main(String[] args) { - new DecimalFormat().format(new MutableInteger(0)); + // Test that a custom subclass of Number can be formatted by + // DecimalFormat without throwing an IllegalArgumentException + @Test + public void formatSubclassedNumberTest() { + assertDoesNotThrow(() -> new DecimalFormat().format(new MutableInteger(0)), + "DecimalFormat.format() should support subclasses of Number"); } + // A custom subclass of Number. Prior to this fix, if an instance of this + // class was formatted by DecimalFormat, an exception would be thrown. @SuppressWarnings("serial") public static class MutableInteger extends Number { public int value; diff --git a/test/jdk/java/text/Format/NumberFormat/Bug6278616.java b/test/jdk/java/text/Format/NumberFormat/Bug6278616.java index b1684b4d177..8f9fc7ca52d 100644 --- a/test/jdk/java/text/Format/NumberFormat/Bug6278616.java +++ b/test/jdk/java/text/Format/NumberFormat/Bug6278616.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. * 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,46 +24,55 @@ /* * @test * @summary Confirm that AtomicInteger and AtomicLong are formatted correctly. + * That is, make sure they are not treated as a double when formatted + * anymore (which can result in the loss of precision). * @bug 6278616 + * @run junit Bug6278616 */ import java.text.NumberFormat; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -import java.util.Locale; +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.assertEquals; public class Bug6278616 { - static final int[] ints = { - Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE - }; + private static final NumberFormat nf = NumberFormat.getInstance(); - static final long[] longs = { - Long.MIN_VALUE, -1, 0, 1, Long.MAX_VALUE - }; + // Test that NumberFormat formats numerically equivalent int + // and AtomicInteger values the same + @ParameterizedTest + @MethodSource("ints") + public void formattedAtomicIntTest(int testInt) { + String formattedInt = nf.format(testInt); + String formattedAtomicInt = nf.format(new AtomicInteger(testInt)); + assertEquals(formattedAtomicInt, formattedInt, "Formatting numerically" + + " equivalent AtomicInteger and int should produce the same String value"); + } - public static void main(String[] args) { - NumberFormat nf = NumberFormat.getInstance(); + // Various int values + private static int[] ints() { + return new int[] { Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE}; + } - for (int j = 0; j < ints.length; j++) { - String s_i = nf.format(ints[j]); - String s_ai = nf.format(new AtomicInteger(ints[j])); - if (!s_i.equals(s_ai)) { - throw new RuntimeException("format(AtomicInteger " + s_ai + - ") doesn't equal format(Integer " + - s_i + ")"); - } - } + // Test that NumberFormat formats numerically equivalent long + // and AtomicLong values the same + @ParameterizedTest + @MethodSource("longs") + public void formattedAtomicLongTest(long testLong) { + String formattedLong = nf.format(testLong); + String formattedAtomicLong = nf.format(new AtomicLong(testLong)); + assertEquals(formattedAtomicLong, formattedLong, "Formatting numerically" + + " equivalent AtomicLong and long should produce the same String value"); + } - for (int j = 0; j < longs.length; j++) { - String s_l = nf.format(longs[j]); - String s_al = nf.format(new AtomicLong(longs[j])); - if (!s_l.equals(s_al)) { - throw new RuntimeException("format(AtomicLong " + s_al + - ") doesn't equal format(Long " + - s_l + ")"); - } - } + // Various long values + private static long[] longs() { + return new long[] { Long.MIN_VALUE, -1, 0, 1, Long.MAX_VALUE}; } } diff --git a/test/jdk/java/text/Format/NumberFormat/Bug8132125.java b/test/jdk/java/text/Format/NumberFormat/Bug8132125.java index 04583dfd019..1f702a9ba24 100644 --- a/test/jdk/java/text/Format/NumberFormat/Bug8132125.java +++ b/test/jdk/java/text/Format/NumberFormat/Bug8132125.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * 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,20 +26,27 @@ * @bug 8132125 8202537 * @summary Checks Swiss' number elements * @modules jdk.localedata + * @run junit Bug8132125 */ -import java.text.*; -import java.util.*; +import java.text.NumberFormat; +import java.util.Locale; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class Bug8132125 { - public static void main(String[] args) { + + // Ensure the CLDRConverter does not omit the Swiss number elements + @Test + public void swissNumElementsTest() { Locale deCH = Locale.of("de", "CH"); NumberFormat nf = NumberFormat.getInstance(deCH); - String expected = "54\u2019839\u2019483.142"; // i.e. "\u2019" as decimal separator, "\u2019" as grouping separator + // "\u002E" as decimal separator, "\u2019" as grouping separator + String expected = "54\u2019839\u2019483.142"; String actual = nf.format(54839483.1415); - if (!actual.equals(expected)) { - throw new RuntimeException("incorrect for de_CH: " + expected + " vs. actual " + actual); - } + assertEquals(expected, actual, "incorrect number elements for de_CH"); } } diff --git a/test/jdk/java/text/Format/NumberFormat/CurrencyFormat.java b/test/jdk/java/text/Format/NumberFormat/CurrencyFormat.java index b3a7bb21eca..d207404f3ef 100644 --- a/test/jdk/java/text/Format/NumberFormat/CurrencyFormat.java +++ b/test/jdk/java/text/Format/NumberFormat/CurrencyFormat.java @@ -25,13 +25,17 @@ * @test * @bug 4290801 4942982 5102005 8008577 8021121 8210153 8227313 * @summary Basic tests for currency formatting. + * Tests both COMPAT and CLDR data. * @modules jdk.localedata - * @run main/othervm -Djava.locale.providers=COMPAT CurrencyFormat COMPAT - * @run main/othervm -Djava.locale.providers=CLDR CurrencyFormat CLDR + * @run junit/othervm -Djava.locale.providers=COMPAT CurrencyFormat + * @run junit/othervm -Djava.locale.providers=CLDR CurrencyFormat */ import java.io.File; import java.io.FileInputStream; +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; import java.util.Currency; import java.util.Locale; import java.util.Properties; @@ -40,126 +44,139 @@ import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.text.SimpleDateFormat; +import java.util.stream.Stream; + +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.assertEquals; public class CurrencyFormat { - private static boolean isCompat; + // Expected data is switched depending on COMPAT or CLDR + // currencySymbolsTest() is only ran for COMPAT + private static final boolean isCompat = + "COMPAT".equals(System.getProperty("java.locale.providers")); - public static void main(String[] args) throws Exception { - isCompat = "COMPAT".equals(args[0]); - testFormatting(); - testSymbols(); + // Tests the formatting of data for COMPAT + CLDR under various currencies + // Using a NumberFormat generated by getCurrencyInstance() + @ParameterizedTest + @MethodSource("currencyFormatDataProvider") + public void currencyFormatTest(String expected, Currency currency, + NumberFormat format, Locale locale) { + if (currency != null) { + format.setCurrency(currency); + int digits = currency.getDefaultFractionDigits(); + format.setMinimumFractionDigits(digits); + format.setMaximumFractionDigits(digits); + } + String result = format.format(1234.56); + assertEquals(expected, result, String.format("Failed with locale: %s%s", + locale, (currency == null ? ", default currency" : (", currency: " + currency)))); } - static void testFormatting() { - boolean failed = false; + // Generate a combination of expected data for 1234.56 formatted + // under various currencies/locale provider/locale + private static Stream currencyFormatDataProvider() { + ArrayList data = new ArrayList(); Locale[] locales = { - Locale.US, - Locale.JAPAN, - Locale.GERMANY, - Locale.ITALY, - Locale.of("it", "IT", "EURO"), - Locale.forLanguageTag("de-AT"), - Locale.forLanguageTag("fr-CH"), + Locale.US, + Locale.JAPAN, + Locale.GERMANY, + Locale.ITALY, + Locale.of("it", "IT", "EURO"), + Locale.forLanguageTag("de-AT"), + Locale.forLanguageTag("fr-CH"), }; Currency[] currencies = { - null, - Currency.getInstance("USD"), - Currency.getInstance("JPY"), - Currency.getInstance("DEM"), - Currency.getInstance("EUR"), + null, + Currency.getInstance("USD"), + Currency.getInstance("JPY"), + Currency.getInstance("DEM"), + Currency.getInstance("EUR"), }; - String[][] expecteds = { - {"$1,234.56", "$1,234.56", "JPY1,235", "DEM1,234.56", "EUR1,234.56"}, - {"\uFFE51,235", "USD1,234.56", "\uFFE51,235", "DEM1,234.56", "EUR1,234.56"}, - {"1.234,56 \u20AC", "1.234,56 USD", "1.235 JPY", "1.234,56 DM", "1.234,56 \u20AC"}, - {"\u20AC 1.234,56", "USD 1.234,56", "JPY 1.235", "DEM 1.234,56", "\u20AC 1.234,56"}, - {"\u20AC 1.234,56", "USD 1.234,56", "JPY 1.235", "DEM 1.234,56", "\u20AC 1.234,56"}, - {"\u20AC 1.234,56", "USD 1.234,56", "JPY 1.235", "DEM 1.234,56", "\u20AC 1.234,56"}, - {"SFr. 1'234.56", "USD 1'234.56", "JPY 1'235", "DEM 1'234.56", "EUR 1'234.56"}, + String[][] expectedCOMPATData = { + {"$1,234.56", "$1,234.56", "JPY1,235", "DEM1,234.56", "EUR1,234.56"}, + {"\uFFE51,235", "USD1,234.56", "\uFFE51,235", "DEM1,234.56", "EUR1,234.56"}, + {"1.234,56 \u20AC", "1.234,56 USD", "1.235 JPY", "1.234,56 DM", "1.234,56 \u20AC"}, + {"\u20AC 1.234,56", "USD 1.234,56", "JPY 1.235", "DEM 1.234,56", "\u20AC 1.234,56"}, + {"\u20AC 1.234,56", "USD 1.234,56", "JPY 1.235", "DEM 1.234,56", "\u20AC 1.234,56"}, + {"\u20AC 1.234,56", "USD 1.234,56", "JPY 1.235", "DEM 1.234,56", "\u20AC 1.234,56"}, + {"SFr. 1'234.56", "USD 1'234.56", "JPY 1'235", "DEM 1'234.56", "EUR 1'234.56"}, }; - String[][] expecteds_cldr = { - {"$1,234.56", "$1,234.56", "\u00a51,235", "DEM1,234.56", "\u20ac1,234.56"}, - {"\uFFE51,235", "$1,234.56", "\uFFE51,235", "DEM1,234.56", "\u20ac1,234.56"}, - {"1.234,56\u00a0\u20ac", "1.234,56\u00a0$", "1.235\u00a0\u00a5", "1.234,56\u00a0DM", "1.234,56\u00a0\u20ac"}, - {"1.234,56\u00a0\u20ac", "1.234,56\u00a0USD", "1.235\u00a0JPY", "1.234,56\u00a0DEM", "1.234,56\u00a0\u20ac"}, - {"1.234,56\u00a0\u20ac", "1.234,56\u00a0USD", "1.235\u00a0JPY", "1.234,56\u00a0DEM", "1.234,56\u00a0\u20ac"}, - {"\u20ac\u00a01.234,56", "$\u00a01.234,56", "\u00a5\u00a01.235", "DM\u00a01.234,56", "\u20ac\u00a01.234,56"}, - {"1\u202f234.56\u00a0CHF", "1\u202f234.56\u00a0$US", "1\u202f235\u00a0JPY", "1\u202f234.56\u00a0DEM", "1\u202f234.56\u00a0\u20ac"}, + String[][] expectedCLDRData = { + {"$1,234.56", "$1,234.56", "\u00a51,235", "DEM1,234.56", "\u20ac1,234.56"}, + {"\uFFE51,235", "$1,234.56", "\uFFE51,235", "DEM1,234.56", "\u20ac1,234.56"}, + {"1.234,56\u00a0\u20ac", "1.234,56\u00a0$", "1.235\u00a0\u00a5", "1.234,56\u00a0DM", "1.234,56\u00a0\u20ac"}, + {"1.234,56\u00a0\u20ac", "1.234,56\u00a0USD", "1.235\u00a0JPY", "1.234,56\u00a0DEM", "1.234,56\u00a0\u20ac"}, + {"1.234,56\u00a0\u20ac", "1.234,56\u00a0USD", "1.235\u00a0JPY", "1.234,56\u00a0DEM", "1.234,56\u00a0\u20ac"}, + {"\u20ac\u00a01.234,56", "$\u00a01.234,56", "\u00a5\u00a01.235", "DM\u00a01.234,56", "\u20ac\u00a01.234,56"}, + {"1\u202f234.56\u00a0CHF", "1\u202f234.56\u00a0$US", "1\u202f235\u00a0JPY", "1\u202f234.56\u00a0DEM", "1\u202f234.56\u00a0\u20ac"}, }; - for (int i = 0; i < locales.length; i++) { Locale locale = locales[i]; NumberFormat format = NumberFormat.getCurrencyInstance(locale); for (int j = 0; j < currencies.length; j++) { Currency currency = currencies[j]; - String expected = isCompat ? expecteds[i][j] : expecteds_cldr[i][j]; - if (currency != null) { - format.setCurrency(currency); - int digits = currency.getDefaultFractionDigits(); - format.setMinimumFractionDigits(digits); - format.setMaximumFractionDigits(digits); - } - String result = format.format(1234.56); - if (!result.equals(expected)) { - failed = true; - System.out.println("FAIL: Locale " + locale - + (currency == null ? ", default currency" : (", currency: " + currency)) - + ", expected: " + expected - + ", actual: " + result); - } + String expected = isCompat ? expectedCOMPATData[i][j] : expectedCLDRData[i][j]; + data.add(Arguments.of(expected, currency, format, locale)); } } - - if (failed) { - throw new RuntimeException(); - } + return data.stream(); } - static void testSymbols() throws Exception { + // Compares the expected currency symbol of a locale to the value returned by + // DecimalFormatSymbols.getCurrencySymbol(). + @ParameterizedTest + @MethodSource("currencySymbolsDataProvider") + public void currencySymbolsTest(String expected, Locale locale) throws ParseException { if (!isCompat) { - // For COMPAT only. - return; + return; // For COMPAT only. } + if (expected == null) { + System.out.println("Warning: No expected currency symbol defined for locale " + locale); + } else { + // Reserved for when a currency will change its symbol at a given time in the future + if (expected.contains(";")) { + expected = getFutureSymbol(expected); + } + DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale); + String result = symbols.getCurrencySymbol(); + assertEquals(expected, result, "Wrong currency symbol for locale " + + locale + ", expected: " + expected + ", got: " + result); + } + } - FileInputStream stream = new FileInputStream(new File(System.getProperty("test.src", "."), "CurrencySymbols.properties")); + // Grabs the custom CurrencySymbols.properties and loads the file into a Properties + // instance. Building the data set, which consists of the currency symbol for the locale. + private static Stream currencySymbolsDataProvider() throws IOException { + ArrayList data = new ArrayList(); + FileInputStream stream = new FileInputStream(new File( + System.getProperty("test.src", "."), "CurrencySymbols.properties")); Properties props = new Properties(); props.load(stream); - SimpleDateFormat format = null; - Locale[] locales = NumberFormat.getAvailableLocales(); - for (int i = 0; i < locales.length; i++) { - Locale locale = locales[i]; - DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale); - String result = symbols.getCurrencySymbol(); + for (Locale locale : locales) { String expected = (String) props.get(locale.toString()); + data.add(Arguments.of(expected, locale)); + } + return data.stream(); + } - if (expected == null) { - System.out.println("Warning: No expected currency symbol defined for locale " + locale); - } else { - if (expected.contains(";")) { - StringTokenizer tokens = new StringTokenizer(expected, ";"); - int tokensCount = tokens.countTokens(); - - if (tokensCount == 3) { - expected = tokens.nextToken(); - if (format == null) { - format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US); - format.setTimeZone(TimeZone.getTimeZone("GMT")); - format.setLenient(false); - } - - if (format.parse(tokens.nextToken()).getTime() < System.currentTimeMillis()) { - expected = tokens.nextToken(); - } - } - } - - if (!expected.equals(result)) { - throw new RuntimeException("Wrong currency symbol for locale " + - locale + ", expected: " + expected + ", got: " + result); - } + // Utility to grab the future symbol if in the right format and date cut-over allows + private static String getFutureSymbol(String expected) throws ParseException { + StringTokenizer tokens = new StringTokenizer(expected, ";"); + int tokensCount = tokens.countTokens(); + if (tokensCount == 3) { + expected = tokens.nextToken(); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US); + format.setTimeZone(TimeZone.getTimeZone("GMT")); + format.setLenient(false); + if (format.parse(tokens.nextToken()).getTime() < System.currentTimeMillis()) { + expected = tokens.nextToken(); } } + return expected; } } diff --git a/test/jdk/java/text/Format/NumberFormat/TestPeruCurrencyFormat.java b/test/jdk/java/text/Format/NumberFormat/TestPeruCurrencyFormat.java index 6ca07288723..12403b022a8 100644 --- a/test/jdk/java/text/Format/NumberFormat/TestPeruCurrencyFormat.java +++ b/test/jdk/java/text/Format/NumberFormat/TestPeruCurrencyFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * 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,27 +21,31 @@ * questions. */ -/** +/* * @test * @bug 8206879 - * @summary Currency decimal marker incorrect for Peru. * @modules jdk.localedata - * @run main/othervm -Djava.locale.providers=JRE TestPeruCurrencyFormat + * @summary Currency decimal marker incorrect for Peru (COMPAT). + * @run junit/othervm -Djava.locale.providers=COMPAT TestPeruCurrencyFormat */ import java.text.NumberFormat; import java.util.Locale; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + public class TestPeruCurrencyFormat { - public static void main(String[] args) { + // Confirm correct decimal marker for Peru locale on COMPAT + @Test + public void peruDecimalMarketCOMPAT() { final String expected = "S/.1,234.56"; NumberFormat currencyFmt = NumberFormat.getCurrencyInstance(Locale.of("es", "PE")); String s = currencyFmt.format(1234.56); - - if (!s.equals(expected)) { - throw new RuntimeException("Currency format for Peru failed, expected " + expected + ", got " + s); - } + assertEquals(expected, s, + "Currency format for Peru failed, expected " + expected + ", got " + s); } } diff --git a/test/jdk/java/util/Currency/CheckDataVersion.java b/test/jdk/java/util/Currency/CheckDataVersion.java index ba18677dbbe..303603c5b85 100644 --- a/test/jdk/java/util/Currency/CheckDataVersion.java +++ b/test/jdk/java/util/Currency/CheckDataVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import java.util.Currency; class CheckDataVersion { - static final String datafile = "tablea1.txt"; + static final String datafile = "ISO4217-list-one.txt"; static final String FILEVERSIONKEY = "FILEVERSION="; static final String DATAVERSIONKEY = "DATAVERSION="; static String fileVersion; diff --git a/test/jdk/java/util/Currency/CurrencyTest.java b/test/jdk/java/util/Currency/CurrencyTest.java index 0561b502730..f371e86e387 100644 --- a/test/jdk/java/util/Currency/CurrencyTest.java +++ b/test/jdk/java/util/Currency/CurrencyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531 * 6488442 7036905 8008577 8039317 8074350 8074351 8150324 8167143 - * 8264792 + * 8264792 8334653 * @summary Basic tests for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -59,7 +59,7 @@ public class CurrencyTest { - // 'tablea1.txt' should be up-to-date before testing + // 'ISO4217-list-one.txt' should be up-to-date before testing @Test public void dataVersionTest() { CheckDataVersion.check(); diff --git a/test/jdk/java/util/Currency/tablea1.txt b/test/jdk/java/util/Currency/ISO4217-list-one.txt similarity index 97% rename from test/jdk/java/util/Currency/tablea1.txt rename to test/jdk/java/util/Currency/ISO4217-list-one.txt index 6e85de5e6d2..1912b5cc7db 100644 --- a/test/jdk/java/util/Currency/tablea1.txt +++ b/test/jdk/java/util/Currency/ISO4217-list-one.txt @@ -1,12 +1,12 @@ # # -# Amendments up until ISO 4217 AMENDMENT NUMBER 176 -# (As of 06 December 2023) +# Amendments up until ISO 4217 AMENDMENT NUMBER 177 +# (As of 20 June 2024) # # Version FILEVERSION=3 -DATAVERSION=176 +DATAVERSION=177 # ISO 4217 currency data AF AFN 971 2 @@ -276,7 +276,7 @@ WF XPF 953 0 EH MAD 504 2 YE YER 886 2 ZM ZMW 967 2 -ZW ZWL 932 2 +ZW ZWG 924 2 #XAU XAU 959 #XBA XBA 955 #XBB XBB 956 diff --git a/test/jdk/java/util/Currency/ValidateISO4217.java b/test/jdk/java/util/Currency/ValidateISO4217.java index 53788c899b3..cd6e4f41a9f 100644 --- a/test/jdk/java/util/Currency/ValidateISO4217.java +++ b/test/jdk/java/util/Currency/ValidateISO4217.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759 * 8039317 8074350 8074351 8145952 8187946 8193552 8202026 8204269 - * 8208746 8209775 8264792 8274658 8283277 8296239 8321480 + * 8208746 8209775 8264792 8274658 8283277 8296239 8321480 8334653 * @summary Validate ISO 4217 data for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -60,7 +60,8 @@ /** * This class tests the latest ISO 4217 data and Java's currency data which is - * based on ISO 4217. The golden-data file (ISO 4217 data) 'tablea1.txt' has the following + * based on ISO 4217. The golden-data file, 'ISO4217-list-one.txt', based on the + * “List one: Currency, fund and precious metal codes” has the following * format: \t\t\t[\t\t\t\t] * The Cutover Date is given in SimpleDateFormat's 'yyyy-MM-dd-HH-mm-ss' format in the GMT time zone. */ @@ -68,7 +69,7 @@ public class ValidateISO4217 { // Input golden-data file private static final File dataFile = new File(System.getProperty( - "test.src", "."), "tablea1.txt"); + "test.src", "."), "ISO4217-list-one.txt"); // Code statuses private static final byte UNDEFINED = 0; private static final byte DEFINED = 1; @@ -89,7 +90,7 @@ public class ValidateISO4217 { + "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-HRK-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-" + "PTE-ROL-RUR-SDD-SIT-SLL-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-" + "XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-" - + "YUM-ZMK-ZWD-ZWN-ZWR"; + + "YUM-ZMK-ZWD-ZWL-ZWN-ZWR"; private static final String[][] extraCodes = { /* Defined in ISO 4217 list, but don't have code and minor unit info. */ {"AQ", "", "", "0"}, // Antarctica diff --git a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java index 04a6e89db7b..cb3d4dde914 100644 --- a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java +++ b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java @@ -25,9 +25,9 @@ * @test * @bug 8025703 8040211 8191404 8203872 8222980 8225435 8241082 8242010 8247432 * 8258795 8267038 8287180 8302512 8304761 8306031 8308021 8313702 8318322 - * 8327631 + * 8327631 8332424 8334418 * @summary Checks the IANA language subtag registry data update - * (LSR Revision: 2024-03-07) with Locale and Locale.LanguageRange + * (LSR Revision: 2024-06-14) with Locale and Locale.LanguageRange * class methods. * @run main LanguageSubtagRegistryTest */ diff --git a/test/jdk/java/util/ResourceBundle/Control/MissingResourceCauseTestRun.java b/test/jdk/java/util/ResourceBundle/Control/MissingResourceCauseTestRun.java index 30cd81757df..66a60f11ad4 100644 --- a/test/jdk/java/util/ResourceBundle/Control/MissingResourceCauseTestRun.java +++ b/test/jdk/java/util/ResourceBundle/Control/MissingResourceCauseTestRun.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 4354216 8213127 + * @bug 4354216 8213127 8334333 * @summary Test for the cause support when throwing a * MissingResourceBundle. (This test exists under * ResourceBundle/Control because bad resource bundle data can be @@ -32,6 +32,7 @@ * @build jdk.test.lib.JDKToolLauncher * jdk.test.lib.Utils * jdk.test.lib.process.ProcessTools + * jdk.test.lib.Platform * MissingResourceCauseTest * NonResourceBundle * PrivateConstructorRB @@ -50,9 +51,14 @@ import jdk.test.lib.JDKToolLauncher; import jdk.test.lib.Utils; import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Platform; +import jtreg.SkippedException; public class MissingResourceCauseTestRun { public static void main(String[] args) throws Throwable { + if (Platform.isRoot() && !Platform.isWindows()) { + throw new SkippedException("Unable to create an unreadable properties file."); + } Path path = Paths.get("UnreadableRB.properties"); Files.deleteIfExists(path); try { @@ -98,7 +104,7 @@ private static void runCmd() throws Throwable { } private static void deleteFile(Path path) throws Throwable { - if(path.toFile().exists()) { + if (path.toFile().exists()) { ProcessTools.executeCommand("chmod", "666", path.toString()) .outputTo(System.out) .errorTo(System.out) diff --git a/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java b/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java index 0f154f307f8..b6459b7b8f5 100644 --- a/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java +++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -45,57 +46,59 @@ public static void main(String[] args) throws Throwable { } static void executeTest() throws Throwable { - final ConcurrentHashMap m = new ConcurrentHashMap<>(); - final ThreadLocalRandom rnd = ThreadLocalRandom.current(); - final int nCPU = Runtime.getRuntime().availableProcessors(); - final int minWorkers = 2; - final int maxWorkers = Math.max(minWorkers, Math.min(32, nCPU)); - final int nWorkers = rnd.nextInt(minWorkers, maxWorkers + 1); - final int sizePerWorker = 1024; - final int maxSize = nWorkers * sizePerWorker; + try (var executor = Executors.newCachedThreadPool()) { + final ConcurrentHashMap m = new ConcurrentHashMap<>(); + final ThreadLocalRandom rnd = ThreadLocalRandom.current(); + final int nCPU = Runtime.getRuntime().availableProcessors(); + final int minWorkers = 2; + final int maxWorkers = Math.max(minWorkers, Math.min(32, nCPU)); + final int nWorkers = rnd.nextInt(minWorkers, maxWorkers + 1); + final int sizePerWorker = 1024; + final int maxSize = nWorkers * sizePerWorker; - // The foreman busy-checks that the size of the arrays obtained - // from the keys and values views grows monotonically until it - // reaches the maximum size. + // The foreman busy-checks that the size of the arrays obtained + // from the keys and values views grows monotonically until it + // reaches the maximum size. - // NOTE: these size constraints are not specific to toArray and are - // applicable to any form of traversal of the collection views - CompletableFuture foreman = CompletableFuture.runAsync(new Runnable() { - private int prevSize = 0; + // NOTE: these size constraints are not specific to toArray and are + // applicable to any form of traversal of the collection views + CompletableFuture foreman = CompletableFuture.runAsync(new Runnable() { + private int prevSize = 0; - private boolean checkProgress(Object[] a) { - int size = a.length; - if (size < prevSize || size > maxSize) - throw new AssertionError( - String.format("prevSize=%d size=%d maxSize=%d", - prevSize, size, maxSize)); - prevSize = size; - return size == maxSize; - } + private boolean checkProgress(Object[] a) { + int size = a.length; + if (size < prevSize || size > maxSize) + throw new AssertionError( + String.format("prevSize=%d size=%d maxSize=%d", + prevSize, size, maxSize)); + prevSize = size; + return size == maxSize; + } - public void run() { - Integer[] empty = new Integer[0]; - for (;;) - if (checkProgress(m.values().toArray()) - & checkProgress(m.keySet().toArray()) - & checkProgress(m.values().toArray(empty)) - & checkProgress(m.keySet().toArray(empty))) - return; - } - }); + public void run() { + Integer[] empty = new Integer[0]; + for (; ; ) + if (checkProgress(m.values().toArray()) + & checkProgress(m.keySet().toArray()) + & checkProgress(m.values().toArray(empty)) + & checkProgress(m.keySet().toArray(empty))) + return; + } + }, executor); - // Each worker puts globally unique keys into the map - List> workers = - IntStream.range(0, nWorkers) - .mapToObj(w -> (Runnable) () -> { - for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++) - m.put(o + i, i); - }) - .map(CompletableFuture::runAsync) - .collect(Collectors.toList()); + // Each worker puts globally unique keys into the map + List> workers = + IntStream.range(0, nWorkers) + .mapToObj(w -> (Runnable) () -> { + for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++) + m.put(o + i, i); + }) + .map(r -> CompletableFuture.runAsync(r, executor)) + .collect(Collectors.toList()); - // Wait for workers and foreman to complete - workers.forEach(CompletableFuture::join); - foreman.join(); + // Wait for workers and foreman to complete + workers.forEach(CompletableFuture::join); + foreman.join(); + } } } diff --git a/test/jdk/java/util/concurrent/SynchronousQueue/Fairness.java b/test/jdk/java/util/concurrent/SynchronousQueue/Fairness.java index deb4b6b1616..3662fd74609 100644 --- a/test/jdk/java/util/concurrent/SynchronousQueue/Fairness.java +++ b/test/jdk/java/util/concurrent/SynchronousQueue/Fairness.java @@ -23,20 +23,45 @@ /* * @test + * @modules java.base/java.util.concurrent:open * @bug 4992438 6633113 * @summary Checks that fairness setting is respected. */ +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Fairness { - private static void testFairness(boolean fair, - final BlockingQueue q) + private final static VarHandle underlyingTransferQueueAccess; + + static { + try { + underlyingTransferQueueAccess = + MethodHandles.privateLookupIn( + SynchronousQueue.class, + MethodHandles.lookup() + ).findVarHandle( + SynchronousQueue.class, + "transferer", + Class.forName(SynchronousQueue.class.getName() + "$Transferer") + ); + } catch (Exception ex) { + throw new ExceptionInInitializerError(ex); + } + } + + + private static void testFairness(boolean fair, final SynchronousQueue q) throws Throwable { + final LinkedTransferQueue underlying = + (LinkedTransferQueue)underlyingTransferQueueAccess.get(q); + final ReentrantLock lock = new ReentrantLock(); final Condition ready = lock.newCondition(); final int threadCount = 10; @@ -53,9 +78,12 @@ private static void testFairness(boolean fair, } catch (Throwable t) { badness[0] = t; }}}; t.start(); ready.await(); - // Probably unnecessary, but should be bullet-proof - while (t.getState() == Thread.State.RUNNABLE) + // Wait until previous put:ing thread is provably parked + while (underlying.size() < (i + 1)) Thread.yield(); + + if (underlying.size() > (i + 1)) + throw new Error("Unexpected number of waiting producers: " + i); } for (int i = 0; i < threadCount; i++) { int j = q.take(); @@ -68,8 +96,8 @@ private static void testFairness(boolean fair, } public static void main(String[] args) throws Throwable { - testFairness(false, new SynchronousQueue()); - testFairness(false, new SynchronousQueue(false)); - testFairness(true, new SynchronousQueue(true)); + testFairness(false, new SynchronousQueue<>()); + testFairness(false, new SynchronousQueue<>(false)); + testFairness(true, new SynchronousQueue<>(true)); } } diff --git a/test/jdk/java/util/concurrent/tck/ForkJoinPool9Test.java b/test/jdk/java/util/concurrent/tck/ForkJoinPool9Test.java index 266c2a036fe..a87aa7b916b 100644 --- a/test/jdk/java/util/concurrent/tck/ForkJoinPool9Test.java +++ b/test/jdk/java/util/concurrent/tck/ForkJoinPool9Test.java @@ -79,6 +79,9 @@ public void testCommonPoolThreadContextClassLoader() throws Throwable { assertSame(ForkJoinPool.commonPool(), ForkJoinTask.getPool()); Thread currentThread = Thread.currentThread(); + ClassLoader preexistingContextClassLoader = + currentThread.getContextClassLoader(); + Stream.of(systemClassLoader, null).forEach(cl -> { if (randomBoolean()) // should always be permitted, without effect @@ -95,6 +98,11 @@ public void testCommonPoolThreadContextClassLoader() throws Throwable { () -> System.getProperty("foo"), () -> currentThread.setContextClassLoader( classLoaderDistinctFromSystemClassLoader)); + else { + currentThread.setContextClassLoader(classLoaderDistinctFromSystemClassLoader); + assertSame(currentThread.getContextClassLoader(), classLoaderDistinctFromSystemClassLoader); + currentThread.setContextClassLoader(preexistingContextClassLoader); + } // TODO ? // if (haveSecurityManager // && Thread.currentThread().getClass().getSimpleName() diff --git a/test/jdk/java/util/concurrent/tck/JSR166TestCase.java b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java index 21aa43e1816..cf60a430ad0 100644 --- a/test/jdk/java/util/concurrent/tck/JSR166TestCase.java +++ b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java @@ -666,6 +666,7 @@ public static Test suite() { if (atLeastJava20()) { String[] java20TestClassNames = { "ForkJoinPool20Test", + "SynchronousQueue20Test", }; addNamedTestClasses(suite, java20TestClassNames); } diff --git a/test/jdk/java/util/concurrent/tck/SynchronousQueue20Test.java b/test/jdk/java/util/concurrent/tck/SynchronousQueue20Test.java new file mode 100644 index 00000000000..bbe3a2e98aa --- /dev/null +++ b/test/jdk/java/util/concurrent/tck/SynchronousQueue20Test.java @@ -0,0 +1,95 @@ +/* + * 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 file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + * Other contributors include Andrew Wright, Jeffrey Hayes, + * Pat Fisher, Mike Judd. + */ + +import junit.framework.Test; + +import java.util.Collections; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.TimeUnit; + +public class SynchronousQueue20Test extends JSR166TestCase { + + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return newTestSuite(SynchronousQueue20Test.class); + } + + public void testFairDoesntLeak() throws InterruptedException { + assertDoesntLeak(new SynchronousQueue<>(true)); + } + + public void testUnfairDoesntLeak() throws InterruptedException { + assertDoesntLeak(new SynchronousQueue<>(false)); + } + + private void assertDoesntLeak(SynchronousQueue queue) throws InterruptedException { + final int NUMBER_OF_ITEMS = 250; + final int ROUND_WAIT_MILLIS = 50; + + class Item {} + final Map survivors = + Collections.synchronizedMap(WeakHashMap.newWeakHashMap(NUMBER_OF_ITEMS)); + + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + for(int i = 0;i < NUMBER_OF_ITEMS;++i) { + executor.submit(() -> { + var item = new Item(); + survivors.put(item, null); + queue.put(item); + return null; + }); + + executor.submit(() -> { + queue.take(); + return null; + }); + } + } // Close waits until all tasks are done + + while(!survivors.isEmpty()) { + System.gc(); + Thread.sleep(ROUND_WAIT_MILLIS); // We don't expect interruptions + } + + assertTrue(queue.isEmpty()); // Make sure that the queue survives until the end + } + +} diff --git a/test/jdk/java/util/concurrent/tck/SynchronousQueueTest.java b/test/jdk/java/util/concurrent/tck/SynchronousQueueTest.java index 7d17fac4d35..5d5c53f92e4 100644 --- a/test/jdk/java/util/concurrent/tck/SynchronousQueueTest.java +++ b/test/jdk/java/util/concurrent/tck/SynchronousQueueTest.java @@ -652,5 +652,4 @@ public void testNeverContainsNull() { assertFalse(q.contains(null)); assertFalse(q.remove(null)); } - } diff --git a/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java b/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java index 114816d4787..e8abec354ed 100644 --- a/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java +++ b/test/jdk/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,15 +101,12 @@ public void isMultiReleaseJar() throws Exception { testCustomMultiReleaseValue("true", true); testCustomMultiReleaseValue("true\r\nOther: value", true); testCustomMultiReleaseValue("true\nOther: value", true); - // JDK-8200530: '\r' support in Manifest/Attributes will be addressed separately - // testCustomMultiReleaseValue("true\rOther: value", true); + testCustomMultiReleaseValue("true\rOther: value", true); testCustomMultiReleaseValue("false", false); testCustomMultiReleaseValue(" true", false); testCustomMultiReleaseValue("true ", false); testCustomMultiReleaseValue("true\n true", false); - - // JDK-8200530: '\r' support in Manifest/Attributes will be addressed separately testCustomMultiReleaseValue("true\r true", false); testCustomMultiReleaseValue("true\r\n true", false); diff --git a/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexResetUpdate.java b/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexResetUpdate.java index f0796bed901..032457aedb3 100644 --- a/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexResetUpdate.java +++ b/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexResetUpdate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ public void run(List properties) throws Exception { TIMEOUT_FACTOR = Double.parseDouble(toFactor); } static int adjustCount(int count) { - return (int) Math.ceil(TIMEOUT_FACTOR * count); + return Math.min(count, (int) Math.ceil(TIMEOUT_FACTOR * count)); } private static final String PREFIX = @@ -211,21 +211,20 @@ static void test(String name, List properties) ReferenceQueue queue = new ReferenceQueue(); WeakReference fooRef = new WeakReference<>(Logger.getLogger("com.foo"), queue); - if (fooRef.get() != fooChild.getParent()) { + if (!fooRef.refersTo(fooChild.getParent())) { throw new RuntimeException("Unexpected parent logger: " + fooChild.getParent() +"\n\texpected: " + fooRef.get()); } WeakReference barRef = new WeakReference<>(Logger.getLogger("com.bar"), queue); - if (barRef.get() != barChild.getParent()) { + if (!barRef.refersTo(barChild.getParent())) { throw new RuntimeException("Unexpected parent logger: " + barChild.getParent() +"\n\texpected: " + barRef.get()); } Reference ref2; - int max = adjustCount(3); + int max = adjustCount(6); barChild = null; - while ((ref2 = queue.poll()) == null) { + while ((ref2 = queue.remove(500)) == null) { System.gc(); - Thread.sleep(1000); if (--max == 0) break; } @@ -347,7 +346,7 @@ static void test(String name, List properties) throw new RuntimeException("Unexpected reference: " + ref2 +"\n\texpected: " + fooRef); } - if (ref2.get() != null) { + if (!ref2.refersTo(null)) { throw new RuntimeException("Referent not cleared: " + ref2.get()); } System.out.println("Got fooRef after reset(), fooChild is " + fooChild); diff --git a/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexUpdate.java b/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexUpdate.java index a8d3240b976..2f9f360d7d4 100644 --- a/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexUpdate.java +++ b/test/jdk/java/util/logging/LogManager/Configuration/updateConfiguration/HandlersOnComplexUpdate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ public void run(List properties) throws Exception { TIMEOUT_FACTOR = Double.parseDouble(toFactor); } static int adjustCount(int count) { - return (int) Math.ceil(TIMEOUT_FACTOR * count); + return Math.min(count, (int) Math.ceil(TIMEOUT_FACTOR * count)); } private static final String PREFIX = @@ -211,21 +211,20 @@ static void test(String name, List properties) ReferenceQueue queue = new ReferenceQueue(); WeakReference fooRef = new WeakReference<>(Logger.getLogger("com.foo"), queue); - if (fooRef.get() != fooChild.getParent()) { + if (!fooRef.refersTo(fooChild.getParent())) { throw new RuntimeException("Unexpected parent logger: " + fooChild.getParent() +"\n\texpected: " + fooRef.get()); } WeakReference barRef = new WeakReference<>(Logger.getLogger("com.bar"), queue); - if (barRef.get() != barChild.getParent()) { + if (!barRef.refersTo(barChild.getParent())) { throw new RuntimeException("Unexpected parent logger: " + barChild.getParent() +"\n\texpected: " + barRef.get()); } Reference ref2; - int max = adjustCount(3); + int max = adjustCount(6); barChild = null; - while ((ref2 = queue.poll()) == null) { + while ((ref2 = queue.remove(500)) == null) { System.gc(); - Thread.sleep(1000); if (--max == 0) break; } @@ -335,7 +334,7 @@ static void test(String name, List properties) throw new RuntimeException("Unexpected reference: " + ref2 +"\n\texpected: " + fooRef); } - if (ref2.get() != null) { + if (!ref2.refersTo(null)) { throw new RuntimeException("Referent not cleared: " + ref2.get()); } System.out.println("Got fooRef after reset(), fooChild is " + fooChild); diff --git a/test/jdk/java/util/zip/DataDescriptorSignatureMissing.java b/test/jdk/java/util/zip/DataDescriptorSignatureMissing.java index f7a2ae2f8eb..db641ccba4c 100644 --- a/test/jdk/java/util/zip/DataDescriptorSignatureMissing.java +++ b/test/jdk/java/util/zip/DataDescriptorSignatureMissing.java @@ -1,5 +1,6 @@ /* * Copyright 2012 Google, Inc. All Rights Reserved. + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * 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,124 +25,137 @@ /** * @test * @bug 8056934 - * @summary Check ability to read zip files created by python zipfile - * implementation, which fails to write optional (but recommended) data - * descriptor signatures. Repro scenario is a Java -> Python -> Java round trip: - * - ZipOutputStream creates zip file with DEFLATED entries and data - * descriptors with optional signature "PK0x0708". - * - Python reads those entries, preserving the 0x08 flag byte - * - Python outputs those entries with data descriptors lacking the - * optional signature. - * - ZipInputStream cannot handle the missing signature - * + * @summary Verify the ability to read zip files whose local header + * data descriptor is missing the optional signature + *

* No way to adapt the technique in this test to get a ZIP64 zip file * without data descriptors was found. - * - * @ignore This test has brittle dependencies on an external working python. + * @run junit DataDescriptorSignatureMissing */ + +import org.junit.jupiter.api.Test; + import java.io.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; import java.util.zip.*; -public class DataDescriptorSignatureMissing { - void printStream(InputStream is) throws IOException { - Reader r = new InputStreamReader(is); - StringBuilder sb = new StringBuilder(); - char[] buf = new char[1024]; - int n; - while ((n = r.read(buf)) > 0) { - sb.append(buf, 0, n); - } - System.out.print(sb); - } +import static org.junit.jupiter.api.Assertions.*; + +public class DataDescriptorSignatureMissing { + + /** + * Verify that ZipInputStream correctly parses a ZIP with a Data Descriptor without + * the recommended but optional signature. + */ + @Test + public void shouldParseSignaturelessDescriptor() throws IOException { + // The ZIP with a signature-less descriptor + byte[] zip = makeZipWithSignaturelessDescriptor(); - int entryCount(File zipFile) throws IOException { - try (FileInputStream fis = new FileInputStream(zipFile); - ZipInputStream zis = new ZipInputStream(fis)) { - for (int count = 0;; count++) - if (zis.getNextEntry() == null) - return count; + // ZipInputStream should read the signature-less data descriptor + try (ZipInputStream in = new ZipInputStream( + new ByteArrayInputStream(zip))) { + ZipEntry first = in.getNextEntry(); + assertNotNull(first, "Zip file is unexpectedly missing first entry"); + assertEquals("first", first.getName()); + assertArrayEquals("first".getBytes(StandardCharsets.UTF_8), in.readAllBytes()); + + ZipEntry second = in.getNextEntry(); + assertNotNull(second, "Zip file is unexpectedly missing second entry"); + assertEquals("second", second.getName()); + assertArrayEquals("second".getBytes(StandardCharsets.UTF_8), in.readAllBytes()); } + } - void test(String[] args) throws Throwable { - if (! new File("/usr/bin/python").canExecute()) - return; - - // Create a java zip file with DEFLATED entries and data - // descriptors with signatures. - final File in = new File("in.zip"); - final File out = new File("out.zip"); - final int count = 3; - try (FileOutputStream fos = new FileOutputStream(in); - ZipOutputStream zos = new ZipOutputStream(fos)) { - for (int i = 0; i < count; i++) { - ZipEntry ze = new ZipEntry("hello.python" + i); - ze.setMethod(ZipEntry.DEFLATED); - zos.putNextEntry(ze); - zos.write(new byte[10]); - zos.closeEntry(); - } + /** + * The 'Data descriptor' record is used to facilitate ZIP streaming. If the size of an + * entry is unknown at the time the LOC header is written, bit 3 of the General Purpose Bit Flag + * is set, and the File data is immediately followed by the 'Data descriptor' record. This record + * then contains the compressed and uncompressed sizes of the entry and also the CRC value. + * + * The 'Data descriptor' record is usually preceded by the recommended, but optional + * signature value 0x08074b50. + * + * A ZIP entry in streaming mode has the following structure: + * + * ------ Local File Header ------ + * 000000 signature 0x04034b50 + * 000004 version 20 + * 000006 flags 0x0808 # Notice bit 3 is set + * [..] Omitted for brevity + * + * ------ File Data ------ + * 000035 data 7 bytes + * + * ------ Data Descriptor ------ + * 000042 signature 0x08074b50 + * 000046 crc 0x3610a686 + * 000050 csize 7 + * 000054 size 5 + * + * A signature-less data descriptor will look like the following: + * + * ------ Data Descriptor ------ + * 000042 crc 0x3610a686 + * 000046 csize 7 + * 000050 size 5 + * + * This method produces a ZIP with two entries, where the first entry + * is made signature-less. + */ + private static byte[] makeZipWithSignaturelessDescriptor() throws IOException { + // Offset of the signed data descriptor + int sigOffset; + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try (ZipOutputStream zo = new ZipOutputStream(out)) { + // Write a first entry + zo.putNextEntry(new ZipEntry("first")); + zo.write("first".getBytes(StandardCharsets.UTF_8)); + // Force the data descriptor to be written out + zo.closeEntry(); + // Signed data descriptor starts 16 bytes before current offset + sigOffset = out.size() - 4 * Integer.BYTES; + // Add a second entry + zo.putNextEntry(new ZipEntry("second")); + zo.write("second".getBytes(StandardCharsets.UTF_8)); } - // Copy the zip file using python's zipfile module - String[] python_program_lines = { - "import os", - "import zipfile", - "input_zip = zipfile.ZipFile('in.zip', mode='r')", - "output_zip = zipfile.ZipFile('out.zip', mode='w')", - "count08 = 0", - "for input_info in input_zip.infolist():", - " output_info = input_info", - " if output_info.flag_bits & 0x08 == 0x08:", - " count08 += 1", - " output_zip.writestr(output_info, input_zip.read(input_info))", - "output_zip.close()", - "if count08 == 0:", - " raise ValueError('Expected to see entries with 0x08 flag_bits set')", - }; - StringBuilder python_program_builder = new StringBuilder(); - for (String line : python_program_lines) - python_program_builder.append(line).append('\n'); - String python_program = python_program_builder.toString(); - String[] cmdline = { "/usr/bin/python", "-c", python_program }; - ProcessBuilder pb = new ProcessBuilder(cmdline); - pb.redirectErrorStream(true); - Process p = pb.start(); - printStream(p.getInputStream()); - p.waitFor(); - equal(p.exitValue(), 0); - - File pythonZipFile = new File("out.zip"); - check(pythonZipFile.exists()); - - equal(entryCount(in), - entryCount(out)); - - // We expect out to be identical to in, except for the removal of - // the optional data descriptor signatures. - final int SIG_LENGTH = 4; // length of a zip signature - PKxx - equal(in.length(), - out.length() + SIG_LENGTH * count); - - in.delete(); - out.delete(); - } + // The generated ZIP file with a signed data descriptor + byte[] sigZip = out.toByteArray(); + + // The offset of the CRC immediately following the 4-byte signature + int crcOffset = sigOffset + Integer.BYTES; + + // Create a ZIP file with a signature-less data descriptor for the first entry + ByteArrayOutputStream sigLess = new ByteArrayOutputStream(); + sigLess.write(sigZip, 0, sigOffset); + // Skip the signature + sigLess.write(sigZip, crcOffset, sigZip.length - crcOffset); + + byte[] siglessZip = sigLess.toByteArray(); - //--------------------- Infrastructure --------------------------- - volatile int passed = 0, failed = 0; - void pass() {passed++;} - void fail() {failed++; Thread.dumpStack();} - void fail(String msg) {System.err.println(msg); fail();} - void unexpected(Throwable t) {failed++; t.printStackTrace();} - void check(boolean cond) {if (cond) pass(); else fail();} - void equal(Object x, Object y) { - if (x == null ? y == null : x.equals(y)) pass(); - else fail(x + " not equal to " + y);} - public static void main(String[] args) throws Throwable { - new DataDescriptorSignatureMissing().instanceMain(args);} - public void instanceMain(String[] args) throws Throwable { - try {test(args);} catch (Throwable t) {unexpected(t);} - System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); - if (failed > 0) throw new AssertionError("Some tests failed");} + // Adjust the CEN offset in the END header + ByteBuffer buffer = ByteBuffer.wrap(siglessZip).order(ByteOrder.LITTLE_ENDIAN); + // Reduce cenOffset by 4 bytes + int cenOff = siglessZip.length - ZipFile.ENDHDR + ZipFile.ENDOFF; + int realCenOff = buffer.getInt(cenOff) - Integer.BYTES; + buffer.putInt(cenOff, realCenOff); + + // Adjust the LOC offset in the second CEN header + int cen = realCenOff; + // Skip past the first CEN header + int nlen = buffer.getShort(cen + ZipFile.CENNAM); + cen += ZipFile.CENHDR + nlen; + + // Reduce LOC offset by 4 bytes + int locOff = cen + ZipFile.CENOFF; + buffer.putInt(locOff, buffer.getInt(locOff) - Integer.BYTES); + + return siglessZip; + } } diff --git a/test/jdk/java/util/zip/ZipFile/ReadLongZipFileName.java b/test/jdk/java/util/zip/ZipFile/ReadLongZipFileName.java index c4e47193e14..d6fa7269ff0 100644 --- a/test/jdk/java/util/zip/ZipFile/ReadLongZipFileName.java +++ b/test/jdk/java/util/zip/ZipFile/ReadLongZipFileName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,114 +21,80 @@ * questions. */ -/** +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +/* * @test * @bug 6374379 - * @library /test/lib - * @build jdk.test.lib.Platform - * jdk.test.lib.util.FileUtils - * @run main ReadLongZipFileName * @summary Verify that we can read zip file names > 255 chars long + * @run junit ReadLongZipFileName */ - -import java.io.*; -import java.util.jar.*; -import java.util.Stack; -import jdk.test.lib.util.FileUtils; - public class ReadLongZipFileName { - private static String entryName = "testFile.txt";; + private static final String ENTRY_NAME = "testFile.txt"; + private static final String LONG_DIR_NAME = "abcdefghijklmnopqrstuvwx"; // 24 chars + private static final String JAR_FILE_NAME = "areallylargejarfilename.jar"; // 27 chars - public static void realMain(String args[]) { - String longDirName = "abcdefghijklmnopqrstuvwx"; // 24 chars. - String jarFileName = "areallylargejarfilename.jar"; // 27 chars. - File file = null; - File myJarFile = null; - int currentFileLength = 0; - int minRequiredLength = 600; // long enough to definitely fail. - Stack directories = new Stack(); + /* + * Creates a jar file at a path whose path name length and jar file name length + * combined is large. Then use the java.util.jar.JarFile APIs to open and read the jar file + * to verify the APIs work against those jar/zip files. + */ + @Test + public void testOpenAndReadJarFile() throws Exception { + int minRequiredPathLength = 600; // long enough to definitely fail. + Path tmpDir = Files.createTempDirectory(Path.of("."), "ReadLongZipFileName-test") + .normalize().toAbsolutePath(); + // Create a directory structure long enough that the filename will + // put us over the minRequiredLength. + int currentPathLength = 0; + Path jarFileDir = tmpDir; + do { + jarFileDir = jarFileDir.resolve(LONG_DIR_NAME); + Files.createDirectories(jarFileDir); + currentPathLength = jarFileDir.toFile().getCanonicalPath().length(); + } while (currentPathLength < (minRequiredPathLength - JAR_FILE_NAME.length())); - String filename = "." + File.separator; - try { - // Create a directory structure long enough that the filename will - // put us over the minRequiredLength. - do { - filename = filename + longDirName + File.separator; - file = new File(filename); - file.mkdir(); - currentFileLength = file.getCanonicalPath().length(); - directories.push(file); - } while (currentFileLength < (minRequiredLength - jarFileName.length())); - - // Create a new Jar file: use jar instead of zip to make sure long - // names work for both zip and jar subclass. - filename = filename + jarFileName; - JarOutputStream out = new JarOutputStream( - new BufferedOutputStream( - new FileOutputStream(filename.toString()))); - out.putNextEntry(new JarEntry(entryName)); + // Create a new Jar file: use jar instead of zip to make sure long + // names work for both zip and jar subclass. + Path jarFilePath = jarFileDir.resolve(JAR_FILE_NAME); + System.out.println("creating a jar file at " + jarFilePath); + try (JarOutputStream out = new JarOutputStream( + new BufferedOutputStream(Files.newOutputStream(jarFilePath)))) { + out.putNextEntry(new JarEntry(ENTRY_NAME)); out.write(1); - out.close(); - myJarFile = new File(filename.toString()); - currentFileLength = myJarFile.getCanonicalPath().length(); - if (!myJarFile.exists()) { - fail("Jar file does not exist."); - } - } catch (IOException e) { - unexpected(e, "Problem creating the Jar file."); } + assertTrue(Files.isRegularFile(jarFilePath), + "jar file " + jarFilePath + " does not exist or is not a file"); - try { - JarFile readJarFile = new JarFile(myJarFile); - JarEntry je = readJarFile.getJarEntry(entryName); - check(je != null); - DataInputStream dis = new DataInputStream( - readJarFile.getInputStream(je)); + try (JarFile readJarFile = new JarFile(jarFilePath.toFile())) { + JarEntry je = readJarFile.getJarEntry(ENTRY_NAME); + assertNotNull(je, "missing jar entry: " + ENTRY_NAME + " in jar file " + jarFilePath); + DataInputStream dis = new DataInputStream(readJarFile.getInputStream(je)); byte val = dis.readByte(); - check(val == 1); + assertEquals(1, val, "unexpected byte " + val + " read from entry " + ENTRY_NAME); try { dis.readByte(); - fail("Read past expected EOF"); + Assertions.fail("Read past expected EOF"); } catch (IOException e) { - pass(); - } - readJarFile.close(); - pass("Opened Jar file for reading with a name " + currentFileLength - + " characters long"); - } catch (IOException e) { - unexpected(e, "Test failed - problem reading the Jar file back in."); - } - - if (myJarFile != null) { - check(myJarFile.delete()); - } - - while (! directories.empty()) { - File f = directories.pop(); - try { - FileUtils.deleteFileWithRetry(f.toPath()); - } catch (IOException e) { - unexpected(e, "Fail to clean up directory, " + f); - break; + // expected + System.out.println("received the expected exception: " + e); } } + System.out.println("Successfully opened and read contents from a jar file with a name " + + jarFilePath.toFile().getCanonicalPath().length() + " characters long"); } - - //--------------------- Infrastructure --------------------------- - static volatile int passed = 0, failed = 0; - static void pass() {passed++;} - static void pass(String msg) {System.out.println(msg); passed++;} - static void fail() {failed++; Thread.dumpStack();} - static void fail(String msg) {System.out.println(msg); fail();} - static void unexpected(Throwable t) {failed++; t.printStackTrace();} - static void unexpected(Throwable t, String msg) { - System.out.println(msg); failed++; t.printStackTrace();} - static void check(boolean cond) {if (cond) pass(); else fail();} - static void equal(Object x, Object y) { - if (x == null ? y == null : x.equals(y)) pass(); - else fail(x + " not equal to " + y);} - public static void main(String[] args) throws Throwable { - try {realMain(args);} catch (Throwable t) {unexpected(t);} - System.out.println("\nPassed = " + passed + " failed = " + failed); - if (failed > 0) throw new AssertionError("Some tests failed");} } diff --git a/test/jdk/javax/crypto/KEM/RSA_KEM.java b/test/jdk/javax/crypto/KEM/RSA_KEM.java index c46ded77623..e666df432a6 100644 --- a/test/jdk/javax/crypto/KEM/RSA_KEM.java +++ b/test/jdk/javax/crypto/KEM/RSA_KEM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ * @modules java.base/sun.security.jca * java.base/sun.security.rsa * java.base/sun.security.util + * java.base/javax.crypto:+open */ import sun.security.jca.JCAUtil; import sun.security.rsa.RSACore; @@ -88,7 +89,7 @@ public static void main(String[] args) throws Exception { KeyPair kp = g.generateKeyPair(); for (RSAKEMParameterSpec kspec : kspecs) { SecretKey cek = KeyGenerator.getInstance("AES").generateKey(); - KEM kem1 = KEM.getInstance("RSA-KEM", p); + KEM kem1 = getKemImpl(p); Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); c.init(Cipher.ENCRYPT_MODE, cek, new IvParameterSpec(iv)); byte[] ciphertext = c.doFinal(msg); @@ -101,7 +102,7 @@ public static void main(String[] args) throws Exception { AlgorithmParameters a = AlgorithmParameters.getInstance("RSA-KEM", p); a.init(enc.params()); - KEM kem2 = KEM.getInstance("RSA-KEM", p); + KEM kem2 = getKemImpl(p); KEM.Decapsulator d = kem2.newDecapsulator(kp.getPrivate(), a.getParameterSpec(AlgorithmParameterSpec.class)); SecretKey k = d.decapsulate(enc.encapsulation(), 0, d.secretSize(), "AES"); Cipher c3 = Cipher.getInstance(kspec.encAlg); @@ -122,6 +123,14 @@ public static void main(String[] args) throws Exception { } } + // To bypass the JCE security provider signature check + private static KEM getKemImpl(Provider p) throws Exception { + var ctor = KEM.class.getDeclaredConstructor( + String.class, KEMSpi.class, Provider.class); + ctor.setAccessible(true); + return ctor.newInstance("RSA-KEM", new KEMImpl(), p); + } + static final String RSA_KEM = "1.2.840.113549.1.9.16.3.14"; static final String KEM_RSA = "1.0.18033.2.2.4"; diff --git a/test/jdk/javax/crypto/SecretKeyFactory/evilprov/Makefile b/test/jdk/javax/crypto/SecretKeyFactory/evilprov/Makefile index 918c31f0947..800e1817b42 100644 --- a/test/jdk/javax/crypto/SecretKeyFactory/evilprov/Makefile +++ b/test/jdk/javax/crypto/SecretKeyFactory/evilprov/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ JAVABIN=$(JAVA_BASE)/bin JAVAC=$(JAVABIN)/javac JAVA=$(JAVABIN)/java -JAR=$(JAVABIN)/jar +JAR=$(JAVABIN)/jar JARSIGNER=$(JAVABIN)/jarsigner # Compile-time flags and paths diff --git a/test/jdk/javax/imageio/plugins/jpeg/LargeAdobeMarkerSegmentTest.java b/test/jdk/javax/imageio/plugins/jpeg/LargeAdobeMarkerSegmentTest.java new file mode 100644 index 00000000000..e682fe6d600 --- /dev/null +++ b/test/jdk/javax/imageio/plugins/jpeg/LargeAdobeMarkerSegmentTest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023 Alphabet LLC. All Rights Reserved. + * 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 6355567 + * @summary Verifies that AdobeMarkerSegment() keeps the available bytes + * and buffer pointer in sync, when a non-standard length Adobe + * marker is encountered. + */ + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; + +public class LargeAdobeMarkerSegmentTest { + + private static String fileName = "jdk_6355567.jpg"; + + public static void main(String[] args) throws IOException { + /* + * Open a JPEG image, and get the metadata. Without the fix for + * 6355567, a NegativeArraySizeException is thrown while reading + * the metadata from the JPEG below. + */ + String sep = System.getProperty("file.separator"); + String dir = System.getProperty("test.src", "."); + String filePath = dir+sep+fileName; + System.out.println("Test file: " + filePath); + File f = new File(filePath); + ImageInputStream iis = ImageIO.createImageInputStream(f); + ImageReader r = ImageIO.getImageReaders(iis).next(); + r.setInput(iis); + r.getImageMetadata(0); + } +} diff --git a/test/jdk/javax/imageio/plugins/jpeg/jdk_6355567.jpg b/test/jdk/javax/imageio/plugins/jpeg/jdk_6355567.jpg new file mode 100644 index 00000000000..608bf27a046 Binary files /dev/null and b/test/jdk/javax/imageio/plugins/jpeg/jdk_6355567.jpg differ diff --git a/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java b/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java index 7a3236a888e..1566ebd03aa 100644 --- a/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java +++ b/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -171,7 +171,7 @@ public synchronized void start() throws Exception { AtomicBoolean error = new AtomicBoolean(false); AtomicBoolean bindError = new AtomicBoolean(false); // The predicate below tries to recognise failures. On a port clash, it sees e.g. - // Error: Exception thrown by the agent : java.rmi.server.ExportException: Port already in use: 46481; nested exception is: + // Error: Exception thrown by the agent: java.rmi.server.ExportException: Port already in use: 46481; nested exception is: // ...and will never see "main enter" from TestApp. p = ProcessTools.startProcess( TEST_APP_NAME + "{" + name + "}", diff --git a/test/jdk/javax/net/ssl/SSLSession/ServerNameRejectedTLSSessionResumption.java b/test/jdk/javax/net/ssl/SSLSession/ServerNameRejectedTLSSessionResumption.java new file mode 100644 index 00000000000..f80f3402c7e --- /dev/null +++ b/test/jdk/javax/net/ssl/SSLSession/ServerNameRejectedTLSSessionResumption.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * 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.nio.ByteBuffer; +import java.util.List; +import java.util.Objects; + +import javax.net.ssl.SNIHostName; +import javax.net.ssl.SNIMatcher; +import javax.net.ssl.SNIServerName; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.StandardConstants; + +/* + * @test + * @bug 8301686 + * @summary verifies that if the server rejects session resumption due to SNI + * mismatch, during TLS handshake, then the subsequent communication + * between the server and the client happens correctly without any + * errors + * @library /javax/net/ssl/templates + * @run main/othervm -Djavax.net.debug=all + * ServerNameRejectedTLSSessionResumption + */ +public class ServerNameRejectedTLSSessionResumption + extends SSLContextTemplate { + + private static final String CLIENT_REQUESTED_SNI = "client.local"; + // dummy host, no connection is attempted in this test + private static final String PEER_HOST = "foobar"; + // dummy port, no connection is attempted in this test + private static final int PEER_PORT = 12345; + + public static void main(final String[] args) throws Exception { + new ServerNameRejectedTLSSessionResumption().runTest(); + } + + private void runTest() throws Exception { + final SSLContext clientSSLContext = createClientSSLContext(); + final SSLContext serverSSLContext = createServerSSLContext(); + // create client and server SSLEngine(s) + final SSLEngine clientEngine = createClientSSLEngine(clientSSLContext); + // use a SNIMatcher on the server's SSLEngine which accepts the + // SNI name presented by the client SSLEngine + final SSLEngine serverEngine = createServerSSLEngine(serverSSLContext, + new TestSNIMatcher(CLIENT_REQUESTED_SNI)); + // establish communication, which involves TLS handshake, between the + // client and server engines. this communication expected to be + // successful. + communicate(clientEngine, serverEngine); + // now that the communication has been successful, we expect the client + // SSLContext's (internal) cache to have created and cached a + // SSLSession against the peer host:port + + // now create the SSLEngine(s) again with the same SSLContext + // instances as before, so that the SSLContext instance attempts + // to reuse the cached SSLSession against the peer host:port + final SSLEngine secondClientEngine = + createClientSSLEngine(clientSSLContext); + // the newly created SSLEngine for the server will not use any + // SNIMatcher so as to reject the session resumption (of the + // cached SSLSession) + final SSLEngine secondServerEngine = + createServerSSLEngine(serverSSLContext, null); + // attempt communication, which again involves TLS handshake + // since these are new engine instances. The session resumption + // should be rejected and a fresh session should get created and + // communication should succeed without any errors + communicate(secondClientEngine, secondServerEngine); + } + + private static void communicate(final SSLEngine clientEngine, + final SSLEngine serverEngine) + throws Exception { + + final ByteBuffer msgFromClient = + ByteBuffer.wrap("Hi Server, I'm Client".getBytes()); + final ByteBuffer msgFromServer = + ByteBuffer.wrap("Hello Client, I'm Server".getBytes()); + final ByteBuffer clientBuffer = ByteBuffer.allocate(1 << 15); + final ByteBuffer serverBuffer = ByteBuffer.allocate(1 << 15); + /* + * For data transport, this test uses local ByteBuffers + */ + final ByteBuffer clientToServerTransport = + ByteBuffer.allocateDirect(1 << 16); + final ByteBuffer serverToClientTransport = + ByteBuffer.allocateDirect(1 << 16); + boolean isClientToServer = true; + while (true) { + if (isClientToServer) { + // send client's message over the transport, will initiate a + // TLS handshake if necessary + SSLEngineResult result = clientEngine.wrap(msgFromClient, + clientToServerTransport); + // run any delegated tasks + final HandshakeStatus hsStatus = checkAndRunTasks(clientEngine, + result.getHandshakeStatus()); + clientToServerTransport.flip(); // will now contain the + // network data from + // client to server + + // read from the client generated network data into + // server's buffer + result = serverEngine.unwrap(clientToServerTransport, + serverBuffer); + checkAndRunTasks(serverEngine, result.getHandshakeStatus()); + clientToServerTransport.compact(); + + if (hsStatus == HandshakeStatus.NEED_UNWRAP) { + isClientToServer = false; + } else if (hsStatus == HandshakeStatus.FINISHED) { + break; + } else if (hsStatus != HandshakeStatus.NEED_WRAP) { + throw new Exception("Unexpected handshake result " + + result); + } + } else { + // send server's message over the transport + SSLEngineResult result = serverEngine.wrap(msgFromServer, + serverToClientTransport); + // run any delegated tasks on the server side + final HandshakeStatus hsStatus = checkAndRunTasks(serverEngine, + result.getHandshakeStatus()); + serverToClientTransport.flip(); // will now contain the + // network data from + // server to client + + // read from the server generated network data into + // client's buffer + result = clientEngine.unwrap(serverToClientTransport, + clientBuffer); + // run any delegated tasks on the client side + checkAndRunTasks(clientEngine, result.getHandshakeStatus()); + serverToClientTransport.compact(); + + if (hsStatus == HandshakeStatus.NEED_UNWRAP) { + isClientToServer = true; + } else if (hsStatus == HandshakeStatus.FINISHED) { + break; + } else if (hsStatus != HandshakeStatus.NEED_WRAP) { + throw new Exception("Unexpected handshake result " + + result); + } + } + } + serverEngine.wrap(msgFromServer, serverToClientTransport); + serverToClientTransport.flip(); + clientEngine.unwrap(serverToClientTransport, clientBuffer); + serverToClientTransport.compact(); + } + + private static SSLEngine createServerSSLEngine( + final SSLContext sslContext, final SNIMatcher sniMatcher) { + final SSLEngine serverEngine = sslContext.createSSLEngine(); + serverEngine.setUseClientMode(false); + if (sniMatcher != null) { + final SSLParameters sslParameters = + serverEngine.getSSLParameters(); // returns a copy + sslParameters.setSNIMatchers(List.of(sniMatcher)); + // use the updated params + serverEngine.setSSLParameters(sslParameters); + } + return serverEngine; + } + + private static SSLEngine createClientSSLEngine( + final SSLContext sslContext) { + final SSLEngine clientEngine = sslContext.createSSLEngine(PEER_HOST, + PEER_PORT); + clientEngine.setUseClientMode(true); + final SSLParameters params = + clientEngine.getSSLParameters(); // returns a copy + // setup SNI name that will be used by the client during TLS handshake + params.setServerNames(List.of(new SNIHostName(CLIENT_REQUESTED_SNI))); + clientEngine.setSSLParameters(params); // use the updated params + return clientEngine; + } + + private static HandshakeStatus checkAndRunTasks( + final SSLEngine engine, final HandshakeStatus handshakeStatus) { + if (handshakeStatus != HandshakeStatus.NEED_TASK) { + return handshakeStatus; + } + Runnable runnable; + while ((runnable = engine.getDelegatedTask()) != null) { + System.out.println("Running task " + runnable); + runnable.run(); + } + return engine.getHandshakeStatus(); + } + + private static final class TestSNIMatcher extends SNIMatcher { + + private final String recognizedSNIServerName; + + private TestSNIMatcher(final String recognizedSNIServerName) { + super(StandardConstants.SNI_HOST_NAME); + this.recognizedSNIServerName = recognizedSNIServerName; + } + + @Override + public boolean matches(final SNIServerName clientRequestedSNI) { + Objects.requireNonNull(clientRequestedSNI); + System.out.println("Attempting SNI match against client" + + " request SNI name: " + clientRequestedSNI + + " against server recognized SNI name " + + recognizedSNIServerName); + if (!SNIHostName.class.isInstance(clientRequestedSNI)) { + System.out.println("SNI match failed - client request" + + " SNI isn't a SNIHostName"); + // we only support SNIHostName type + return false; + } + final String requestedName = + ((SNIHostName) clientRequestedSNI).getAsciiName(); + final boolean matches = + recognizedSNIServerName.equals(requestedName); + System.out.println("SNI match " + (matches ? "passed" : "failed")); + return matches; + } + } +} diff --git a/test/jdk/javax/print/DialogMargins.java b/test/jdk/javax/print/DialogMargins.java index cb5b488369c..ca45a1690a6 100644 --- a/test/jdk/javax/print/DialogMargins.java +++ b/test/jdk/javax/print/DialogMargins.java @@ -24,12 +24,12 @@ /** * @test * @bug 4485755 6361370 6448717 5080051 6939417 8016343 + * @key printer * @summary dialog doesn't have way to specify margins * for 6361370, verify exception for offline printer in Windows * for 6448717, faster display of print dialog * for 6500903, verify status of printer if accepting jobs or not * for 8016343, verify printing to non-default printer - * @author prr * @run main/manual DialogMargins */ diff --git a/test/jdk/javax/print/LookupServices.java b/test/jdk/javax/print/LookupServices.java index 7f6b9f1f604..a5685dbc57c 100644 --- a/test/jdk/javax/print/LookupServices.java +++ b/test/jdk/javax/print/LookupServices.java @@ -24,6 +24,7 @@ /* * @test * @bug 4510477 6520186 + * @key printer * @summary No crash with HP OfficeJet 600 installed. * @run main LookupServices */ diff --git a/test/jdk/javax/print/PrintServiceLookup/GetPrintServices.java b/test/jdk/javax/print/PrintServiceLookup/GetPrintServices.java index 544428566cb..092f7f17da5 100644 --- a/test/jdk/javax/print/PrintServiceLookup/GetPrintServices.java +++ b/test/jdk/javax/print/PrintServiceLookup/GetPrintServices.java @@ -29,6 +29,7 @@ /* * @test + * @key printer * @bug 8013810 8025439 * @summary Test that print service returned without filter are of the same class * as with name filter diff --git a/test/jdk/javax/print/PrintSubInputStream/Example.java b/test/jdk/javax/print/PrintSubInputStream/Example.java index 27acae8af6e..b2aa913dccb 100644 --- a/test/jdk/javax/print/PrintSubInputStream/Example.java +++ b/test/jdk/javax/print/PrintSubInputStream/Example.java @@ -23,9 +23,9 @@ /** * @test + * key printer * @bug 4700712 4707777 * @summary Should submit only 1 job in Windows and print only 1 page. - * @author jgodinez * @run main/manual Example */ import java.awt.*; diff --git a/test/jdk/javax/print/ServiceUIPropBtnTest.java b/test/jdk/javax/print/ServiceUIPropBtnTest.java index ccb57ba4037..189b9b3ac25 100644 --- a/test/jdk/javax/print/ServiceUIPropBtnTest.java +++ b/test/jdk/javax/print/ServiceUIPropBtnTest.java @@ -23,6 +23,7 @@ /* @test @bug 8246742 + @key printer @summary Verifies ServiceUI.printDialog does not support properties dialog @run main/manual ServiceUIPropBtnTest */ diff --git a/test/jdk/javax/print/TextFlavorTest.java b/test/jdk/javax/print/TextFlavorTest.java index f703e8aacc5..18b5e08f6b4 100644 --- a/test/jdk/javax/print/TextFlavorTest.java +++ b/test/jdk/javax/print/TextFlavorTest.java @@ -24,6 +24,7 @@ /* @test @bug 6334074 8022536 + @key printer @summary test supported text flavors reported properly @run main TextFlavorTest */ diff --git a/test/jdk/javax/print/attribute/Chroma.java b/test/jdk/javax/print/attribute/Chroma.java index 5968f951409..60ce9f6719a 100644 --- a/test/jdk/javax/print/attribute/Chroma.java +++ b/test/jdk/javax/print/attribute/Chroma.java @@ -21,7 +21,7 @@ * questions. */ /* - * @test 1.3 01/05/11 + * @test * @bug 4456750 * @summary Test for supported chromaticity values with null DocFlavor. * No exception should be thrown. diff --git a/test/jdk/javax/print/attribute/CollateAttr.java b/test/jdk/javax/print/attribute/CollateAttr.java index 5ea8a78be37..0c6cef60bce 100644 --- a/test/jdk/javax/print/attribute/CollateAttr.java +++ b/test/jdk/javax/print/attribute/CollateAttr.java @@ -24,6 +24,7 @@ /** * @test * @bug 6574117 + * @key printer * @summary Verify no NPE testing service support of SheetCollate * @run main CollateAttr */ diff --git a/test/jdk/javax/print/attribute/PSCopiesFlavorTest.java b/test/jdk/javax/print/attribute/PSCopiesFlavorTest.java index 25b5d955fa5..3f78fa38537 100644 --- a/test/jdk/javax/print/attribute/PSCopiesFlavorTest.java +++ b/test/jdk/javax/print/attribute/PSCopiesFlavorTest.java @@ -24,6 +24,7 @@ /** * @test * @bug 6527316 6732647 + * @key printer * @summary Copies isn't supported for PS flavors. * @run main PSCopiesFlavorTest */ diff --git a/test/jdk/javax/print/attribute/PrintResAttr.java b/test/jdk/javax/print/attribute/PrintResAttr.java index c5467b32532..dee94ae1b78 100644 --- a/test/jdk/javax/print/attribute/PrintResAttr.java +++ b/test/jdk/javax/print/attribute/PrintResAttr.java @@ -23,6 +23,7 @@ /** * @test + * @key printer * @bug 8048328 * @summary CUPS Printing does not report supported printer resolutions. * @run main PrintResAttr diff --git a/test/jdk/javax/print/attribute/ServiceDialogTest.java b/test/jdk/javax/print/attribute/ServiceDialogTest.java index bce24e749cf..626325ab1a4 100644 --- a/test/jdk/javax/print/attribute/ServiceDialogTest.java +++ b/test/jdk/javax/print/attribute/ServiceDialogTest.java @@ -25,6 +25,7 @@ /** * @test * @bug 4910388 4871089 4998624 + * @key printer * @summary Confirm that * 1. After choosing Reverse Landscape in the system default print * Print Service (2nd in the list), it diff --git a/test/jdk/javax/print/attribute/ServiceDialogValidateTest.java b/test/jdk/javax/print/attribute/ServiceDialogValidateTest.java index 929f76869cf..3598d4ae7bd 100644 --- a/test/jdk/javax/print/attribute/ServiceDialogValidateTest.java +++ b/test/jdk/javax/print/attribute/ServiceDialogValidateTest.java @@ -23,6 +23,7 @@ /* * @test * @bug 5049012 8163922 + * @key printer * @summary Verify if PrintToFile option is disabled for flavors that do not * support Destination * @requires (os.family == "linux") diff --git a/test/jdk/javax/print/attribute/ServiceDlgPageRangeTest.java b/test/jdk/javax/print/attribute/ServiceDlgPageRangeTest.java index bdf3368f5b0..f2982a13669 100644 --- a/test/jdk/javax/print/attribute/ServiceDlgPageRangeTest.java +++ b/test/jdk/javax/print/attribute/ServiceDlgPageRangeTest.java @@ -23,6 +23,7 @@ /* * @test * @bug 5080098 8164205 + * @key printer * @summary Verify if PageRanges option is disabled for Non service-formatted * flavors. * @run main/manual ServiceDlgPageRangeTest diff --git a/test/jdk/javax/print/attribute/ServiceDlgSheetCollateTest.java b/test/jdk/javax/print/attribute/ServiceDlgSheetCollateTest.java index 4f80acc29aa..dd569639f25 100644 --- a/test/jdk/javax/print/attribute/ServiceDlgSheetCollateTest.java +++ b/test/jdk/javax/print/attribute/ServiceDlgSheetCollateTest.java @@ -23,6 +23,7 @@ /* * @test * @bug 5080830 + * @key printer * @summary Verify if SheetCollate option is disabled for flavors that do not * support SheetCollate * @run main/manual ServiceDlgSheetCollateTest diff --git a/test/jdk/javax/print/attribute/Services_getDocFl.java b/test/jdk/javax/print/attribute/Services_getDocFl.java index ca926b39928..63986e46a93 100644 --- a/test/jdk/javax/print/attribute/Services_getDocFl.java +++ b/test/jdk/javax/print/attribute/Services_getDocFl.java @@ -28,6 +28,7 @@ /* * @test + * @key printer * @bug 4901243 8040139 8167291 * @summary JPG, GIF, and PNG DocFlavors (URL) should be supported if Postscript is supported. * @run main Services_getDocFl diff --git a/test/jdk/javax/print/attribute/SidesAttributeTest.java b/test/jdk/javax/print/attribute/SidesAttributeTest.java index 60454f30407..09890c7211b 100644 --- a/test/jdk/javax/print/attribute/SidesAttributeTest.java +++ b/test/jdk/javax/print/attribute/SidesAttributeTest.java @@ -25,6 +25,7 @@ /* * @test * @bug JDK-8311033 + * @key printer * @summary [macos] PrinterJob does not take into account Sides attribute * @run main/manual SidesAttributeTest */ diff --git a/test/jdk/javax/print/attribute/TestUnsupportedResolution.java b/test/jdk/javax/print/attribute/TestUnsupportedResolution.java index 0ecf842af2a..78e7e93c5f5 100644 --- a/test/jdk/javax/print/attribute/TestUnsupportedResolution.java +++ b/test/jdk/javax/print/attribute/TestUnsupportedResolution.java @@ -25,6 +25,7 @@ /** * @test * @bug 8033277 + * @key printer * @summary Confirm that scaling of printout is correct. Manual comparison with printout using a supported resolution is needed. * @run main/manual TestUnsupportedResolution */ diff --git a/test/jdk/javax/print/attribute/autosense/PrintAutoSenseData.java b/test/jdk/javax/print/attribute/autosense/PrintAutoSenseData.java index f5ddc0d15e2..008e0917342 100644 --- a/test/jdk/javax/print/attribute/autosense/PrintAutoSenseData.java +++ b/test/jdk/javax/print/attribute/autosense/PrintAutoSenseData.java @@ -24,6 +24,7 @@ /* * @test * @bug 4468109 8021583 + * @key printer * @summary Test for printing AUTOSENSE DocFlavor. No exception should be thrown. * @run main PrintAutoSenseData */ diff --git a/test/jdk/javax/swing/JButton/PressedButtonRightClickTest.java b/test/jdk/javax/swing/JButton/PressedButtonRightClickTest.java index 078c9718e2e..8f3da452c21 100644 --- a/test/jdk/javax/swing/JButton/PressedButtonRightClickTest.java +++ b/test/jdk/javax/swing/JButton/PressedButtonRightClickTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,12 @@ import java.awt.AWTException; import java.awt.BorderLayout; +import java.awt.EventQueue; import java.awt.Point; import java.awt.Robot; import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.SwingUtilities; @@ -46,13 +49,7 @@ public class PressedButtonRightClickTest { public static void main(String[] args) throws Throwable { - SwingUtilities.invokeAndWait(new Runnable() { - - @Override - public void run() { - constructTestUI(); - } - }); + SwingUtilities.invokeAndWait(PressedButtonRightClickTest::constructTestUI); try { testRobot = new Robot(); @@ -61,11 +58,14 @@ public void run() { } testRobot.waitForIdle(); + testRobot.delay(500); // Method performing auto test operation - test(); - - disposeTestUI(); + try { + test(); + } finally { + EventQueue.invokeAndWait(PressedButtonRightClickTest::disposeTestUI); + } } private static void test() { @@ -74,22 +74,27 @@ private static void test() { testRobot.mouseMove((loc.x + 100), (loc.y + 100)); // Press the left mouse button + System.out.println("press BUTTON1_DOWN_MASK"); testRobot.mousePress(InputEvent.BUTTON1_DOWN_MASK); myButton.setText("Left button pressed"); - testRobot.delay(1000); + testRobot.delay(500); // Press the right mouse button + System.out.println("press BUTTON3_DOWN_MASK"); testRobot.mousePress(InputEvent.BUTTON3_DOWN_MASK); myButton.setText("Left button pressed + Right button pressed"); - testRobot.delay(1000); + testRobot.delay(500); // Release the right mouse button + System.out.println("release BUTTON3_DOWN_MASK"); testRobot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); myButton.setText("Right button released"); - testRobot.delay(1000); + testRobot.waitForIdle(); + testRobot.delay(500); // Test whether the button is still pressed boolean pressed = myButton.getModel().isPressed(); + System.out.println("release BUTTON1_DOWN_MASK"); testRobot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); if (!pressed) { disposeTestUI(); @@ -106,6 +111,32 @@ public static void constructTestUI() { myFrame = new JFrame(); myFrame.setLayout(new BorderLayout()); myButton = new JButton("Whatever"); + myButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + System.out.println(e); + } + + @Override + public void mousePressed(MouseEvent e) { + System.out.println(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + System.out.println(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + System.out.println(e); + } + + @Override + public void mouseExited(MouseEvent e) { + System.out.println(e); + } + }); myFrame.add(myButton, BorderLayout.CENTER); myFrame.setSize(400, 300); myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/test/jdk/javax/swing/JButton/bug4234034.java b/test/jdk/javax/swing/JButton/bug4234034.java new file mode 100644 index 00000000000..e1e65345f73 --- /dev/null +++ b/test/jdk/javax/swing/JButton/bug4234034.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 4234034 + * @summary Tests NullPointerException when ToolTip invoked via keyboard + * @key headful + * @run main bug4234034 + */ + +import java.awt.Robot; +import java.awt.event.KeyEvent; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +public class bug4234034 { + static JFrame frame; + static JButton button; + + public static void main(String args[]) throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(100); + try { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("bug4323121"); + button = new JButton("Press tab, then Ctrl+F1"); + button.setToolTipText("Tooltip for button"); + frame.getContentPane().add(button); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.keyPress(KeyEvent.VK_F1); + robot.keyRelease(KeyEvent.VK_F1); + robot.keyRelease(KeyEvent.VK_CONTROL); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/JButton/bug4323121.java b/test/jdk/javax/swing/JButton/bug4323121.java new file mode 100644 index 00000000000..0b352ce57eb --- /dev/null +++ b/test/jdk/javax/swing/JButton/bug4323121.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 4323121 + * @summary Tests whether any button that extends JButton always + returns true for isArmed() + * @key headful + * @run main bug4323121 + */ + +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +public class bug4323121 { + + static JFrame frame; + static testButton button; + static volatile Point pt; + static volatile int buttonW; + static volatile int buttonH; + static volatile boolean failed = false; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(100); + try { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("bug4323121"); + button = new testButton("gotcha"); + frame.getContentPane().add(button); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + pt = button.getLocationOnScreen(); + buttonW = button.getSize().width; + buttonH = button.getSize().height; + }); + robot.mouseMove(pt.x + buttonW / 2, pt.y + buttonH / 2); + robot.waitForIdle(); + if (failed) { + throw new RuntimeException("Any created button returns " + + "true for isArmed()"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + static class testButton extends JButton implements MouseMotionListener, MouseListener { + public testButton(String label) { + super(label); + addMouseMotionListener(this); + addMouseListener(this); + } + + protected void paintComponent(Graphics g) { + super.paintComponent(g); + } + + protected void paintBorder(Graphics g) { + } + + public void mousePressed(MouseEvent e) { + } + + public void mouseDragged(MouseEvent e) { + } + + public void mouseMoved(MouseEvent e) { + } + + public void mouseReleased(MouseEvent e) { + } + + public void mouseEntered(MouseEvent e) { + if (getModel().isArmed()) { + failed = true; + } + } + + public void mouseExited(MouseEvent e) { + } + + public void mouseClicked(MouseEvent e) { + } + } +} diff --git a/test/jdk/javax/swing/JButton/bug4490179.java b/test/jdk/javax/swing/JButton/bug4490179.java new file mode 100644 index 00000000000..079c7a026f8 --- /dev/null +++ b/test/jdk/javax/swing/JButton/bug4490179.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4490179 + * @summary Tests that JButton only responds to left mouse clicks. + * @key headful + * @run main bug4490179 + */ + +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +public class bug4490179 { + static JFrame frame; + static JButton button; + static volatile Point pt; + static volatile int buttonW; + static volatile int buttonH; + static volatile boolean passed = true; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(100); + robot.setAutoWaitForIdle(true); + try { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("bug4490179"); + button = new JButton("Button"); + frame.getContentPane().add(button); + button.addActionListener(e -> { + if ((e.getModifiers() & InputEvent.BUTTON1_MASK) + != InputEvent.BUTTON1_MASK) { + System.out.println("Status: Failed"); + passed = false; + } + }); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + pt = button.getLocationOnScreen(); + buttonW = button.getSize().width; + buttonH = button.getSize().height; + }); + + robot.mouseMove(pt.x + buttonW / 2, pt.y + buttonH / 2); + robot.waitForIdle(); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(500); + + if (!passed) { + throw new RuntimeException("Test Failed"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/JComboBox/DisabledComboBoxFontTestAuto.java b/test/jdk/javax/swing/JComboBox/DisabledComboBoxFontTestAuto.java index 49b1dbc016a..50d3708fa5a 100644 --- a/test/jdk/javax/swing/JComboBox/DisabledComboBoxFontTestAuto.java +++ b/test/jdk/javax/swing/JComboBox/DisabledComboBoxFontTestAuto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,13 +21,6 @@ * questions. */ -/* - * @test - * @bug 7093691 - * @summary Tests if JComboBox has correct font color when disabled/enabled - * @run main/othervm -Dsun.java2d.uiScale=1 DisabledComboBoxFontTestAuto - */ - import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; @@ -44,20 +37,29 @@ import static java.awt.image.BufferedImage.TYPE_INT_ARGB; +/* + * @test + * @bug 7093691 8310072 + * @summary Tests if JComboBox has correct font color when disabled/enabled + * @key headful + * @run main/othervm -Dsun.java2d.uiScale=1 DisabledComboBoxFontTestAuto + */ + public class DisabledComboBoxFontTestAuto { private static JComboBox combo, combo2; private static BufferedImage enabledImage, disabledImage, enabledImage2, disabledImage2; - private static Path testDir; private static String lafName; private static StringBuffer failingLafs; private static int COMBO_HEIGHT, COMBO_WIDTH, COMBO2_HEIGHT, COMBO2_WIDTH; private static void createCombo() { combo = new JComboBox(); - combo.addItem("Simple JComboBox"); + combo.addItem("\u2588".repeat(5)); + combo.setFont(combo.getFont().deriveFont(50.0f)); combo.setRenderer(new DefaultListCellRenderer()); combo2 = new JComboBox(); - combo2.addItem("Simple JComboBox"); + combo2.addItem("\u2588".repeat(5)); + combo2.setFont(combo2.getFont().deriveFont(50.0f)); COMBO_WIDTH = (int) combo.getPreferredSize().getWidth(); COMBO_HEIGHT = (int) combo.getPreferredSize().getHeight(); COMBO2_WIDTH = (int) combo2.getPreferredSize().getWidth(); @@ -90,53 +92,38 @@ private static void paintCombo() { } private static void testMethod() throws IOException { - ImageIO.write(enabledImage, "png", new File(testDir - + "/" + lafName + "Enabled.png")); - ImageIO.write(disabledImage, "png", new File(testDir - + "/" + lafName + "Disabled.png")); - ImageIO.write(enabledImage2, "png", new File(testDir - + "/" + lafName + "EnabledDLCR.png")); - ImageIO.write(disabledImage2, "png", new File(testDir - + "/" + lafName + "DisabledDLCR.png")); - - boolean isIdentical = true; Color eColor1, eColor2, dColor1, dColor2; + Path testDir = Path.of(System.getProperty("test.classes", ".")); // Use center line to compare RGB values - int y = 10; + int y = enabledImage.getHeight() / 2; for (int x = (enabledImage.getWidth() / 2) - 20; x < (enabledImage.getWidth() / 2) + 20; x++) { - // Nimbus has a pixel offset in coordinates since Nimbus is 2px - // smaller in width than other L&F's - if (lafName.equals("Nimbus")) { - eColor1 = new Color(enabledImage.getRGB(x + 1, y)); - eColor2 = new Color(enabledImage2.getRGB(x, y)); - dColor1 = new Color(disabledImage.getRGB(x + 1, y)); - dColor2 = new Color(disabledImage2.getRGB(x, y)); - } else { - eColor1 = new Color(enabledImage.getRGB(x, y)); - eColor2 = new Color(enabledImage2.getRGB(x, y)); - dColor1 = new Color(disabledImage.getRGB(x, y)); - dColor2 = new Color(disabledImage2.getRGB(x, y)); - } + eColor1 = new Color(enabledImage.getRGB(x, y)); + eColor2 = new Color(enabledImage2.getRGB(x, y)); + dColor1 = new Color(disabledImage.getRGB(x, y)); + dColor2 = new Color(disabledImage2.getRGB(x, y)); + if ((!isColorMatching(eColor1, eColor2)) || (!isColorMatching(dColor1, dColor2))) { - isIdentical = false; - break; + failingLafs.append(lafName + ", "); + ImageIO.write(enabledImage, "png", new File(testDir + + "/" + lafName + "Enabled.png")); + ImageIO.write(disabledImage, "png", new File(testDir + + "/" + lafName + "Disabled.png")); + ImageIO.write(enabledImage2, "png", new File(testDir + + "/" + lafName + "EnabledDLCR.png")); + ImageIO.write(disabledImage2, "png", new File(testDir + + "/" + lafName + "DisabledDLCR.png")); + return; } } - - if (isIdentical) { - System.out.println("PASSED"); - } else { - failingLafs.append(lafName + ", "); - } + System.out.println("Test Passed: " + lafName); } private static boolean isColorMatching(Color c1, Color c2) { if ((c1.getRed() != c2.getRed()) - || (c1.getBlue() != c2.getBlue()) - || (c1.getGreen() != c2.getGreen())) { - + || (c1.getBlue() != c2.getBlue()) + || (c1.getGreen() != c2.getGreen())) { System.out.println(lafName + " Enabled RGB failure: " + c1.getRed() + ", " + c1.getBlue() + ", " @@ -163,7 +150,6 @@ private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { public static void main(String[] args) throws Exception { lafName = "null"; failingLafs = new StringBuffer(); - testDir = Path.of(System.getProperty("test.classes", ".")); for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { // Change Motif LAF name to avoid using slash in saved image file path lafName = laf.getName().equals("CDE/Motif") ? "Motif" : laf.getName(); diff --git a/test/jdk/javax/swing/JEditorPane/EditorPaneCharset.java b/test/jdk/javax/swing/JEditorPane/EditorPaneCharset.java new file mode 100644 index 00000000000..cf2edf0e1a1 --- /dev/null +++ b/test/jdk/javax/swing/JEditorPane/EditorPaneCharset.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.Charset; + +import javax.swing.JEditorPane; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; + +/* + * @test + * @bug 8328953 + * @summary Verifies JEditorPane.read doesn't throw ChangedCharSetException + but handles it and reads HTML in the specified encoding + * @run main EditorPaneCharset + */ + +public final class EditorPaneCharset { + private static final String CYRILLIC_TEXT = + "\u041F\u0440\u0438\u0432\u0435\u0442, \u043C\u0438\u0440!"; + private static final String HTML_CYRILLIC = + "\n" + + "\n" + + " \n" + + "\n" + + "

" + CYRILLIC_TEXT + "

\n" + + "\n"; + + public static void main(String[] args) throws IOException, BadLocationException { + JEditorPane editorPane = new JEditorPane(); + editorPane.setContentType("text/html"); + Document document = editorPane.getDocument(); + + // Shouldn't throw ChangedCharSetException + editorPane.read( + new ByteArrayInputStream( + HTML_CYRILLIC.getBytes( + Charset.forName("windows-1251"))), + document); + + Element root = document.getDefaultRootElement(); + Element body = root.getElement(1); + Element p = body.getElement(0); + String pText = document.getText(p.getStartOffset(), + p.getEndOffset() - p.getStartOffset() - 1); + if (!CYRILLIC_TEXT.equals(pText)) { + throw new RuntimeException("Text doesn't match"); + } + } +} diff --git a/test/jdk/javax/swing/JFileChooser/FileSystemView/Win32FolderSort.java b/test/jdk/javax/swing/JFileChooser/FileSystemView/Win32FolderSort.java new file mode 100644 index 00000000000..7ed5e0f1705 --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/FileSystemView/Win32FolderSort.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/* + * @test + * @bug 8305072 + * @requires (os.family == "windows") + * @modules java.desktop/sun.awt.shell + * @summary Verifies consistency of Win32ShellFolder2.compareTo + * @run main/othervm --add-opens java.desktop/sun.awt.shell=ALL-UNNAMED Win32FolderSort + */ +public class Win32FolderSort { + public static void main(String[] args) throws Exception { + Class folderManager = Class.forName("sun.awt.shell.Win32ShellFolderManager2"); + Class folder = Class.forName("sun.awt.shell.Win32ShellFolder2"); + + Method getDesktop = folderManager.getDeclaredMethod("getDesktop"); + getDesktop.setAccessible(true); + Method getPersonal = folderManager.getDeclaredMethod("getPersonal"); + getPersonal.setAccessible(true); + + Method createShellFolder = folderManager.getDeclaredMethod("createShellFolder", folder, File.class); + createShellFolder.setAccessible(true); + + Method isFileSystem = folder.getMethod("isFileSystem"); + isFileSystem.setAccessible(true); + Method isSpecial = folder.getMethod("isSpecial"); + isSpecial.setAccessible(true); + Method getChildByPath = folder.getDeclaredMethod("getChildByPath", String.class); + getChildByPath.setAccessible(true); + + File desktop = (File) getDesktop.invoke(null); + File personal = (File) getPersonal.invoke(null); + if (!((Boolean) isSpecial.invoke(personal))) { + throw new RuntimeException("personal is not special"); + } + File fakePersonal = (File) getChildByPath.invoke(desktop, personal.getPath()); + if (fakePersonal == null) { + fakePersonal = (File) createShellFolder.invoke(null, desktop, + new File(personal.getPath())); + } + if ((Boolean) isSpecial.invoke(fakePersonal)) { + throw new RuntimeException("fakePersonal is special"); + } + File homeDir = (File) createShellFolder.invoke(null, desktop, + new File(System.getProperty("user.home"))); + + File[] files = {fakePersonal, personal, homeDir}; + for (File f : files) { + if (!((Boolean) isFileSystem.invoke(f))) { + throw new RuntimeException(f + " is not on file system"); + } + } + + List errors = new ArrayList<>(2); + for (File f1 : files) { + for (File f2 : files) { + for (File f3 : files) { + String result = verifyCompareTo(f1, f2, f3); + if (result != null) { + String error = result + "\nwhere" + + "\n a = " + formatFile(f1, isSpecial) + + "\n b = " + formatFile(f2, isSpecial) + + "\n c = " + formatFile(f3, isSpecial); + errors.add(error); + } + } + } + } + + + System.out.println("Unsorted:"); + for (File f : files) { + System.out.println(formatFile(f, isSpecial)); + } + System.out.println(); + + Arrays.sort(files); + System.out.println("Sorted:"); + for (File f : files) { + System.out.println(formatFile(f, isSpecial)); + } + + + if (!errors.isEmpty()) { + System.err.println("Implementation of Win32ShellFolder2.compareTo is inconsistent:"); + errors.forEach(System.err::println); + throw new RuntimeException("Inconsistencies found: " + errors.size() + + " - " + errors.get(0)); + } + } + + /** + * Verifies consistency of {@code Comparable} implementation. + * + * @param a the first object + * @param b the second object + * @param c the third object + * @return error message if inconsistency is found, + * or {@code null } otherwise + */ + private static String verifyCompareTo(File a, File b, File c) { + // a < b & b < c => a < c + if (a.compareTo(b) < 0 && b.compareTo(c) < 0) { + if (a.compareTo(c) >= 0) { + return "a < b & b < c but a >= c"; + } + } + + // a > b & b > c => a > c + if (a.compareTo(b) > 0 && b.compareTo(c) > 0) { + if (a.compareTo(c) <= 0) { + return "a > b & b > c but a <= c"; + } + } + + // a = b & b = c => a = c + if (a.compareTo(b) == 0 && b.compareTo(c) == 0) { + if (a.compareTo(c) != 0) { + return "a = b & b = c but a != c"; + } + } + + return null; + } + + private static String formatFile(File f, Method isSpecial) + throws InvocationTargetException, IllegalAccessException { + return f + "(" + isSpecial.invoke(f) + ")"; + } +} diff --git a/test/jdk/javax/swing/JFileChooser/TABTestONFCExit.java b/test/jdk/javax/swing/JFileChooser/TABTestONFCExit.java new file mode 100644 index 00000000000..16fcc9d1208 --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/TABTestONFCExit.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Point; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +import javax.swing.AbstractButton; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.JToggleButton; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; +import javax.swing.UIManager; +import javax.swing.table.DefaultTableModel; + +import java.util.function.Predicate; + +/* + * @test + * @bug 6967482 + * @key headful + * @summary Test to check if TAB is working on JTable after JFileChooser is + * closed + * @run main TABTestONFCExit + */ + +public class TABTestONFCExit { + private static JTable table; + private static JFileChooser fc; + private static JFrame frame; + private static Robot robot; + private static volatile Point loc; + private static volatile Rectangle rect; + private static volatile int selectedColumnBeforeTabPress; + private static volatile int selectedColumnAfterTabPress; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoDelay(50); + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + try { + SwingUtilities.invokeAndWait(TABTestONFCExit::initialize); + robot.waitForIdle(); + robot.delay(100); + + SwingUtilities.invokeAndWait(TABTestONFCExit::clickDetails); + robot.waitForIdle(); + robot.delay(100); + + SwingUtilities.invokeAndWait(() -> { + loc = table.getLocationOnScreen(); + rect = table.getCellRect(0, 0, true); + }); + + onClick(loc, rect); + + SwingUtilities.invokeAndWait(() -> + selectedColumnBeforeTabPress = table.getSelectedColumn()); + + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + robot.waitForIdle(); + robot.delay(100); + + SwingUtilities.invokeAndWait(() -> + selectedColumnAfterTabPress = table.getSelectedColumn()); + robot.waitForIdle(); + robot.delay(100); + + if (selectedColumnAfterTabPress == selectedColumnBeforeTabPress) { + throw new RuntimeException("TAB failed to move cell!"); + } + System.out.println("Test Passed" ); + + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void onClick(Point loc, Rectangle cellRect) { + robot.mouseMove(loc.x + cellRect.x + cellRect.width / 2, + loc.y + cellRect.y + cellRect.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(100); + } + + private static void initialize() { + frame = new JFrame("Tab Test"); + fc = new JFileChooser(); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.add(getJTable(), BorderLayout.NORTH); + frame.add(fc, BorderLayout.SOUTH); + frame.pack(); + frame.setVisible(true); + } + + private static JTable getJTable() { + if (table == null) { + table = new JTable(); + table.setModel(new DefaultTableModel(5, 5)); + } + return table; + } + private static void clickDetails() { + AbstractButton details = findDetailsButton(fc); + if (details == null) { + throw new Error("Couldn't find 'Details' button in JFileChooser"); + } + details.doClick(); + } + + private static AbstractButton findDetailsButton(final Container container) { + Component result = findComponent(container, + c -> c instanceof JToggleButton button + && "Details".equals(button.getToolTipText())); + return (AbstractButton) result; + } + + private static Component findComponent(final Container container, + final Predicate predicate) { + for (Component child : container.getComponents()) { + if (predicate.test(child)) { + return child; + } + if (child instanceof Container cont && cont.getComponentCount() > 0) { + Component result = findComponent(cont, predicate); + if (result != null) { + return result; + } + } + } + return null; + } +} diff --git a/test/jdk/javax/swing/JFrame/DefaultCloseOperation.java b/test/jdk/javax/swing/JFrame/DefaultCloseOperation.java new file mode 100644 index 00000000000..098000a8bab --- /dev/null +++ b/test/jdk/javax/swing/JFrame/DefaultCloseOperation.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * 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.Frame; +import java.awt.FlowLayout; +import java.awt.Window; +import java.awt.event.ItemEvent; +import java.awt.event.WindowEvent; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +/* + * @test + * @summary test for defaultCloseOperation property for Swing JFrame and JDialog + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DefaultCloseOperation + */ + +public class DefaultCloseOperation extends JPanel { + + private static final String INSTRUCTIONS = """ + Do the following steps: + + - Click the "Open Frame" button (a TestFrame will appear) + - On the TestFrame, select "Close" from the system menu (the window should go away) + - Select "Do Nothing" from the "JFrame Default Close Operation" ComboBox + - Click the "Open Frame" button + - On the TestFrame, select "Close" from the system menu (the window should remain open) + - Select "Dispose" from the "JFrame Default Close Operation" ComboBox + - On the TestFrame, select "Close" from the system menu (the window should go away) + + + - Click the "Open Frame" button + - Click the "Open Dialog" button (a TestDialog will appear) + - On the TestDialog, select "Close" from the system menu (the window should go away) + - Select "Do Nothing" from the "JDialog Default Close Operation" ComboBox + - Click the "Open Dialog" button + - On the TestDialog, select "Close" from the system menu (the window should remain open) + - Select "Dispose" from the "JDialog Default Close Operation" ComboBox + - On the TestDialog, select "Close" from the system menu (the window should go away) + """; + + JComboBox frameCloseOp; + + CloseOpDialog testDialog; + JComboBox dialogCloseOp; + + public static void main(String[] args) throws Exception { + + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("DefaultCloseOperation Manual Test") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(20) + .columns(70) + .build(); + + SwingUtilities.invokeAndWait(() -> { + DefaultCloseOperation dco = new DefaultCloseOperation(); + dco.init(); + + JFrame frame = new JFrame("DefaultCloseOperation"); + frame.add(dco); + frame.setSize(500,200); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame + .positionTestWindow(frame, PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } + + public void init() { + setLayout(new FlowLayout()); + + CloseOpFrame testFrame = new CloseOpFrame(); + testFrame.setLocationRelativeTo(null); + PassFailJFrame.addTestWindow(testFrame); + + add(new JLabel("JFrame Default Close Operation:")); + frameCloseOp = new JComboBox<>(); + frameCloseOp.addItem("Hide"); + frameCloseOp.addItem("Do Nothing"); + frameCloseOp.addItem("Dispose"); + frameCloseOp.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + String item = (String)e.getItem(); + switch (item) { + case "Do Nothing" -> testFrame + .setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + case "Hide" -> testFrame + .setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); + case "Dispose" -> testFrame + .setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + } + } + }); + add(frameCloseOp); + + JButton b = new JButton("Open Frame..."); + b.addActionListener(e -> testFrame.setVisible(true)); + add(b); + + testDialog = new CloseOpDialog(testFrame); + testDialog.setLocationRelativeTo(null); + PassFailJFrame.addTestWindow(testDialog); + + add(new JLabel("JDialog Default Close Operation:")); + dialogCloseOp = new JComboBox<>(); + dialogCloseOp.addItem("Hide"); + dialogCloseOp.addItem("Do Nothing"); + dialogCloseOp.addItem("Dispose"); + dialogCloseOp.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + String item = (String)e.getItem(); + switch (item) { + case "Do Nothing" -> testDialog + .setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + case "Hide" -> testDialog + .setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); + case "Dispose" -> testDialog + .setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + } + } + }); + add(dialogCloseOp); + + b = new JButton("Open Dialog..."); + b.addActionListener(e -> testDialog.setVisible(true)); + add(b); + } + + public static void verifyCloseOperation(Window window, int op) { + switch (op) { + case WindowConstants.DO_NOTHING_ON_CLOSE -> { + if (!window.isVisible()) { + PassFailJFrame + .forceFail("defaultCloseOperation=DoNothing failed"); + } + } + case WindowConstants.HIDE_ON_CLOSE -> { + if (window.isVisible()) { + PassFailJFrame + .forceFail("defaultCloseOperation=Hide failed"); + } + } + case WindowConstants.DISPOSE_ON_CLOSE -> { + if (window.isVisible() || window.isDisplayable()) { + PassFailJFrame + .forceFail("defaultCloseOperation=Dispose failed"); + } + } + } + } +} + +class CloseOpFrame extends JFrame { + + public CloseOpFrame() { + super("DefaultCloseOperation Test"); + getContentPane().add("Center", new JLabel("Test Frame")); + pack(); + } + + protected void processWindowEvent(WindowEvent e) { + super.processWindowEvent(e); + + if (e.getID() == WindowEvent.WINDOW_CLOSING) { + DefaultCloseOperation + .verifyCloseOperation(this, getDefaultCloseOperation()); + } + } +} + +class CloseOpDialog extends JDialog { + + public CloseOpDialog(Frame owner) { + super(owner, "DefaultCloseOperation Test Dialog"); + getContentPane().add("Center", new JLabel("Test Dialog")); + pack(); + } + + protected void processWindowEvent(WindowEvent e) { + super.processWindowEvent(e); + + if (e.getID() == WindowEvent.WINDOW_CLOSING) { + DefaultCloseOperation + .verifyCloseOperation(this, getDefaultCloseOperation()); + } + } +} diff --git a/test/jdk/javax/swing/JFrame/bug4419914.java b/test/jdk/javax/swing/JFrame/bug4419914.java new file mode 100644 index 00000000000..4574b1ac3d6 --- /dev/null +++ b/test/jdk/javax/swing/JFrame/bug4419914.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4419914 + * @summary Tests that tab movement is correct in RTL component orientation. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4419914 +*/ + +import java.awt.BorderLayout; +import java.awt.ComponentOrientation; +import javax.swing.JButton; +import javax.swing.JFrame; +import java.util.Locale; + +public class bug4419914 { + private static final String INSTRUCTIONS = """ + 1. You will see a frame with five buttons. + 2. Confirm that each button is placed as follows: + NORTH + END CENTER START + SOUTH + 3. Press the "NORTH" button and confirm the button is focused. + 4. Press TAB repeatedly and confirm that the TAB focus moves from right to left. + (NORTH - START - CENTER - END - SOUTH - NORTH - START - CENTER - ...) + + If there's anything different from the above items, click Fail else click Pass."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Tab movement Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(48) + .testUI(bug4419914::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("bug4419914"); + frame.setFocusCycleRoot(true); + frame.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + frame.setLocale(Locale.ENGLISH); + frame.enableInputMethods(false); + + frame.getContentPane().setComponentOrientation( + ComponentOrientation.RIGHT_TO_LEFT); + frame.getContentPane().setLocale(Locale.ENGLISH); + frame.getContentPane().setLayout(new BorderLayout()); + frame.add(new JButton("SOUTH"), BorderLayout.SOUTH); + frame.add(new JButton("CENTER"), BorderLayout.CENTER); + frame.add(new JButton("END"), BorderLayout.LINE_END); + frame.add(new JButton("START"), BorderLayout.LINE_START); + frame.add(new JButton("NORTH"), BorderLayout.NORTH); + frame.setSize(300, 150); + return frame; + } +} diff --git a/test/jdk/javax/swing/JLabel/4138746/JLabelMnemonicsTest.java b/test/jdk/javax/swing/JLabel/4138746/JLabelMnemonicsTest.java index 7cbd3232b13..ddb2ed32382 100644 --- a/test/jdk/javax/swing/JLabel/4138746/JLabelMnemonicsTest.java +++ b/test/jdk/javax/swing/JLabel/4138746/JLabelMnemonicsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,6 +90,7 @@ public static void main(String[] args) throws Exception { continue; } robot.waitForIdle(); + robot.delay(500); // Verifier 1: Verifies if getDisplayedMnemonicIndex() returns the // right index set with setDisplayedMnemonicIndex method for JButton diff --git a/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java b/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java new file mode 100644 index 00000000000..80779c9ce1d --- /dev/null +++ b/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4211731 4214512 + * @summary + * This test checks if menu bars lay out correctly when their + * ComponentOrientation property is set to RIGHT_TO_LEFT. This test is + * manual. The tester is asked to compare left-to-right and + * right-to-left menu bars and judge whether they are mirror images of each + * other. + * @library /test/jdk/java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RightLeftOrientation + */ + +import java.awt.ComponentOrientation; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.ButtonGroup; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class RightLeftOrientation { + + static JFrame ltrFrame; + static JFrame rtlFrame; + + private static final String INSTRUCTIONS = """ + This test checks menu bars for correct Right-To-Left Component Orientation. + + You should see two frames, each containing a menu bar. + + One frame will be labelled "Left To Right" and will contain + a menu bar with menus starting on its left side. + The other frame will be labelled "Right To Left" and will + contain a menu bar with menus starting on its right side. + + The test will also contain radio buttons that can be used to set + the look and feel of the menu bars. + For each look and feel, you should compare the two menu + bars and make sure they are mirror images of each other. """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("RTL test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(30) + .testUI(RightLeftOrientation::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("RightLeftOrientation"); + JPanel panel = new JPanel(); + + ButtonGroup group = new ButtonGroup(); + JRadioButton rb; + ActionListener plafChanger = new PlafChanger(); + + UIManager.LookAndFeelInfo[] lafInfos = UIManager.getInstalledLookAndFeels(); + for (int i = 0; i < lafInfos.length; i++) { + rb = new JRadioButton(lafInfos[i].getName()); + rb.setActionCommand(lafInfos[i].getClassName()); + rb.addActionListener(plafChanger); + group.add(rb); + panel.add(rb); + if (i == 0) { + rb.setSelected(true); + } + } + + frame.add(panel); + + ltrFrame = new JFrame("Left To Right"); + ltrFrame.setJMenuBar(createMenuBar(ComponentOrientation.LEFT_TO_RIGHT)); + ltrFrame.setSize(400, 100); + ltrFrame.setLocation(new Point(10, 10)); + ltrFrame.setVisible(true); + + rtlFrame = new JFrame("Right To Left"); + rtlFrame.setJMenuBar(createMenuBar(ComponentOrientation.RIGHT_TO_LEFT)); + rtlFrame.setSize(400, 100); + rtlFrame.setLocation(new Point(10, 120)); + rtlFrame.setVisible(true); + frame.pack(); + return frame; + } + + static class PlafChanger implements ActionListener { + public void actionPerformed(ActionEvent e) { + String lnfName = e.getActionCommand(); + + try { + UIManager.setLookAndFeel(lnfName); + SwingUtilities.updateComponentTreeUI(ltrFrame); + SwingUtilities.updateComponentTreeUI(rtlFrame); + } + catch (Exception exc) { + System.err.println("Could not load LookAndFeel: " + lnfName); + } + + } + } + + + static JMenuBar createMenuBar(ComponentOrientation o) { + JMenuBar menuBar = new JMenuBar(); + menuBar.setComponentOrientation(o); + + JMenu menu = new JMenu("One"); + menu.setComponentOrientation(o); + menuBar.add(menu); + + menu = new JMenu("Two"); + menu.setComponentOrientation(o); + menuBar.add(menu); + + menu = new JMenu("Three"); + menu.setComponentOrientation(o); + menuBar.add(menu); + + return menuBar; + } + +} diff --git a/test/jdk/javax/swing/JRadioButton/bug4823809.java b/test/jdk/javax/swing/JRadioButton/bug4823809.java new file mode 100644 index 00000000000..810f4f42939 --- /dev/null +++ b/test/jdk/javax/swing/JRadioButton/bug4823809.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JFrame; +import javax.swing.JRadioButton; +import javax.swing.SwingUtilities; +import javax.swing.plaf.ButtonUI; +import javax.swing.plaf.metal.MetalRadioButtonUI; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Robot; + +/* + * @test + * @bug 4823809 + * @summary No Mnemonic or Focus Indicator when using HTML for a Component Text + * @key headful + * @run main bug4823809 + */ + +public class bug4823809 { + private static ButtonUI testUI; + private static volatile boolean passed = false; + private static JFrame frame; + private static Robot robot; + + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("RadioButton Test"); + testUI = new TestRadioButtonUI(); + JRadioButton radio = new TestRadioButton("This is a radiobutton test!"); + + frame.getContentPane().add(radio); + frame.pack(); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + + if (!passed) { + throw new Error("Focus isn't painted for JRadioButton with HTML text."); + } + System.out.println("Test Passed!"); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + static class TestRadioButton extends JRadioButton { + public TestRadioButton(String s) { + super(s); + } + + public void setUI(ButtonUI ui) { + super.setUI(testUI); + } + } + + static class TestRadioButtonUI extends MetalRadioButtonUI { + protected void paintFocus(Graphics g, Rectangle t, Dimension d) { + super.paintFocus(g, t, d); + passed = true; + } + } + +} diff --git a/test/jdk/javax/swing/JRootPane/DefaultButtonTest.java b/test/jdk/javax/swing/JRootPane/DefaultButtonTest.java index 560c5d82331..784cd00c244 100644 --- a/test/jdk/javax/swing/JRootPane/DefaultButtonTest.java +++ b/test/jdk/javax/swing/JRootPane/DefaultButtonTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,6 +83,7 @@ private void createUI() { public void runTest() throws Exception { Robot robot = new Robot(); + robot.setAutoWaitForIdle(true); robot.setAutoDelay(100); for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) { try { @@ -100,6 +101,8 @@ public void runTest() throws Exception { createUI(); }); robot.waitForIdle(); + robot.delay(1000); + robot.keyPress(KeyEvent.VK_ENTER); robot.keyRelease(KeyEvent.VK_ENTER); robot.waitForIdle(); diff --git a/test/jdk/javax/swing/JSpinner/8008657/bug8008657.java b/test/jdk/javax/swing/JSpinner/8008657/bug8008657.java index cbeb0c185bb..26ed0e0082c 100644 --- a/test/jdk/javax/swing/JSpinner/8008657/bug8008657.java +++ b/test/jdk/javax/swing/JSpinner/8008657/bug8008657.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,6 @@ * @test * @key headful * @bug 8008657 - * @author Alexander Scherbatiy * @summary JSpinner setComponentOrientation doesn't affect on text orientation * @run main bug8008657 */ @@ -137,6 +136,7 @@ static void createDateSpinner() { calendar.add(Calendar.YEAR, -1); Date earliestDate = calendar.getTime(); calendar.add(Calendar.YEAR, 1); + calendar.add(Calendar.DAY_OF_MONTH, 1); Date latestDate = calendar.getTime(); SpinnerModel dateModel = new SpinnerDateModel(initDate, earliestDate, diff --git a/test/jdk/javax/swing/JSplitPane/bug4147653.java b/test/jdk/javax/swing/JSplitPane/bug4147653.java new file mode 100644 index 00000000000..ed84776d46d --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/bug4147653.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JSplitPane; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +/* + * @test + * @bug 4147653 + * @summary JSplitPane.DIVIDER_LOCATION_PROPERTY is a property, + * you can use that to know when the position changes. + * @run main bug4147653 + */ + +public class bug4147653 { + private static volatile boolean flag = false; + + static class DevMoved implements PropertyChangeListener { + public void propertyChange(PropertyChangeEvent evt) { + flag = true; + } + } + + public static void main(String[] args) throws Exception { + JSplitPane sp = new JSplitPane(); + + DevMoved pl = new DevMoved(); + sp.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, pl); + sp.setDividerLocation(sp.getDividerLocation() + 10); + Thread.sleep(1000); + + if (!flag) { + throw new RuntimeException("Divider property was not changed..."); + } + System.out.println("Test Passed!"); + } +} diff --git a/test/jdk/javax/swing/JSplitPane/bug4870674.java b/test/jdk/javax/swing/JSplitPane/bug4870674.java new file mode 100644 index 00000000000..1984d747f76 --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/bug4870674.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JSplitPane; +import javax.swing.SwingUtilities; +import javax.swing.plaf.basic.BasicSplitPaneDivider; +import javax.swing.plaf.basic.BasicSplitPaneUI; +import java.awt.GridLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; + +/* + * @test + * @bug 4870674 + * @summary JSplitPane's one-touch buttons should deal with resized split panes better + * @key headful + * @run main bug4870674 + */ + +public class bug4870674 { + private static JSplitPane jsp0, jsp1; + private static JButton[] leftOneTouchButton = new JButton[2]; + private static JButton[] rightOneTouchButton = new JButton[2]; + private static JFrame frame; + private static Robot robot; + private static volatile boolean passed = true; + private static volatile Point rightBtnPos0; + private static volatile Point leftBtnPos0; + private static volatile Point rightBtnPos1; + private static volatile Point leftBtnPos1; + + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("Test"); + frame.getContentPane().setLayout(new GridLayout(2, 1)); + + jsp0 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + new JButton("Left"), + new JButton("Right")); + frame.getContentPane().add(jsp0); + + jsp0.setUI(new TestSplitPaneUI(0)); + jsp0.setOneTouchExpandable(true); + + jsp1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + new JButton("Left"), + new JButton("Right")); + frame.getContentPane().add(jsp1); + + jsp1.setUI(new TestSplitPaneUI(1)); + jsp1.setOneTouchExpandable(true); + + frame.setSize(300, 100); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + rightBtnPos0 = rightOneTouchButton[0].getLocationOnScreen(); + rightBtnPos0.x += rightOneTouchButton[0].getWidth() / 2; + rightBtnPos0.y += rightOneTouchButton[0].getHeight() / 2; + + leftBtnPos1 = leftOneTouchButton[1].getLocationOnScreen(); + leftBtnPos1.x += leftOneTouchButton[0].getWidth() / 2; + leftBtnPos1.y += leftOneTouchButton[0].getHeight() / 2; + + leftBtnPos0 = leftOneTouchButton[0].getLocationOnScreen(); + leftBtnPos0.x += leftOneTouchButton[0].getWidth() / 2; + leftBtnPos0.y += leftOneTouchButton[0].getHeight() / 2; + + rightBtnPos1 = rightOneTouchButton[1].getLocationOnScreen(); + rightBtnPos1.x += rightOneTouchButton[0].getWidth() / 2; + rightBtnPos1.y += rightOneTouchButton[0].getHeight() / 2; + + jsp0.setDividerLocation(250); + }); + robot.mouseMove(rightBtnPos0.x, rightBtnPos0.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + SwingUtilities.invokeAndWait(() -> { + jsp1.setDividerLocation(250); + }); + robot.waitForIdle(); + robot.delay(100); + robot.mouseMove(leftBtnPos1.x, leftBtnPos1.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + SwingUtilities.invokeAndWait(() -> { + frame.setSize(200, 100); + }); + robot.waitForIdle(); + robot.delay(100); + robot.mouseMove(leftBtnPos0.x, leftBtnPos0.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(100); + robot.mouseMove(rightBtnPos1.x, rightBtnPos1.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(100); + + SwingUtilities.invokeAndWait(() -> { + if (jsp0.getDividerLocation() > jsp0.getMaximumDividerLocation() || + jsp1.getDividerLocation() > jsp1.getMaximumDividerLocation()) { + passed = false; + } + }); + + if (!passed) { + throw new RuntimeException("The divider location couldn't " + + "be greater then its maximum location"); + } + System.out.println("Test Passed!"); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + static class TestSplitPaneUI extends BasicSplitPaneUI { + int i; + + public TestSplitPaneUI(int i) { + super(); + this.i = i; + } + + public BasicSplitPaneDivider createDefaultDivider() { + return new TestSplitPaneDivider(this, i); + } + } + + static class TestSplitPaneDivider extends BasicSplitPaneDivider { + int i = 0; + + public TestSplitPaneDivider(BasicSplitPaneUI ui, int i) { + super(ui); + this.i = i; + } + + protected JButton createLeftOneTouchButton() { + leftOneTouchButton[i] = super.createLeftOneTouchButton(); + return leftOneTouchButton[i]; + } + + protected JButton createRightOneTouchButton() { + rightOneTouchButton[i] = super.createRightOneTouchButton(); + return rightOneTouchButton[i]; + } + } +} diff --git a/test/jdk/javax/swing/JTabbedPane/GetComponentAtTest.java b/test/jdk/javax/swing/JTabbedPane/GetComponentAtTest.java new file mode 100644 index 00000000000..ddefd541f40 --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/GetComponentAtTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 4122109 + * @summary Ensure SwingUtilities.getDeepestComponentAt() works correctly + * (in this particular case, with JTabbedPane) + * @key headful + * @run main GetComponentAtTest + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Robot; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; + +public class GetComponentAtTest { + static JFrame f; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("GetComponentAtTest"); + JTabbedPane tabbedpane = new JTabbedPane(); + f.getContentPane().add(tabbedpane, BorderLayout.CENTER); + + JPanel panel1 = new JPanel(); + panel1.setName("Panel 1"); + panel1.setLayout(new BorderLayout()); + tabbedpane.add(panel1); + JPanel subPanel = new JPanel(); + subPanel.setName("Sub-Panel"); + subPanel.setBackground(Color.green); + panel1.add(subPanel); // add sub panel to 1st tab + + JPanel panel2 = new JPanel(); + panel2.setName("Panel 2"); + tabbedpane.add(panel2); + + f.setSize(150, 150); + f.setVisible(true); + + robot.delay(1000); + + tabbedpane.setSelectedIndex(1); // display 2nd tab + tabbedpane.invalidate(); + tabbedpane.validate(); + if (SwingUtilities.getDeepestComponentAt(tabbedpane, 50, 50) != panel2) { + throw new RuntimeException("SwingUtilities.getDeepestComponentAt() " + + "returned incorrect component! (1)"); + } + + tabbedpane.setSelectedIndex(0); // display 1st tab + tabbedpane.invalidate(); + tabbedpane.validate(); + if (SwingUtilities.getDeepestComponentAt(tabbedpane, 50, 50) != subPanel) { + throw new RuntimeException("SwingUtilities.getDeepestComponentAt() " + + "returned incorrect component! (2)"); + } + }); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + + } +} diff --git a/test/jdk/javax/swing/JTabbedPane/ReplaceCompTab.java b/test/jdk/javax/swing/JTabbedPane/ReplaceCompTab.java new file mode 100644 index 00000000000..92e9ffeff13 --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/ReplaceCompTab.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 4213896 4228439 + * @summary Ensure that inserting a new tab with a component + * where that component already exists as another tab is handled + * properly. The old tab should be removed and the new tab added. + * @key headful + * @run main ReplaceCompTab + */ + +import java.awt.BorderLayout; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; + +public class ReplaceCompTab { + static JFrame f; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("ReplaceCompTab"); + JTabbedPane tabbedpane = new JTabbedPane(); + f.getContentPane().add(tabbedpane, BorderLayout.CENTER); + + JPanel comp = new JPanel(); + + // Add first tab + tabbedpane.addTab("First(temp)", comp); + + // Add second tab with same component (should just replace first one) + tabbedpane.insertTab("First", null, comp, "component added next", 0); + + // Check to ensure only a single tab exists + if (tabbedpane.getTabCount() > 1) { + throw new RuntimeException("Only one tab should exist"); + } + // Check to make sure second tab correctly replaced the first + if (!(tabbedpane.getTitleAt(0).equals("First"))) { + throw new RuntimeException("Tab not replaced correctly"); + } + // Check to make sure adding null continues to work + try { + tabbedpane.addTab("Second", null); + } catch (Exception e) { + throw new RuntimeException("Adding first null " + + "component failed:", e); + } + try { + tabbedpane.addTab("Third", null); + } catch (Exception e) { + throw new RuntimeException("Adding subsequent null " + + "component failed: ", e); + } + try { + tabbedpane.setComponentAt(1, new JLabel("Second Component")); + tabbedpane.setComponentAt(2, new JLabel("Third Component")); + } catch (Exception e) { + throw new RuntimeException("Setting null component " + + "to non-null failed: ", e); + } + }); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/JTabbedPane/bug4703690.java b/test/jdk/javax/swing/JTabbedPane/bug4703690.java new file mode 100644 index 00000000000..08be30def82 --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/bug4703690.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 4703690 + * @summary JTabbedPane should focus proper component at the tab container + * @key headful + * @run main bug4703690 + */ + +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.InputEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; + +public class bug4703690 { + static JFrame frame; + static JTabbedPane tabbedPane; + static JButton one, two; + + static final CountDownLatch focusButtonTwo = new CountDownLatch(1); + static final CountDownLatch switchToTabTwo = new CountDownLatch(1); + static final CountDownLatch focusButtonOne = new CountDownLatch(1); + static Robot robot; + + static Point p; + static Rectangle rect; + + public static void main(String[] args) throws Exception { + bug4703690 test = new bug4703690(); + try { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("bug4703690"); + + JPanel panel = new JPanel(); + one = new JButton("Button 1"); + panel.add(one); + two = new JButton("Button 2"); + panel.add(two); + + tabbedPane = new JTabbedPane(); + frame.getContentPane().add(tabbedPane); + tabbedPane.addTab("Tab one", panel); + tabbedPane.addTab("Tab two", new JPanel()); + + two.addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + focusButtonTwo.countDown(); + } + }); + + tabbedPane.addChangeListener(e -> { + if (tabbedPane.getSelectedIndex() == 1) { + switchToTabTwo.countDown(); + } + }); + + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + + test.execute(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public void execute() throws Exception { + robot = new Robot(); + robot.setAutoDelay(50); + + SwingUtilities.invokeAndWait(two::requestFocus); + + if (!focusButtonTwo.await(1, TimeUnit.SECONDS)) { + throw new RuntimeException("Button two didn't receive focus"); + } + + one.addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + focusButtonOne.countDown(); + } + }); + + // Switch to tab two + SwingUtilities.invokeAndWait(() -> { + p = tabbedPane.getLocationOnScreen(); + rect = tabbedPane.getBoundsAt(1); + }); + robot.mouseMove(p.x + rect.x + rect.width / 2, + p.y + rect.y + rect.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + if (!switchToTabTwo.await(1, TimeUnit.SECONDS)) { + throw new RuntimeException("Switching to tab two failed"); + } + + // Switch to tab one + SwingUtilities.invokeAndWait(() -> { + p = tabbedPane.getLocationOnScreen(); + rect = tabbedPane.getBoundsAt(0); + }); + robot.mouseMove(p.x + rect.x + rect.width / 2, + p.y + rect.y + rect.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + if (!focusButtonOne.await(1, TimeUnit.SECONDS)) { + throw new RuntimeException("The 'Button 1' button doesn't have focus"); + } + } +} diff --git a/test/jdk/javax/swing/JTextArea/bug4849868.java b/test/jdk/javax/swing/JTextArea/bug4849868.java new file mode 100644 index 00000000000..efd94b46336 --- /dev/null +++ b/test/jdk/javax/swing/JTextArea/bug4849868.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 4849868 + * @summary Tests if JTextArea.getSelectionEnd works correctly + * @key headful + * @run main bug4849868 + */ + +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; + +public class bug4849868 { + + private static volatile boolean passed = false; + + private static JTextArea textArea; + private static JFrame f; + private static Point p; + + private static int end; + private static int len; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(100); + robot.setAutoWaitForIdle(true); + + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("bug4849868"); + textArea = new JTextArea("1234"); + textArea.setLineWrap(true); + JScrollPane pane = new JScrollPane(textArea, + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + f.getContentPane().add(pane); + f.setSize(300, 300); + f.setLocationRelativeTo(null); + f.setVisible(true); + }); + + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> + p = textArea.getLocationOnScreen()); + + robot.mouseMove(p.x, p.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseMove(p.x + 350, p.y); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + end = textArea.getSelectionEnd(); + len = textArea.getDocument().getLength(); + }); + passed = (end <= len); + + System.out.println("end: " + end); + System.out.println("len: " + len); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + + if (!passed) { + throw new RuntimeException("Test failed."); + } + } +} diff --git a/test/jdk/javax/swing/JTextField/bug4244613.java b/test/jdk/javax/swing/JTextField/bug4244613.java new file mode 100644 index 00000000000..6a1a8bb9d23 --- /dev/null +++ b/test/jdk/javax/swing/JTextField/bug4244613.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 4244613 + * @summary Tests that JTextField has setAction(Action) constructor + * @run main bug4244613 + */ + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JTextField; + +public class bug4244613 { + /** Auxilliary class implementing Action + */ + static class NullAction extends AbstractAction { + @Override + public void actionPerformed(ActionEvent e) {} + public Object getValue(String key) { return null; } + public boolean isEnabled() { return false; } + } + + public static void main(String[] args) { + JTextField tf = new JTextField("bug4244613"); + Action action = new NullAction(); + tf.setAction(action); + } +} diff --git a/test/jdk/javax/swing/JToolBar/RightLeftOrientation.java b/test/jdk/javax/swing/JToolBar/RightLeftOrientation.java new file mode 100644 index 00000000000..8822a86f79a --- /dev/null +++ b/test/jdk/javax/swing/JToolBar/RightLeftOrientation.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4214514 + * @summary + * This test checks if tool bars lay out correctly when their + * ComponentOrientation property is set to RIGHT_TO_LEFT. This test is + * manual. The tester is asked to compare left-to-right and + * right-to-left tool bars and judge whether they are mirror images of each + * other. + * @library /test/jdk/java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RightLeftOrientation + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.ComponentOrientation; +import java.awt.Container; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JToolBar; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class RightLeftOrientation { + + static JFrame ltrFrame; + static JFrame rtlFrame; + + private static final String INSTRUCTIONS = """ + This test checks tool bars for correct Right-To-Left Component Orientation. + + You should see two frames, each containing a tool bar. + + One frame will be labelled "Left To Right" and will contain + a tool bar with buttons starting on its left side. + The other frame will be labelled "Right To Left" and will + contain a tool bar with buttons starting on its right side. + + The test will also contain radio buttons that can be used to set + the look and feel of the tool bars. + For each look and feel, you should compare the two tool bars and + make sure they are mirror images of each other. + You should also drag the tool bars to each corner of the frame + to make sure the docking behavior is consistent between the two frames."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("RTL test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(RightLeftOrientation::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("RightLeftOrientation"); + JPanel panel = new JPanel(); + + ButtonGroup group = new ButtonGroup(); + JRadioButton rb; + ActionListener plafChanger = new PlafChanger(); + + UIManager.LookAndFeelInfo[] lafInfos = UIManager.getInstalledLookAndFeels(); + for (int i = 0; i < lafInfos.length; i++) { + rb = new JRadioButton(lafInfos[i].getName()); + rb.setActionCommand(lafInfos[i].getClassName()); + rb.addActionListener(plafChanger); + group.add(rb); + panel.add(rb); + if (i == 0) { + rb.setSelected(true); + } + } + + frame.add(panel); + + ltrFrame = new JFrame("Left To Right"); + Container contentPane = ltrFrame.getContentPane(); + contentPane.setLayout(new BorderLayout()); + panel = new JPanel(); + panel.setBackground(Color.white); + contentPane.add("Center",panel); + contentPane.add("North", + createToolBar(ComponentOrientation.LEFT_TO_RIGHT)); + ltrFrame.setSize(400, 140); + ltrFrame.setLocation(new Point(10, 10)); + ltrFrame.setVisible(true); + + rtlFrame = new JFrame("Right To Left"); + contentPane = rtlFrame.getContentPane(); + contentPane.setLayout(new BorderLayout()); + panel = new JPanel(); + panel.setBackground(Color.white); + contentPane.add("Center",panel); + contentPane.add("North", + createToolBar(ComponentOrientation.RIGHT_TO_LEFT)); + rtlFrame.setSize(400, 140); + rtlFrame.setLocation(new Point(420, 10)); + rtlFrame.setVisible(true); + + frame.pack(); + return frame; + } + + static class PlafChanger implements ActionListener { + public void actionPerformed(ActionEvent e) { + String lnfName = e.getActionCommand(); + + try { + UIManager.setLookAndFeel(lnfName); + SwingUtilities.updateComponentTreeUI(ltrFrame); + SwingUtilities.updateComponentTreeUI(rtlFrame); + } + catch (Exception exc) { + System.err.println("Could not load LookAndFeel: " + lnfName); + } + + } + } + + + static JToolBar createToolBar(ComponentOrientation o) { + JToolBar toolBar = new JToolBar(); + toolBar.setComponentOrientation(o); + + JButton button = new JButton("One"); + button.setComponentOrientation(o); + toolBar.add(button); + + button = new JButton("Two"); + button.setComponentOrientation(o); + toolBar.add(button); + + button = new JButton("Three"); + button.setComponentOrientation(o); + toolBar.add(button); + + return toolBar; + } + +} diff --git a/test/jdk/javax/swing/JToolBar/bug4203039.java b/test/jdk/javax/swing/JToolBar/bug4203039.java new file mode 100644 index 00000000000..af8b1f122c0 --- /dev/null +++ b/test/jdk/javax/swing/JToolBar/bug4203039.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; + +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JToolBar; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4203039 + * @summary JToolBar needs a way to limit docking to a particular orientation + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4203039 + */ + +public class bug4203039 { + private static final String instructionsText = """ + This test is used to verify that application-installed + components prevent the toolbar from docking in + those locations. + + This test has installed components on the SOUTH + and EAST, so verify the toolbar cannot dock in those + locations but can dock on the NORTH and WEST"""; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("bug4203039 Instructions") + .instructions(instructionsText) + .testTimeOut(5) + .rows(10) + .columns(35) + .build(); + + SwingUtilities.invokeAndWait(() -> { + JFrame frame = new JFrame("bug4203039"); + frame.setSize(300, 200); + + JToolBar toolbar = new JToolBar(); + JLabel label = new JLabel("This is the toolbar"); + toolbar.add(label); + + frame.add(toolbar, BorderLayout.NORTH); + + frame.add(new JComponent(){}, BorderLayout.SOUTH); + frame.add(new JComponent(){}, BorderLayout.EAST); + + PassFailJFrame.addTestWindow(frame); + PassFailJFrame.positionTestWindow(frame, + PassFailJFrame.Position.HORIZONTAL); + + frame.setVisible(true); + }); + + passFailJFrame.awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/JTree/8003400/Test8003400.java b/test/jdk/javax/swing/JTree/8003400/Test8003400.java index 95f5e826aa9..dcc9b0fce6e 100644 --- a/test/jdk/javax/swing/JTree/8003400/Test8003400.java +++ b/test/jdk/javax/swing/JTree/8003400/Test8003400.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -109,6 +109,10 @@ public void run() { Robot robot = new Robot(); robot.setAutoDelay(100); + robot.setAutoWaitForIdle(true); + robot.waitForIdle(); + robot.delay(500); + SwingUtilities.invokeAndWait(() -> { point = tree.getLocationOnScreen(); rect = tree.getBounds(); diff --git a/test/jdk/javax/swing/border/Test4129681.html b/test/jdk/javax/swing/border/Test4129681.html deleted file mode 100644 index c80b417075a..00000000000 --- a/test/jdk/javax/swing/border/Test4129681.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - -When applet starts, you'll see a checkbox and a label with a titled border. -Turn on the checkbox to disable the label. -The test passes if the title of the border is disabled as well as the label. - - - - - diff --git a/test/jdk/javax/swing/border/Test4129681.java b/test/jdk/javax/swing/border/Test4129681.java index 330126d3f3f..993dc2d139c 100644 --- a/test/jdk/javax/swing/border/Test4129681.java +++ b/test/jdk/javax/swing/border/Test4129681.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,39 +21,62 @@ * questions. */ +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Point; +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.UIManager; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; + /* * @test * @bug 4129681 - * @summary Tests enabling/disabling of titled border's caption - * @author Sergey Malenkov - * @run applet/manual=yesno Test4129681.html + * @summary Tests disabling of titled border's caption + * @run main/othervm -Dsun.java2d.uiScale=1 Test4129681 */ -import java.awt.BorderLayout; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import javax.swing.BorderFactory; -import javax.swing.JApplet; -import javax.swing.JCheckBox; -import javax.swing.JLabel; +public class Test4129681 { + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + int correctColoredPixels = 0; + int totalPixels = 0; + int tolerance = 20; + JLabel label; + Color labelDisableColor = Color.RED; + Dimension SIZE = new Dimension(100, 40); + Point startPoint = new Point(8, 4); + Point endPoint = new Point(18, 14); -public class Test4129681 extends JApplet implements ItemListener { - private JLabel label; + label = new JLabel("Label"); + label.setBorder(BorderFactory.createTitledBorder("\u2588".repeat(5))); + UIManager.getDefaults().put("Label.disabledForeground", labelDisableColor); + label.setSize(SIZE); + label.setEnabled(false); + BufferedImage image = new BufferedImage(label.getWidth(), label.getHeight(), + BufferedImage.TYPE_INT_ARGB); - @Override - public void init() { - JCheckBox check = new JCheckBox("disable"); - check.addItemListener(this); + Graphics2D g2d = image.createGraphics(); + label.paint(g2d); + g2d.dispose(); - this.label = new JLabel("message"); - this.label.setBorder(BorderFactory.createTitledBorder("label")); - this.label.setEnabled(!check.isSelected()); - - add(BorderLayout.NORTH, check); - add(BorderLayout.CENTER, this.label); - } + for (int x = startPoint.x; x < endPoint.x; x++) { + for (int y = startPoint.y; y < endPoint.y; y++) { + if (image.getRGB(x, y) == labelDisableColor.getRGB()) { + correctColoredPixels++; + } + totalPixels++; + } + } - public void itemStateChanged(ItemEvent event) { - this.label.setEnabled(ItemEvent.DESELECTED == event.getStateChange()); + if (((double) correctColoredPixels / totalPixels * 100) <= tolerance) { + ImageIO.write(image, "png", new File("failureImage.png")); + throw new RuntimeException("Label with border is not disabled"); + } + System.out.println("Test Passed"); } } diff --git a/test/jdk/javax/swing/plaf/basic/BasicComboPopup/JComboBoxPopupLocation/JComboBoxPopupLocation.java b/test/jdk/javax/swing/plaf/basic/BasicComboPopup/JComboBoxPopupLocation/JComboBoxPopupLocation.java index 588abd90861..bd210fa557a 100644 --- a/test/jdk/javax/swing/plaf/basic/BasicComboPopup/JComboBoxPopupLocation/JComboBoxPopupLocation.java +++ b/test/jdk/javax/swing/plaf/basic/BasicComboPopup/JComboBoxPopupLocation/JComboBoxPopupLocation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -90,6 +90,7 @@ private static void step(GraphicsDevice[] sds, setup(point); }); robot.waitForIdle(); + robot.delay(500); test(comboBox); robot.waitForIdle(); validate(comboBox); @@ -110,6 +111,7 @@ private static void step(GraphicsDevice[] sds, setup(finalLeft); }); robot.waitForIdle(); + robot.delay(500); test(comboBox); robot.waitForIdle(); validate(comboBox); diff --git a/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java b/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java new file mode 100644 index 00000000000..0c23ee23b5b --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.IntStream; +import java.util.stream.LongStream; + +import javax.swing.JFileChooser; + +/* + * @test + * @bug 8323670 8307091 8240690 + * @requires os.family == "mac" | os.family == "linux" + * @summary Verifies thread-safety of BasicDirectoryModel (JFileChooser) + * @run main/othervm -Djava.awt.headless=true ConcurrentModification + */ +public final class ConcurrentModification extends ThreadGroup { + /** Initial number of files. */ + private static final long NUMBER_OF_FILES = 50; + /** Maximum number of files created on a timer tick. */ + private static final long LIMIT_FILES = 10; + + /** Timer period (delay) for creating new files. */ + private static final long TIMER_PERIOD = 250; + + /** + * Number of threads running {@code fileChooser.rescanCurrentDirectory()}. + */ + private static final int NUMBER_OF_THREADS = 5; + /** Number of repeated calls to {@code rescanCurrentDirectory}. */ + private static final int NUMBER_OF_REPEATS = 2_000; + /** Maximum amount a thread waits before initiating rescan. */ + private static final long LIMIT_SLEEP = 100; + + + /** The barrier to start all the scanner threads simultaneously. */ + private static final CyclicBarrier start = new CyclicBarrier(NUMBER_OF_THREADS); + /** The barrier to wait for all the scanner threads to complete, plus main thread. */ + private static final CyclicBarrier end = new CyclicBarrier(NUMBER_OF_THREADS + 1); + + /** List of scanner threads. */ + private static final List threads = new ArrayList<>(NUMBER_OF_THREADS); + + /** + * Stores an exception caught by any of the threads. + * If more exceptions are caught, they're added as suppressed exceptions. + */ + private static final AtomicReference exception = + new AtomicReference<>(); + + /** + * Stores an {@code IOException} thrown while removing the files. + */ + private static final AtomicReference ioException = + new AtomicReference<>(); + + + public static void main(String[] args) throws Throwable { + try { + // Start the test in its own thread group to catch and handle + // all thrown exceptions, in particular in + // BasicDirectoryModel.FilesLoader which is created by Swing. + ThreadGroup threadGroup = new ConcurrentModification(); + Thread runner = new Thread(threadGroup, + ConcurrentModification::wrapper, + "Test Runner"); + runner.start(); + runner.join(); + } catch (Throwable throwable) { + handleException(throwable); + } + + if (ioException.get() != null) { + System.err.println("An error occurred while removing files:"); + ioException.get().printStackTrace(); + } + + if (exception.get() != null) { + throw exception.get(); + } + } + + private static void wrapper() { + final long timeStart = System.currentTimeMillis(); + try { + runTest(timeStart); + } catch (Throwable throwable) { + handleException(throwable); + } finally { + System.out.printf("Duration: %,d\n", + (System.currentTimeMillis() - timeStart)); + } + } + + private static void runTest(final long timeStart) throws Throwable { + final Path temp = Files.createDirectory(Paths.get("fileChooser-concurrency-" + timeStart)); + + final Timer timer = new Timer("File creator"); + + try { + createFiles(temp); + + final JFileChooser fc = new JFileChooser(temp.toFile()); + + IntStream.range(0, NUMBER_OF_THREADS) + .forEach(i -> { + Thread thread = new Thread(new Scanner(fc)); + threads.add(thread); + thread.start(); + }); + + timer.scheduleAtFixedRate(new CreateFilesTimerTask(temp), + 0, TIMER_PERIOD); + + end.await(); + } catch (Throwable e) { + threads.forEach(Thread::interrupt); + throw e; + } finally { + timer.cancel(); + + deleteFiles(temp); + deleteFile(temp); + } + } + + + private ConcurrentModification() { + super("bdmConcurrency"); + } + + @Override + public void uncaughtException(Thread t, Throwable e) { + handleException(t, e); + } + + private static void handleException(Throwable throwable) { + handleException(Thread.currentThread(), throwable); + } + + private static void handleException(final Thread thread, + final Throwable throwable) { + System.err.println("Exception in " + thread.getName() + ": " + + throwable.getClass() + + (throwable.getMessage() != null + ? ": " + throwable.getMessage() + : "")); + if (!exception.compareAndSet(null, throwable)) { + exception.get().addSuppressed(throwable); + } + threads.stream() + .filter(t -> t != thread) + .forEach(Thread::interrupt); + } + + + private record Scanner(JFileChooser fileChooser) + implements Runnable { + + @Override + public void run() { + try { + start.await(); + + int counter = 0; + try { + do { + fileChooser.rescanCurrentDirectory(); + Thread.sleep((long) (Math.random() * LIMIT_SLEEP)); + } while (++counter < NUMBER_OF_REPEATS + && !Thread.interrupted()); + } catch (InterruptedException e) { + // Just exit the loop + } + } catch (Throwable throwable) { + handleException(throwable); + } finally { + try { + end.await(); + } catch (InterruptedException | BrokenBarrierException e) { + handleException(e); + } + } + } + } + + private static void createFiles(final Path parent) { + createFiles(parent, 0, NUMBER_OF_FILES); + } + + private static void createFiles(final Path parent, + final long start, + final long end) { + LongStream.range(start, end) + .forEach(n -> createFile(parent.resolve(n + ".file"))); + } + + private static void createFile(final Path file) { + try { + Files.createFile(file); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static void deleteFiles(final Path parent) throws IOException { + try (var stream = Files.walk(parent)) { + stream.filter(p -> p != parent) + .forEach(ConcurrentModification::deleteFile); + } + } + + private static void deleteFile(final Path file) { + try { + Files.delete(file); + } catch (IOException e) { + if (!ioException.compareAndSet(null, e)) { + ioException.get().addSuppressed(e); + } + } + } + + private static final class CreateFilesTimerTask extends TimerTask { + private final Path temp; + private long no; + + public CreateFilesTimerTask(Path temp) { + this.temp = temp; + no = NUMBER_OF_FILES; + } + + @Override + public void run() { + try { + long count = (long) (Math.random() * LIMIT_FILES); + createFiles(temp, no, no + count); + no += count; + } catch (Throwable t) { + handleException(t); + } + } + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/LoaderThreadCount.java b/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/LoaderThreadCount.java new file mode 100644 index 00000000000..770c8f92b26 --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/LoaderThreadCount.java @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.LongStream; +import java.util.stream.Stream; + +import javax.swing.JFileChooser; + +/* + * @test + * @bug 8325179 + * @requires os.family == "windows" + * @summary Verifies there's only one BasicDirectoryModel.FilesLoader thread + * at any given moment + * @run main/othervm -Djava.awt.headless=true LoaderThreadCount + */ +public final class LoaderThreadCount extends ThreadGroup { + /** Initial number of files. */ + private static final long NUMBER_OF_FILES = 500; + + /** + * Number of threads running {@code fileChooser.rescanCurrentDirectory()}. + */ + private static final int NUMBER_OF_THREADS = 5; + + /** Number of snapshots with live threads. */ + private static final int SNAPSHOTS = 20; + + /** The barrier to synchronise scanner threads and capturing live threads. */ + private static final CyclicBarrier start = new CyclicBarrier(NUMBER_OF_THREADS + 1); + + /** List of scanner threads. */ + private static final List threads = new ArrayList<>(NUMBER_OF_THREADS); + + /** + * Stores an exception caught by any of the threads. + * If more exceptions are caught, they're added as suppressed exceptions. + */ + private static final AtomicReference exception = + new AtomicReference<>(); + + /** + * Stores an {@code IOException} thrown while removing the files. + */ + private static final AtomicReference ioException = + new AtomicReference<>(); + + + public static void main(String[] args) throws Throwable { + try { + // Start the test in its own thread group to catch and handle + // all thrown exceptions, in particular in + // BasicDirectoryModel.FilesLoader which is created by Swing. + ThreadGroup threadGroup = new LoaderThreadCount(); + Thread runner = new Thread(threadGroup, + LoaderThreadCount::wrapper, + "Test Runner"); + runner.start(); + runner.join(); + } catch (Throwable throwable) { + handleException(throwable); + } + + if (ioException.get() != null) { + System.err.println("An error occurred while removing files:"); + ioException.get().printStackTrace(); + } + + if (exception.get() != null) { + throw exception.get(); + } + } + + private static void wrapper() { + final long timeStart = System.currentTimeMillis(); + try { + runTest(timeStart); + } catch (Throwable throwable) { + handleException(throwable); + } finally { + System.out.printf("Duration: %,d\n", + (System.currentTimeMillis() - timeStart)); + } + } + + private static void runTest(final long timeStart) throws Throwable { + final Path temp = Files.createDirectory(Paths.get("fileChooser-concurrency-" + timeStart)); + + try { + createFiles(temp); + + final JFileChooser fc = new JFileChooser(temp.toFile()); + + threads.addAll(Stream.generate(() -> new Thread(new Scanner(fc))) + .limit(NUMBER_OF_THREADS) + .toList()); + threads.forEach(Thread::start); + + // Create snapshots of live threads + List threadsCapture = + Stream.generate(LoaderThreadCount::getThreadSnapshot) + .limit(SNAPSHOTS) + .toList(); + + threads.forEach(Thread::interrupt); + + List loaderCount = + threadsCapture.stream() + .map(ta -> Arrays.stream(ta) + .filter(Objects::nonNull) + .map(Thread::getName) + .filter(tn -> tn.startsWith("Basic L&F File Loading Thread")) + .count()) + .filter(c -> c > 0) + .toList(); + + if (loaderCount.isEmpty()) { + throw new RuntimeException("Invalid results: no loader threads detected"); + } + + System.out.println("Number of snapshots: " + loaderCount.size()); + + long ones = loaderCount.stream() + .filter(n -> n == 1) + .count(); + long twos = loaderCount.stream() + .filter(n -> n == 2) + .count(); + long count = loaderCount.stream() + .filter(n -> n > 2) + .count(); + System.out.println("Number of snapshots where number of loader threads:"); + System.out.println(" = 1: " + ones); + System.out.println(" = 2: " + twos); + System.out.println(" > 2: " + count); + if (count > loaderCount.size() / 2) { + throw new RuntimeException("Detected " + count + " snapshots " + + "with several loading threads"); + } + } catch (Throwable e) { + threads.forEach(Thread::interrupt); + throw e; + } finally { + deleteFiles(temp); + deleteFile(temp); + } + } + + private static Thread[] getThreadSnapshot() { + try { + start.await(); + // Allow for the scanner threads to initiate re-scanning + Thread.sleep(10); + + Thread[] array = new Thread[Thread.activeCount()]; + Thread.currentThread() + .getThreadGroup() + .enumerate(array, false); + + // Additional delay between captures + Thread.sleep(500); + + return array; + } catch (InterruptedException | BrokenBarrierException e) { + handleException(e); + throw new RuntimeException("getThreadSnapshot is interrupted"); + } + } + + + private LoaderThreadCount() { + super("bdmConcurrency"); + } + + @Override + public void uncaughtException(Thread t, Throwable e) { + handleException(t, e); + } + + private static void handleException(Throwable throwable) { + handleException(Thread.currentThread(), throwable); + } + + private static void handleException(final Thread thread, + final Throwable throwable) { + System.err.println("Exception in " + thread.getName() + ": " + + throwable.getClass() + + (throwable.getMessage() != null + ? ": " + throwable.getMessage() + : "")); + if (!exception.compareAndSet(null, throwable)) { + exception.get().addSuppressed(throwable); + } + threads.stream() + .filter(t -> t != thread) + .forEach(Thread::interrupt); + } + + + private record Scanner(JFileChooser fileChooser) + implements Runnable { + + @Override + public void run() { + try { + do { + start.await(); + fileChooser.rescanCurrentDirectory(); + } while (!Thread.interrupted()); + } catch (InterruptedException | BrokenBarrierException e) { + // Just exit the loop + } + } + } + + private static void createFiles(final Path parent) { + LongStream.range(0, LoaderThreadCount.NUMBER_OF_FILES) + .mapToObj(n -> parent.resolve(n + ".file")) + .forEach(LoaderThreadCount::createFile); + } + + private static void createFile(final Path file) { + try { + Files.createFile(file); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static void deleteFiles(final Path parent) throws IOException { + try (var stream = Files.walk(parent)) { + stream.filter(p -> p != parent) + .forEach(LoaderThreadCount::deleteFile); + } + } + + private static void deleteFile(final Path file) { + try { + Files.delete(file); + } catch (IOException e) { + if (!ioException.compareAndSet(null, e)) { + ioException.get().addSuppressed(e); + } + } + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicMenuUI/4983388/bug4983388.java b/test/jdk/javax/swing/plaf/basic/BasicMenuUI/4983388/bug4983388.java index 957f0e2cfe8..18f78d88f52 100644 --- a/test/jdk/javax/swing/plaf/basic/BasicMenuUI/4983388/bug4983388.java +++ b/test/jdk/javax/swing/plaf/basic/BasicMenuUI/4983388/bug4983388.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ public class bug4983388 { static volatile boolean bMenuSelected = false; + static JFrame frame; private static class TestMenuListener implements MenuListener { public void menuCanceled(MenuEvent e) {} @@ -55,8 +56,9 @@ private static void createAndShowGUI() { JMenu menu = new JMenu("File"); menu.setMnemonic('F'); menuBar.add(menu); - JFrame frame = new JFrame(); + frame = new JFrame(); frame.setJMenuBar(menuBar); + frame.setLocationRelativeTo(null); frame.pack(); frame.setVisible(true); MenuListener listener = new TestMenuListener(); @@ -80,9 +82,13 @@ public void run() { Robot robot = new Robot(); robot.setAutoDelay(50); robot.waitForIdle(); + robot.delay(500); + Util.hitMnemonics(robot, KeyEvent.VK_F); robot.waitForIdle(); - robot.delay(200); + robot.delay(500); + + SwingUtilities.invokeAndWait(() -> frame.dispose()); if (!bMenuSelected) { throw new RuntimeException("shortcuts on menus do not work"); diff --git a/test/jdk/javax/swing/text/JTextComponent/5074573/bug5074573.java b/test/jdk/javax/swing/text/JTextComponent/5074573/bug5074573.java index 2c83bf2f3a9..5d66a477473 100644 --- a/test/jdk/javax/swing/text/JTextComponent/5074573/bug5074573.java +++ b/test/jdk/javax/swing/text/JTextComponent/5074573/bug5074573.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @key headful * @bug 5074573 8196100 - * @summary tests delte-next-word and delete-prev-word actions for all text compnents and all look&feels + * @summary tests delete-next-word and delete-prev-word actions for all text components and all look&feels * @run main bug5074573 */ @@ -49,6 +49,8 @@ public class bug5074573 { private static JTextComponent textComponent; + private static JFrame frame; + private static Robot robot; final static String testString = "123 456 789"; final static String resultString = "456 "; final static List> textClasses = Arrays.asList( @@ -56,24 +58,32 @@ public class bug5074573 { JTextField.class, JFormattedTextField.class, JPasswordField.class); public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(50); + for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { UIManager.setLookAndFeel(info.getClassName()); System.out.println(info); for (Class clazz : textClasses) { - boolean res = test(clazz); - if (!res && clazz != JPasswordField.class) { - throw new RuntimeException("failed"); + try { + boolean res = test(clazz); + if (!res && clazz != JPasswordField.class) { + throw new RuntimeException("failed"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + frame = null; + } + }); } } } } static boolean test(final Class textComponentClass) throws Exception { - Robot robot = new Robot(); - robot.setAutoWaitForIdle(true); - robot.setAutoDelay(50); - - SwingUtilities.invokeAndWait(new Runnable() { @Override @@ -83,6 +93,7 @@ public void run() { }); robot.waitForIdle(); + robot.delay(500); // Remove selection from JTextField components for the Aqua Look & Feel if (textComponent instanceof JTextField && "Aqua".equals(UIManager.getLookAndFeel().getID())) { @@ -120,6 +131,7 @@ public void run() { robot.keyRelease(KeyEvent.VK_DELETE); robot.keyRelease(getCtrlKey()); robot.waitForIdle(); + robot.delay(250); return resultString.equals(getText()); } @@ -152,7 +164,7 @@ public static int getCtrlKey() { private static void initialize(Class textComponentClass) { try { - JFrame frame = new JFrame(); + frame = new JFrame(); textComponent = textComponentClass.newInstance(); textComponent.setText(testString); frame.add(textComponent); diff --git a/test/jdk/javax/swing/text/PaintTest.java b/test/jdk/javax/swing/text/PaintTest.java new file mode 100644 index 00000000000..9df7e54b22e --- /dev/null +++ b/test/jdk/javax/swing/text/PaintTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4210250 + * @summary Tests that PlainView repaints the necessary lines of text. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PaintTest + */ + +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; + +public class PaintTest { + + private static final String INSTRUCTIONS = """ + Click the paint button. + If half of the second line is erased, + that is you can only see the bottom half of the second line + with the top half painted over in white, click fail, else click pass."""; + + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("PlainView Repaint Instructions") + .instructions(INSTRUCTIONS) + .rows(7) + .columns(35) + .testUI(PaintTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("PaintTest"); + + new PaintTest().create(frame.getContentPane()); + frame.pack(); + return frame; + } + + + void create(Container parent) { + parent.setLayout(new FlowLayout()); + + final JTextArea ta = new JTextArea + ("A sample textarea\nwith a couple of lines\nof text") { + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + if (getFont() != null) { + size.height += getFontMetrics(getFont()) + .getHeight() / 2; + } + return size; + } + }; + JButton button = new JButton("paint"); + + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + Rectangle taBounds = ta.getBounds(); + int fontHeight = + ta.getFontMetrics(ta.getFont()).getHeight(); + + taBounds.height = fontHeight + fontHeight / 2; + ta.repaint(taBounds); + } + }); + } + }); + + parent.add(new JScrollPane(ta)); + parent.add(button); + } +} diff --git a/test/jdk/javax/swing/text/bug4148489.java b/test/jdk/javax/swing/text/bug4148489.java new file mode 100644 index 00000000000..12fc5849d47 --- /dev/null +++ b/test/jdk/javax/swing/text/bug4148489.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4148489 + * @summary Text gets deleted with negative values for setFirstLineIndent. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4148489 + */ + +import java.awt.BorderLayout; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextPane; +import javax.swing.UIManager; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultStyledDocument; +import javax.swing.text.JTextComponent; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyleContext; +import javax.swing.text.Style; + +public class bug4148489 { + + static StyleContext sc; + static DefaultStyledDocument doc; + + private static final String INSTRUCTIONS = """ + Put the cursor at the beginning of the first text line and move the + cursor to the right using arrow key. + If the text is not corrupted then click Pass + If the text disappear while cursor moves click Fail."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Text traversal Instructions") + .instructions(INSTRUCTIONS) + .rows(5) + .columns(35) + .testUI(bug4148489::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + try { + UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); + } catch (Exception e) { + System.err.println("Error loading L&F: " + e); + } + JPanel testPanel = new JPanel(); + testPanel.setLayout(new BorderLayout()); + sc = new StyleContext(); + doc = new DefaultStyledDocument(sc); + + setParagraph(); + JTextComponent editor = new JTextPane(doc); + JScrollPane scroller = new JScrollPane(); + scroller.getViewport().add(editor); + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.add("Center", scroller); + testPanel.add("Center", panel); + JFrame frame = new JFrame("Styled Document"); + frame.add(testPanel); + frame.pack(); + return frame; + } + + static void setParagraph() { + Style sty = sc.addStyle("normal", sc.getStyle(StyleContext.DEFAULT_STYLE)); + //here sets the negative value for setFirstLineIndent + StyleConstants.setFirstLineIndent(sty, -50); + StyleConstants.setLeftIndent(sty, 50); + String data = "Here I wrote some text for test. You can ignore this text because of it's a senseless text."; + try { + Style s = null; + doc.insertString(doc.getLength(), data, s); + Style ls = sc.getStyle("normal"); + doc.setLogicalStyle(doc.getLength() - 1, ls); + doc.insertString(doc.getLength(), "\n", null); + } catch (BadLocationException e) { + throw new RuntimeException("BadLocationException occures while calls insertString()...", e); + } + } +} diff --git a/test/jdk/javax/swing/text/html/HTMLDocument/HTMLStrikeOnly.java b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLStrikeOnly.java new file mode 100644 index 00000000000..5ec32f74d40 --- /dev/null +++ b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLStrikeOnly.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.JEditorPane; +import javax.swing.text.View; +import javax.swing.text.html.CSS; + +/* + * @test + * @bug 8326734 + * @summary Tests different combinations of setting 'line-through' + * @run main HTMLStrikeOnly + */ +public class HTMLStrikeOnly { + private static final String HTML = """ + + + + + line-through + + + +

line-through?

+

line-through?

+

line-through?

+

line-through?

+ +

line-through?

+

line-through?

+

line-through?

+

line-through?

+ +

line-through?

+

line-through?

+

line-through?

+ +

line-through

+

line-through

+

line-through

+

line-through

+ + + """; + public static void main(String[] args) { + final JEditorPane html = new JEditorPane("text/html", HTML); + html.setEditable(false); + + final Dimension size = html.getPreferredSize(); + html.setSize(size); + + BufferedImage image = new BufferedImage(size.width, size.height, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.createGraphics(); + // Paint the editor pane to ensure all views are created + html.paint(g); + g.dispose(); + + int errorCount = 0; + String firstError = null; + + System.out.println("----- Views -----"); + final View bodyView = html.getUI() + .getRootView(html) + .getView(1) + .getView(1); + for (int i = 0; i < bodyView.getViewCount(); i++) { + View pView = bodyView.getView(i); + View contentView = getContentView(pView); + + String decoration = + contentView.getAttributes() + .getAttribute(CSS.Attribute.TEXT_DECORATION) + .toString(); + + System.out.println(i + ": " + decoration); + if (!decoration.contains("line-through") + || decoration.contains("underline")) { + errorCount++; + if (firstError == null) { + firstError = "Line " + i + ": " + decoration; + } + } + } + + if (errorCount > 0) { + saveImage(image); + throw new RuntimeException(errorCount + " error(s) found, " + + "the first one: " + firstError); + } + } + + private static View getContentView(View parent) { + View view = parent.getView(0); + return view.getViewCount() > 0 + ? getContentView(view) + : view; + } + + private static void saveImage(BufferedImage image) { + try { + ImageIO.write(image, "png", + new File("html.png")); + } catch (IOException ignored) { } + } +} diff --git a/test/jdk/javax/swing/text/html/HTMLDocument/HTMLTextDecoration.java b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLTextDecoration.java new file mode 100644 index 00000000000..a8868d05a5a --- /dev/null +++ b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLTextDecoration.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.JEditorPane; +import javax.swing.text.View; +import javax.swing.text.html.CSS; + +/* + * @test + * @bug 8323801 8326734 + * @summary Tests different combination of 'underline' and 'line-through'; + * the text should render with both 'underline' and 'line-through'. + * @run main HTMLTextDecoration + */ +public final class HTMLTextDecoration { + private static final String HTML = """ + + + + + underline + line-through text + + + +

underline + line-through?

+

underline + line-through?

+

underline + line-through?

+ +

underline + line-through?

+

underline + line-through?

+

underline + line-through?

+ +

underline + line-through?

+

underline + line-through?

+ +

underline + line-through?

+

underline + line-through?

+

underline + line-through?

+ +

underline + line-through?

+

underline + line-through?

+ +

underline + line-through?

+

underline + line-through?

+

underline + line-through?

+ +

underline + line-through?

+

underline + line-through?

+ +
underline + line-through?
+
underline + line-through?
+
underline + line-through?
+ +
underline + line-through?
+
underline + line-through?
+ +

underline + line-through?

+

underline + line-through?

+ +
underline + line-through?
+
underline + line-through?
+ + + """; + + public static void main(String[] args) { + final JEditorPane html = new JEditorPane("text/html", HTML); + html.setEditable(false); + + final Dimension size = html.getPreferredSize(); + html.setSize(size); + + BufferedImage image = new BufferedImage(size.width, size.height, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.createGraphics(); + // Paint the editor pane to ensure all views are created + html.paint(g); + g.dispose(); + + int errorCount = 0; + String firstError = null; + + System.out.println("----- Views -----"); + final View bodyView = html.getUI() + .getRootView(html) + .getView(1) + .getView(1); + for (int i = 0; i < bodyView.getViewCount(); i++) { + View pView = bodyView.getView(i); + View contentView = getContentView(pView); + + String decoration = + contentView.getAttributes() + .getAttribute(CSS.Attribute.TEXT_DECORATION) + .toString(); + + System.out.println(i + ": " + decoration); + if (!decoration.contains("underline") + || !decoration.contains("line-through")) { + errorCount++; + if (firstError == null) { + firstError = "Line " + i + ": " + decoration; + } + } + } + + if (errorCount > 0) { + saveImage(image); + throw new RuntimeException(errorCount + " error(s) found, " + + "the first one: " + firstError); + } + } + + private static View getContentView(View parent) { + View view = parent.getView(0); + return view.getViewCount() > 0 + ? getContentView(view) + : view; + } + + private static void saveImage(BufferedImage image) { + try { + ImageIO.write(image, "png", + new File("html.png")); + } catch (IOException ignored) { } + } +} diff --git a/test/jdk/javax/swing/text/html/HTMLDocument/HTMLTextDecorationNone.java b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLTextDecorationNone.java new file mode 100644 index 00000000000..318626e5110 --- /dev/null +++ b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLTextDecorationNone.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.JEditorPane; +import javax.swing.text.View; +import javax.swing.text.html.CSS; + +/* + * @test + * @bug 8335967 + * @summary Tests 'text-decoration: none' is respected + * @run main HTMLTextDecorationNone + */ +public final class HTMLTextDecorationNone { + private static final String HTML = """ + + + + + text-decoration: none (<a>) + + + +

underlined

+

not underlined

+

not underlined

+

underlined?

+

underlined?

+ + + """; + + private static final boolean[] underlined = {true, false, false, true, true}; + + public static void main(String[] args) { + final JEditorPane html = new JEditorPane("text/html", HTML); + html.setEditable(false); + + final Dimension size = html.getPreferredSize(); + html.setSize(size); + + BufferedImage image = new BufferedImage(size.width, size.height, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.createGraphics(); + // Paint the editor pane to ensure all views are created + html.paint(g); + g.dispose(); + + int errorCount = 0; + String firstError = null; + + System.out.println("----- Views -----"); + final View bodyView = html.getUI() + .getRootView(html) + .getView(1) + .getView(1); + for (int i = 0; i < bodyView.getViewCount(); i++) { + View pView = bodyView.getView(i); + View contentView = getContentView(pView); + + Object decorationAttr = + contentView.getAttributes() + .getAttribute(CSS.Attribute.TEXT_DECORATION); + String decoration = decorationAttr == null + ? "none" : decorationAttr.toString(); + + System.out.println(i + ": " + decoration); + if (decoration.contains("underline") != underlined[i]) { + errorCount++; + if (firstError == null) { + firstError = "Line " + i + ": " + decoration + " vs " + + (underlined[i] ? "underline" : "none"); + } + } + } + + if (errorCount > 0) { + saveImage(image); + throw new RuntimeException(errorCount + " error(s) found, " + + "the first one: " + firstError); + } + } + + private static View getContentView(View parent) { + View view = parent.getView(0); + return view.getViewCount() > 0 + ? getContentView(view) + : view; + } + + private static void saveImage(BufferedImage image) { + try { + ImageIO.write(image, "png", + new File("html.png")); + } catch (IOException ignored) { } + } +} diff --git a/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineOnly.java b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineOnly.java new file mode 100644 index 00000000000..e142203b458 --- /dev/null +++ b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineOnly.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.JEditorPane; +import javax.swing.text.View; +import javax.swing.text.html.CSS; + +/* + * @test + * @bug 8326734 + * @summary Tests different combinations of setting 'underline' + * @run main HTMLUnderlineOnly + */ +public class HTMLUnderlineOnly { + private static final String HTML = """ + + + + + underline + + + +

underline?

+

underline?

+ +

underline?

+

underline?

+ +

underline?

+

underline?

+ +

underline

+

underline

+

underline

+ + + """; + public static void main(String[] args) { + final JEditorPane html = new JEditorPane("text/html", HTML); + html.setEditable(false); + + final Dimension size = html.getPreferredSize(); + html.setSize(size); + + BufferedImage image = new BufferedImage(size.width, size.height, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.createGraphics(); + // Paint the editor pane to ensure all views are created + html.paint(g); + g.dispose(); + + int errorCount = 0; + String firstError = null; + + System.out.println("----- Views -----"); + final View bodyView = html.getUI() + .getRootView(html) + .getView(1) + .getView(1); + for (int i = 0; i < bodyView.getViewCount(); i++) { + View pView = bodyView.getView(i); + View contentView = getContentView(pView); + + String decoration = + contentView.getAttributes() + .getAttribute(CSS.Attribute.TEXT_DECORATION) + .toString(); + + System.out.println(i + ": " + decoration); + if (!decoration.contains("underline") + || decoration.contains("line-through")) { + errorCount++; + if (firstError == null) { + firstError = "Line " + i + ": " + decoration; + } + } + } + + if (errorCount > 0) { + saveImage(image); + throw new RuntimeException(errorCount + " error(s) found, " + + "the first one: " + firstError); + } + } + + private static View getContentView(View parent) { + View view = parent.getView(0); + return view.getViewCount() > 0 + ? getContentView(view) + : view; + } + + private static void saveImage(BufferedImage image) { + try { + ImageIO.write(image, "png", + new File("html.png")); + } catch (IOException ignored) { } + } +} diff --git a/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineStrike.java b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineStrike.java new file mode 100644 index 00000000000..79aa5c81281 --- /dev/null +++ b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineStrike.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.StringReader; + +import javax.swing.text.AttributeSet; +import javax.swing.text.Element; +import javax.swing.text.html.CSS; +import javax.swing.text.html.HTMLDocument; +import javax.swing.text.html.HTMLEditorKit; + +/* + * @test + * @bug 8323801 8326734 + * @summary Tests that '' produce underlined and struck-through text + */ +public final class HTMLUnderlineStrike { + private static final String HTML = """ + + + + + Strike-through text + + +

struck?

+

struck?

+ +

struck?

+

struck?

+ + + """; + + public static void main(String[] args) throws Exception { + HTMLEditorKit kit = new HTMLEditorKit(); + HTMLDocument doc = new HTMLDocument(); + + try (StringReader reader = new StringReader(HTML)) { + kit.read(reader, doc, 0); + } + + StringBuilder errors = new StringBuilder(); + + Element root = doc.getDefaultRootElement(); + Element body = root.getElement(1); + for (int i = 0; i < body.getElementCount(); i++) { + Element p = body.getElement(i); + Element content = p.getElement(0); + AttributeSet attr = content.getAttributes(); + Object decoration = attr.getAttribute(CSS.Attribute.TEXT_DECORATION); + String strDecoration = decoration.toString(); + System.out.println(i + ": " + decoration); + if (!strDecoration.contains("line-through") + || !strDecoration.contains("underline")) { + errors.append("

[") + .append(i) + .append("], "); + } + } + + if (!errors.isEmpty()) { + errors.delete(errors.length() - 2, errors.length()); + throw new RuntimeException(errors + " must have both " + + "'line-through' and 'underline' in " + + "'text-decoration'"); + } + } +} diff --git a/test/jdk/javax/swing/text/html/StyleSheet/bug4803145.java b/test/jdk/javax/swing/text/html/StyleSheet/bug4803145.java new file mode 100644 index 00000000000..2d701657234 --- /dev/null +++ b/test/jdk/javax/swing/text/html/StyleSheet/bug4803145.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +/* + * @test + * @bug 4803145 + * @summary Tests if bullets for HTML

    are on the correct side for Arabic and Hebrew in JEditorPane + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4803145 +*/ + +import java.awt.BorderLayout; +import java.awt.ComponentOrientation; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.text.html.HTMLEditorKit; + +public class bug4803145 { + + private static final String INSTRUCTIONS = """ + A JEditorPane with some html list in Hebrew appears. + The bullets should be on the left side of the list items. + Press the "switch text orientation" button. + After the text relayouts: + + - If the bullets are to the right of the list items then test PASSED. + + - If the bullets remained on the left side then test FAILED."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JEditorPane Instructions") + .instructions(INSTRUCTIONS) + .rows(10) + .columns(30) + .testUI(bug4803145::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + + String text = + "
      " + + "
    • מבוא" + + "
    • אחסון" + + "
    • (new code) הקוד הישן (Old Code)" + + "
    "; + + JFrame f = new JFrame("bug4803145"); + JEditorPane jep = new JEditorPane(); + jep.setEditorKit(new HTMLEditorKit()); + jep.setEditable(false); + + jep.setText(text); + + f.setSize(500, 500); + f.add(jep); + + JButton switchButton = new JButton("switch text orientation"); + switchButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + boolean isLeftToRight = jep.getComponentOrientation().isLeftToRight(); + jep.setComponentOrientation(isLeftToRight ? ComponentOrientation.RIGHT_TO_LEFT : + ComponentOrientation.LEFT_TO_RIGHT); + } + }); + f.add(switchButton, BorderLayout.SOUTH); + f.pack(); + return f; + } + +} diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index 383d42cfa55..f7c955a08ce 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -60,6 +60,8 @@ public class Double128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1078,6 +1093,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2168,7 +2191,7 @@ static void ADDReduceDouble128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double128VectorTests::ADDReduce, Double128VectorTests::ADDReduceAll); + Double128VectorTests::ADDReduce, Double128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2214,7 +2237,7 @@ static void ADDReduceDouble128VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double128VectorTests::ADDReduceMasked, Double128VectorTests::ADDReduceAllMasked); + Double128VectorTests::ADDReduceMasked, Double128VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { @@ -2257,7 +2280,7 @@ static void MULReduceDouble128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double128VectorTests::MULReduce, Double128VectorTests::MULReduceAll); + Double128VectorTests::MULReduce, Double128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2303,7 +2326,7 @@ static void MULReduceDouble128VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double128VectorTests::MULReduceMasked, Double128VectorTests::MULReduceAllMasked); + Double128VectorTests::MULReduceMasked, Double128VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index 770e95938f5..27f9c0df194 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -60,6 +60,8 @@ public class Double256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1078,6 +1093,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2168,7 +2191,7 @@ static void ADDReduceDouble256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double256VectorTests::ADDReduce, Double256VectorTests::ADDReduceAll); + Double256VectorTests::ADDReduce, Double256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2214,7 +2237,7 @@ static void ADDReduceDouble256VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double256VectorTests::ADDReduceMasked, Double256VectorTests::ADDReduceAllMasked); + Double256VectorTests::ADDReduceMasked, Double256VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { @@ -2257,7 +2280,7 @@ static void MULReduceDouble256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double256VectorTests::MULReduce, Double256VectorTests::MULReduceAll); + Double256VectorTests::MULReduce, Double256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2303,7 +2326,7 @@ static void MULReduceDouble256VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double256VectorTests::MULReduceMasked, Double256VectorTests::MULReduceAllMasked); + Double256VectorTests::MULReduceMasked, Double256VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index f42c5930f48..440a553dc33 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -60,6 +60,8 @@ public class Double512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1078,6 +1093,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2168,7 +2191,7 @@ static void ADDReduceDouble512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double512VectorTests::ADDReduce, Double512VectorTests::ADDReduceAll); + Double512VectorTests::ADDReduce, Double512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2214,7 +2237,7 @@ static void ADDReduceDouble512VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double512VectorTests::ADDReduceMasked, Double512VectorTests::ADDReduceAllMasked); + Double512VectorTests::ADDReduceMasked, Double512VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { @@ -2257,7 +2280,7 @@ static void MULReduceDouble512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double512VectorTests::MULReduce, Double512VectorTests::MULReduceAll); + Double512VectorTests::MULReduce, Double512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2303,7 +2326,7 @@ static void MULReduceDouble512VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double512VectorTests::MULReduceMasked, Double512VectorTests::MULReduceAllMasked); + Double512VectorTests::MULReduceMasked, Double512VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index a58fda6dc06..73ac9b00c05 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -60,6 +60,8 @@ public class Double64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1078,6 +1093,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2168,7 +2191,7 @@ static void ADDReduceDouble64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double64VectorTests::ADDReduce, Double64VectorTests::ADDReduceAll); + Double64VectorTests::ADDReduce, Double64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2214,7 +2237,7 @@ static void ADDReduceDouble64VectorTestsMasked(IntFunction fa, IntFunc } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double64VectorTests::ADDReduceMasked, Double64VectorTests::ADDReduceAllMasked); + Double64VectorTests::ADDReduceMasked, Double64VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { @@ -2257,7 +2280,7 @@ static void MULReduceDouble64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double64VectorTests::MULReduce, Double64VectorTests::MULReduceAll); + Double64VectorTests::MULReduce, Double64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2303,7 +2326,7 @@ static void MULReduceDouble64VectorTestsMasked(IntFunction fa, IntFunc } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double64VectorTests::MULReduceMasked, Double64VectorTests::MULReduceAllMasked); + Double64VectorTests::MULReduceMasked, Double64VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index 33bff482c9e..296e23a7023 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -65,6 +65,8 @@ static VectorShape getMaxBit() { private static final int Max = 256; // juts so we can do N/Max + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); @@ -124,15 +126,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -146,15 +154,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1083,6 +1098,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2173,7 +2196,7 @@ static void ADDReduceDoubleMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - DoubleMaxVectorTests::ADDReduce, DoubleMaxVectorTests::ADDReduceAll); + DoubleMaxVectorTests::ADDReduce, DoubleMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2219,7 +2242,7 @@ static void ADDReduceDoubleMaxVectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - DoubleMaxVectorTests::ADDReduceMasked, DoubleMaxVectorTests::ADDReduceAllMasked); + DoubleMaxVectorTests::ADDReduceMasked, DoubleMaxVectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { @@ -2262,7 +2285,7 @@ static void MULReduceDoubleMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - DoubleMaxVectorTests::MULReduce, DoubleMaxVectorTests::MULReduceAll); + DoubleMaxVectorTests::MULReduce, DoubleMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2308,7 +2331,7 @@ static void MULReduceDoubleMaxVectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - DoubleMaxVectorTests::MULReduceMasked, DoubleMaxVectorTests::MULReduceAllMasked); + DoubleMaxVectorTests::MULReduceMasked, DoubleMaxVectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index 40637be249b..bf61881e3d8 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -60,6 +60,8 @@ public class Float128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1089,6 +1104,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2179,7 +2202,7 @@ static void ADDReduceFloat128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float128VectorTests::ADDReduce, Float128VectorTests::ADDReduceAll); + Float128VectorTests::ADDReduce, Float128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2225,7 +2248,7 @@ static void ADDReduceFloat128VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float128VectorTests::ADDReduceMasked, Float128VectorTests::ADDReduceAllMasked); + Float128VectorTests::ADDReduceMasked, Float128VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { @@ -2268,7 +2291,7 @@ static void MULReduceFloat128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float128VectorTests::MULReduce, Float128VectorTests::MULReduceAll); + Float128VectorTests::MULReduce, Float128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2314,7 +2337,7 @@ static void MULReduceFloat128VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float128VectorTests::MULReduceMasked, Float128VectorTests::MULReduceAllMasked); + Float128VectorTests::MULReduceMasked, Float128VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index 874a064544e..7292f55aa6d 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -60,6 +60,8 @@ public class Float256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1089,6 +1104,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2179,7 +2202,7 @@ static void ADDReduceFloat256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float256VectorTests::ADDReduce, Float256VectorTests::ADDReduceAll); + Float256VectorTests::ADDReduce, Float256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2225,7 +2248,7 @@ static void ADDReduceFloat256VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float256VectorTests::ADDReduceMasked, Float256VectorTests::ADDReduceAllMasked); + Float256VectorTests::ADDReduceMasked, Float256VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { @@ -2268,7 +2291,7 @@ static void MULReduceFloat256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float256VectorTests::MULReduce, Float256VectorTests::MULReduceAll); + Float256VectorTests::MULReduce, Float256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2314,7 +2337,7 @@ static void MULReduceFloat256VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float256VectorTests::MULReduceMasked, Float256VectorTests::MULReduceAllMasked); + Float256VectorTests::MULReduceMasked, Float256VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index e006883aa9f..01d1e27209b 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -60,6 +60,8 @@ public class Float512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1089,6 +1104,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2179,7 +2202,7 @@ static void ADDReduceFloat512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float512VectorTests::ADDReduce, Float512VectorTests::ADDReduceAll); + Float512VectorTests::ADDReduce, Float512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2225,7 +2248,7 @@ static void ADDReduceFloat512VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float512VectorTests::ADDReduceMasked, Float512VectorTests::ADDReduceAllMasked); + Float512VectorTests::ADDReduceMasked, Float512VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { @@ -2268,7 +2291,7 @@ static void MULReduceFloat512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float512VectorTests::MULReduce, Float512VectorTests::MULReduceAll); + Float512VectorTests::MULReduce, Float512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2314,7 +2337,7 @@ static void MULReduceFloat512VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float512VectorTests::MULReduceMasked, Float512VectorTests::MULReduceAllMasked); + Float512VectorTests::MULReduceMasked, Float512VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index 8d98d2a72f5..b7fd8ab2767 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -60,6 +60,8 @@ public class Float64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1089,6 +1104,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2179,7 +2202,7 @@ static void ADDReduceFloat64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float64VectorTests::ADDReduce, Float64VectorTests::ADDReduceAll); + Float64VectorTests::ADDReduce, Float64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2225,7 +2248,7 @@ static void ADDReduceFloat64VectorTestsMasked(IntFunction fa, IntFuncti } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float64VectorTests::ADDReduceMasked, Float64VectorTests::ADDReduceAllMasked); + Float64VectorTests::ADDReduceMasked, Float64VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { @@ -2268,7 +2291,7 @@ static void MULReduceFloat64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float64VectorTests::MULReduce, Float64VectorTests::MULReduceAll); + Float64VectorTests::MULReduce, Float64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2314,7 +2337,7 @@ static void MULReduceFloat64VectorTestsMasked(IntFunction fa, IntFuncti } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float64VectorTests::MULReduceMasked, Float64VectorTests::MULReduceAllMasked); + Float64VectorTests::MULReduceMasked, Float64VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index 2030f620c62..5592f5985b0 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -65,6 +65,8 @@ static VectorShape getMaxBit() { private static final int Max = 256; // juts so we can do N/Max + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); @@ -124,15 +126,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -146,15 +154,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1094,6 +1109,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2184,7 +2207,7 @@ static void ADDReduceFloatMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - FloatMaxVectorTests::ADDReduce, FloatMaxVectorTests::ADDReduceAll); + FloatMaxVectorTests::ADDReduce, FloatMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2230,7 +2253,7 @@ static void ADDReduceFloatMaxVectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - FloatMaxVectorTests::ADDReduceMasked, FloatMaxVectorTests::ADDReduceAllMasked); + FloatMaxVectorTests::ADDReduceMasked, FloatMaxVectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { @@ -2273,7 +2296,7 @@ static void MULReduceFloatMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - FloatMaxVectorTests::MULReduce, FloatMaxVectorTests::MULReduceAll); + FloatMaxVectorTests::MULReduce, FloatMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2319,7 +2342,7 @@ static void MULReduceFloatMaxVectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - FloatMaxVectorTests::MULReduceMasked, FloatMaxVectorTests::MULReduceAllMasked); + FloatMaxVectorTests::MULReduceMasked, FloatMaxVectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template index 8af236eb0e3..3b306ce387a 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template @@ -3,5 +3,9 @@ static void [[TEST]]Reduce$vectorteststype$Masked(IntFunction<$type$[]> fa, IntFunction fm) { [[KERNEL]] assertReductionArraysEqualsMasked(r, ra, a, mask, +#if[FP] + $vectorteststype$::[[TEST]]ReduceMasked, $vectorteststype$::[[TEST]]ReduceAllMasked, RELATIVE_ROUNDING_ERROR); +#else[FP] $vectorteststype$::[[TEST]]ReduceMasked, $vectorteststype$::[[TEST]]ReduceAllMasked); +#end[FP] } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template index e6bcdb83c2e..5c689688708 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template @@ -3,5 +3,9 @@ static void [[TEST]]Reduce$vectorteststype$(IntFunction<$type$[]> fa) { [[KERNEL]] assertReductionArraysEquals(r, ra, a, +#if[FP] + $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll, RELATIVE_ROUNDING_ERROR); +#else[FP] $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll); +#end[FP] } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index a23ee5941a0..4d3795ea3d1 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -92,6 +92,10 @@ public class $vectorteststype$ extends AbstractVectorTest { #if[BITWISE] private static final $type$ CONST_SHIFT = $Boxtype$.SIZE / 2; #end[BITWISE] +#if[FP] + // for floating point reduction ops that may introduce rounding errors + private static final $type$ RELATIVE_ROUNDING_ERROR = ($type$)0.000001; +#end[FP] static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / $bits$); @@ -151,6 +155,9 @@ public class $vectorteststype$ extends AbstractVectorTest { static void assertReductionArraysEquals($type$[] r, $type$ rc, $type$[] a, FReductionOp f, FReductionAllOp fa) { +#if[FP] + assertReductionArraysEquals(r, rc, a, f, fa, ($type$)0.0); +#else[FP] int i = 0; try { Assert.assertEquals(rc, fa.apply(a)); @@ -161,7 +168,25 @@ public class $vectorteststype$ extends AbstractVectorTest { Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); } +#end[FP] + } +#if[FP] + + static void assertReductionArraysEquals($type$[] r, $type$ rc, $type$[] a, + FReductionOp f, FReductionAllOp fa, + $type$ relativeError) { + int i = 0; + try { + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + for (; i < a.length; i += SPECIES.length()) { + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + } + } catch (AssertionError e) { + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + } } +#end[FP] interface FReductionMaskedOp { $type$ apply($type$[] a, int idx, boolean[] mask); @@ -173,6 +198,9 @@ public class $vectorteststype$ extends AbstractVectorTest { static void assertReductionArraysEqualsMasked($type$[] r, $type$ rc, $type$[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { +#if[FP] + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, ($type$)0.0); +#else[FP] int i = 0; try { Assert.assertEquals(rc, fa.apply(a, mask)); @@ -183,7 +211,26 @@ public class $vectorteststype$ extends AbstractVectorTest { Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); } +#end[FP] + } +#if[FP] + + static void assertReductionArraysEqualsMasked($type$[] r, $type$ rc, $type$[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + $type$ relativeError) { + int i = 0; + try { + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); + for (; i < a.length; i += SPECIES.length()) { + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); + } + } catch (AssertionError e) { + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); + } } +#end[FP] #if[!Long] interface FReductionOpLong { @@ -1147,6 +1194,16 @@ public class $vectorteststype$ extends AbstractVectorTest { return fill(s * BUFFER_REPS, i -> ((($type$)(i + 1) == 0) ? 1 : ($type$)(i + 1))); }), +#if[FP] + withToString("$type$[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> ($type$)0.01 + (($type$)i / (i + 1))); + }), + withToString("$type$[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : ($type$)0.01 + (($type$)i / (i + 1))); + }), +#end[FP] withToString("$type$[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); diff --git a/test/jdk/jdk/internal/vm/Continuation/OSRTest.java b/test/jdk/jdk/internal/vm/Continuation/OSRTest.java new file mode 100644 index 00000000000..bf0bfeab674 --- /dev/null +++ b/test/jdk/jdk/internal/vm/Continuation/OSRTest.java @@ -0,0 +1,238 @@ +/* +* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +*/ + +/** +* @test +* @bug 8325469 +* @summary Test freeze/thaw with OSR frames +* @requires vm.continuations +* @requires vm.compMode != "Xint" & vm.compMode != "Xcomp" +* @modules java.base/jdk.internal.vm +* @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 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI OSRTest true true true +* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=inline,*::yield0 OSRTest true true false +* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=dontinline,*::yield* OSRTest true true false +* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=exclude,*::bar() OSRTest true false false +* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI OSRTest false true true +* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI OSRTest false true false +* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=exclude,*::bar() OSRTest false false false +* +*/ + +import jdk.internal.vm.Continuation; +import jdk.internal.vm.ContinuationScope; + +import java.lang.reflect.Method; +import jdk.test.whitebox.WhiteBox; + +public class OSRTest { + static final WhiteBox wb = WhiteBox.getWhiteBox(); + static final ContinuationScope FOO = new ContinuationScope() {}; + static final Method foo = getMethod("foo"); + static final Method fooBigFrame = getMethod("fooBigFrame"); + boolean osrAtBottom; + boolean freezeFast; + boolean thawFast; + int fooCallCount; + + public static void main(String[] args) { + if (args.length != 3) { + throw new Error("Error: args.length must be 3"); + } + boolean TEST_OSR_AT_BOTTOM = Boolean.parseBoolean(args[0]); + boolean FREEZE_FAST = Boolean.parseBoolean(args[1]); + boolean THAW_FAST = Boolean.parseBoolean(args[2]); + assert !THAW_FAST || FREEZE_FAST : "THAW_FAST requires FREEZE_FAST"; + + OSRTest test = new OSRTest(TEST_OSR_AT_BOTTOM, FREEZE_FAST, THAW_FAST); + test.runTest(); + } + + public OSRTest(boolean osrAtBottom, boolean freezeFast, boolean thawFast) { + this.osrAtBottom = osrAtBottom; + this.freezeFast = freezeFast; + this.thawFast = thawFast; + } + + public void runTest() { + Runnable testCase = osrAtBottom ? ()-> testOSRAtStackBottom() : ()-> TestOSRNotAtStackBottom(); + Continuation cont = new Continuation(FOO, testCase); + + while (!cont.isDone()) { + cont.run(); + if (freezeFast && !thawFast && fooCallCount == 2) { + // All frames frozen in last yield should be compiled + // including OSR version of foo. Invoke full GC now so + // that chunk is marked and we force thaw slow path. + System.gc(); + fooCallCount++; // Don't call again + } + } + } + + public void testOSRAtStackBottom() { + if (freezeFast) { + // Trigger compilation of Continuation.yield/yield0 + for (int i = 0; i < 10_000; i++) { + Continuation.yield(FOO); + } + } + for (int i = 0; i < 2; i++) { + if (freezeFast && !thawFast) { + foo(new Object(), new Object(), new Object(), new Object(), new Object(), + new Object(), new Object(), new Object(), new Object(), new Object(), + 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f); + } else { + fooBigFrame(new Object(), new Object(), new Object(), new Object(), new Object(), + new Object(), new Object(), new Object(), new Object(), new Object(), + 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f); + } + } + } + + // Declare many parameters and unused locals so that size of interpreter frame is bigger + // than size of OSR frame + size of Continuation.yield/yield0 frames. This is so that once + // foo is OSR, on yield we clear cont_fastpath() forcing the freeze fast path. + public void foo(Object o1, Object o2, Object o3, Object o4, Object o5, + Object o6, Object o7, Object o8, Object o9, Object o10, + float f1, float f2, float f3, float f4, float f5, float f6, float f7) { + int i1 = 1; + int i2 = i1 + 1; + int i3 = i2 + 1; + int i4 = i3 + 1; + int i5 = i4 + 1; + int i6 = i5 + 1; + int i7 = i6 + 1; + long ll = 2*(long)i1; + float ff = ll + 1.2f; + double dd = ff + 1.3D; + + if (osrAtBottom) { + // freeze all frames so that we only run with foo on the stack + Continuation.yield(FOO); + } + + // Provoke OSR compilation. After we verified the method was compiled keep looping + // until we trigger the _backedge_counter overflow to actually trigger OSR. + for (int i = 0; fooCallCount > 0 && (!wb.isMethodCompiled(foo, true) || i++ < 2_000);) { + } + fooCallCount++; + + if (freezeFast) { + Continuation.yield(FOO); + } else { + bar(); + } + } + + public void bar() { + Continuation.yield(FOO); + } + + public double fooBigFrame(Object o1, Object o2, Object o3, Object o4, Object o5, + Object o6, Object o7, Object o8, Object o9, Object o10, + float f1, float f2, float f3, float f4, float f5, float f6, float f7) { + double d1=1,d2=2,d3=3,d4=4,d5=5,d6=6,d7=7,d8=8,d9=9,d10=10,d11=11,d12=12,d13=13,d14=14,d15=15,d16=16,d17=17,d18=18,d19=19,d20=20,d21=21,d22=22,d23=23,d24=24,d25=25; + double d26=26,d27=27,d28=28,d29=29,d30=30,d31=31,d32=32,d33=33,d34=34,d35=35,d36=36,d37=37,d38=38,d39=39,d40=40,d41=41,d42=42,d43=43,d44=44,d45=45,d46=46,d47=47,d48=48,d49=49,d50=50; + double d51=51,d52=52,d53=53,d54=54,d55=55,d56=56,d57=57,d58=58,d59=59,d60=60,d61=61,d62=62,d63=63,d64=64,d65=65,d66=66,d67=67,d68=68,d69=69,d70=70,d71=71,d72=72,d73=73,d74=74,d75=75; + double d76=76,d77=77,d78=78,d79=79,d80=80,d81=81,d82=82,d83=83,d84=84,d85=85,d86=86,d87=87,d88=88,d89=89,d90=90,d91=91,d92=92,d93=93,d94=94,d95=95,d96=96,d97=97,d98=98,d99=99,d100=100; + double d101=101,d102=102,d103=103,d104=104,d105=105,d106=106,d107=107,d108=108,d109=109,d110=110,d111=111,d112=112,d113=113,d114=114,d115=115,d116=116,d117=117,d118=118,d119=119,d120=120,d121=121,d122=122,d123=123,d124=124,d125=125; + double d126=126,d127=127,d128=128,d129=129,d130=130,d131=131,d132=132,d133=133,d134=134,d135=135,d136=136,d137=137,d138=138,d139=139,d140=140,d141=141,d142=142,d143=143,d144=144,d145=145,d146=146,d147=147,d148=148,d149=149,d150=150; + double d151=151,d152=152,d153=153,d154=154,d155=155,d156=156,d157=157,d158=158,d159=159,d160=160,d161=161,d162=162,d163=163,d164=164,d165=165,d166=166,d167=167,d168=168,d169=169,d170=170,d171=171,d172=172,d173=173,d174=174,d175=175; + double d176=176,d177=177,d178=178,d179=179,d180=180,d181=181,d182=182,d183=183,d184=184,d185=185,d186=186,d187=187,d188=188,d189=189,d190=190,d191=191,d192=192,d193=193,d194=194,d195=195,d196=196,d197=197,d198=198,d199=199,d200=200; + double d201=201,d202=202,d203=203,d204=204,d205=205,d206=206,d207=207,d208=208,d209=209,d210=210,d211=211,d212=212,d213=213,d214=214,d215=215,d216=216,d217=217,d218=218,d219=219,d220=220,d221=221,d222=222,d223=223,d224=224,d225=225; + double d226=226,d227=227,d228=228,d229=229,d230=230,d231=231,d232=232,d233=233,d234=234,d235=235,d236=236,d237=237,d238=238,d239=239,d240=240,d241=241,d242=242,d243=243,d244=244,d245=245,d246=246,d247=247,d248=248,d249=249,d250=250; + double d251=251,d252=252,d253=253,d254=254,d255=255,d256=256,d257=257,d258=258,d259=259,d260=260,d261=261,d262=262,d263=263,d264=264,d265=265,d266=266,d267=267,d268=268,d269=269,d270=270,d271=271,d272=272,d273=273,d274=274,d275=275; + double d276=276,d277=277,d278=278,d279=279,d280=280,d281=281,d282=282,d283=283,d284=284,d285=285,d286=286,d287=287,d288=288,d289=289,d290=290,d291=291,d292=292,d293=293,d294=294,d295=295,d296=296,d297=297,d298=298,d299=299,d300=300; + + // freeze all frames so that we only run with fooBigFrame on the stack + Continuation.yield(FOO); + + // Provoke OSR compilation. After we verified the method was compiled keep looping + // until we trigger the _backedge_counter overflow to actually trigger OSR. + for (int i = 0; fooCallCount > 0 && (!wb.isMethodCompiled(fooBigFrame, true) || i++ < 2_000);) { + } + fooCallCount++; + + Continuation.yield(FOO); + + // For the thaw fast case we want to trigger the case of thawing one + // frame at a time. Because the OSR frame is at the bottom we have to + // make its size > 500 words, so we use a lot of locals. We also want + // the interpreted frame size be bigger than OSR frame + size of + // Continuation.yield/yield0, so that we clear cont_fastpath() on yield + // forcing the freeze fast path (same as with foo). For that, we just + // declare more locals than the ones we use after OSR happens. + // For the freeze slow case we also want the interpreted frame size to + // be bigger than OSR frame + size of Continuation.yield/yield0, so the + // last technique serves for this case too. + double res = d1*d2*d3*d4*d5*d6*d7*d8*d9*d10*d11*d12*d13*d14*d15*d16*d17*d18*d19*d20*d21*d22*d23*d24*d25*d26*d27*d28*d29*d30*d31*d32*d33*d34*d35*d36*d37*d38*d39*d40*d41*d42*d43*d44*d45*d46*d47*d48*d49*d50* + d51*d52*d53*d54*d55*d56*d57*d58*d59*d60*d61*d62*d63*d64*d65*d66*d67*d68*d69*d70*d71*d72*d73*d74*d75*d76*d77*d78*d79*d80*d81*d82*d83*d84*d85*d86*d87*d88*d89*d90*d91*d92*d93*d94*d95*d96*d97*d98*d99*d100* + d101*d102*d103*d104*d105*d106*d107*d108*d109*d110*d111*d112*d113*d114*d115*d116*d117*d118*d119*d120*d121*d122*d123*d124*d125*d126*d127*d128*d129*d130*d131*d132*d133*d134*d135*d136*d137*d138*d139*d140* + d141*d142*d143*d144*d145*d146*d147*d148*d149*d150*d151*d152*d153*d154*d155*d156*d157*d158*d159*d160*d161*d162*d163*d164*d165*d166*d167*d168*d169*d170*d171*d172*d173*d174*d175*d176*d177*d178*d179*d180* + d181*d182*d183*d184*d185*d186*d187*d188*d189*d190*d191*d192*d193*d194*d195*d196*d197*d198*d199*d200*d201*d202*d203*d204*d205*d206*d207*d208*d209*d210*d211*d212*d213*d214*d215*d216*d217*d218*d219*d220* + d221*d222*d223*d224*d225*d226*d227*d228*d229*d230*d231*d232*d233*d234*d235*d236*d237*d238*d239*d240*d241*d242*d243*d244*d245*d246*d247*d248*d249*d250*d251*d252*d253*d254*d255*d256*d257*d258*d259*d260* + d261*d262*d263*d264*d265*d266*d267*d268*d269*d270*d271*d272*d273*d274*d275; + return res; + } + + public void TestOSRNotAtStackBottom() { + // freeze all frames currently in the stack + boolean res = Continuation.yield(FOO); + + for (int i = 1; i < 100000; i++) { + // When testing the thaw fast path make recursion big enough so that + // the size of all frames at freeze time is more than 500 words. This + // way we later force thawing one frame at a time. + recurse(thawFast ? 60 : 5, i); + } + } + + public void recurse(int depth, int iteration) { + if (depth > 0) { + recurse(depth - 1, iteration); + } else { + // Make compiler see this branch but not enough times to avoid foo + // getting compiled, since we want the OSR version. + if (iteration % 45000 == 0) { + foo(new Object(), new Object(), new Object(), new Object(), new Object(), + new Object(), new Object(), new Object(), new Object(), new Object(), + 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f); + } else { + Continuation.yield(FOO); + } + } + } + + static Method getMethod(String method) { + try { + return OSRTest.class.getMethod(method, Object.class, Object.class, Object.class, Object.class, Object.class, Object.class, Object.class, Object.class, + Object.class, Object.class, Float.TYPE, Float.TYPE, Float.TYPE, Float.TYPE, Float.TYPE, Float.TYPE, Float.TYPE); + } catch (Exception e) { + throw new RuntimeException("Exception: couldn't found method " + method + ". " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/test/jdk/jdk/jfr/api/consumer/TestRecordedClass.java b/test/jdk/jdk/jfr/api/consumer/TestRecordedClass.java new file mode 100644 index 00000000000..19c63704919 --- /dev/null +++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedClass.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.api.consumer; + +import java.lang.reflect.Modifier; +import java.util.List; + +import jdk.jfr.Event; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedClass; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Verifies methods of RecordedClass + * @key jfr + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.api.consumer.TestRecordedClass + */ +public class TestRecordedClass { + + static class TestEvent extends Event { + Class typeA; + Class typeB; + } + + private static class TypeA { + } + + public final static class TypeB { + } + + public static void main(String[] args) throws Exception { + try (Recording recording = new Recording()) { + recording.start(); + TestEvent event = new TestEvent(); + event.typeA = TypeA.class; + event.typeB = TypeB.class; + event.commit(); + recording.stop(); + + List events = Events.fromRecording(recording); + Events.hasEvents(events); + for (RecordedEvent recordedEvent : events) { + RecordedClass typeA = recordedEvent.getClass("typeA"); + RecordedClass typeB = recordedEvent.getClass("typeB"); + assertModifiers(typeA, TypeA.class); + assertModifiers(typeB, TypeB.class); + assertName(typeA, TypeA.class); + assertName(typeB, TypeB.class); + assertClassLoader(typeA, TypeA.class.getClassLoader()); + assertClassLoader(typeB, TypeB.class.getClassLoader()); + assertId(typeA); + assertId(typeB); + if (typeA.getId() == typeB.getId()) { + throw new Exception("Same ID for different classes"); + } + } + } + } + + private static void assertId(RecordedClass recordedClass) throws Exception { + long id = recordedClass.getId(); + if (id < 1 || id >= 1024 * 1024) { + throw new Exception("Expected class ID to be above 1 and below 1 M"); + } + } + + private static void assertClassLoader(RecordedClass recordedClass, ClassLoader classLoader) throws Exception { + String expected = classLoader.getClass().getName(); + String actual = recordedClass.getClassLoader().getType().getName(); + if (!expected.equals(actual)) { + throw new Exception("Expected class loader to be " + expected + ", was " + actual); + } + } + + private static void assertName(RecordedClass recordedClass, Class clazz) throws Exception { + String className = clazz.getClass().getName(); + if (className.equals(recordedClass.getName())) { + throw new Exception("Expected class to be named " + className); + } + } + + private static void assertModifiers(RecordedClass recordedClass, Class clazz) throws Exception { + int modifiers = clazz.getModifiers(); + if (modifiers != recordedClass.getModifiers()) { + String expected = Modifier.toString(modifiers); + String actual = Modifier.toString(recordedClass.getModifiers()); + throw new Exception("Expected modifier to be '" + expected + "', was '" + actual + "'"); + } + } +} diff --git a/test/jdk/jdk/jfr/api/consumer/filestream/TestOrdered.java b/test/jdk/jdk/jfr/api/consumer/filestream/TestOrdered.java index 94383298ddc..58f23350dd0 100644 --- a/test/jdk/jdk/jfr/api/consumer/filestream/TestOrdered.java +++ b/test/jdk/jdk/jfr/api/consumer/filestream/TestOrdered.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import jdk.jfr.Event; @@ -88,69 +89,98 @@ public static void main(String... args) throws Exception { private static void testSetOrderedTrue(Path p) throws Exception { for (boolean reuse : BOOLEAN_STATES) { + System.out.println(); + System.out.println("Testing: testSetOrderedTrue reuse = " + reuse); AtomicReference timestamp = new AtomicReference<>(Instant.MIN); + AtomicBoolean unordered = new AtomicBoolean(false); try (EventStream es = EventStream.openFile(p)) { es.setReuse(reuse); es.setOrdered(true); es.onEvent(e -> { Instant endTime = e.getEndTime(); + printTimestamp(endTime); if (endTime.isBefore(timestamp.get())) { - throw new Error("Events are not ordered! Reuse = " + reuse); + unordered.set(true); } timestamp.set(endTime); }); es.start(); } + if (unordered.get()) { + throw new Exception("Events are not ordered! Reuse = " + reuse); + } } } private static void testSetOrderedFalse(Path p) throws Exception { for (boolean reuse : BOOLEAN_STATES) { + System.out.println(); + System.out.println("Testing: testSetOrderedFalse reuse = " + reuse); AtomicReference timestamp = new AtomicReference<>(Instant.MIN); - AtomicBoolean unoreded = new AtomicBoolean(false); + AtomicBoolean unordered = new AtomicBoolean(false); try (EventStream es = EventStream.openFile(p)) { es.setReuse(reuse); es.setOrdered(false); es.onEvent(e -> { Instant endTime = e.getEndTime(); - System.out.println("testSetOrderedFalse: endTime: " + endTime); + printTimestamp(endTime); if (endTime.isBefore(timestamp.get())) { - unoreded.set(true); - es.close(); + unordered.set(true); } timestamp.set(endTime); }); es.start(); - if (!unoreded.get()) { + if (!unordered.get()) { throw new Exception("Expected at least some events to be out of order! Reuse = " + reuse); } } } } + private static void printTimestamp(Instant timestamp) { + long seconds = timestamp.getEpochSecond(); + long nanos = timestamp.getNano(); + System.out.println(timestamp + " seconds = " + seconds + " nanos = " + nanos); + } + private static Path makeUnorderedRecording() throws Exception { - CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); - - try (Recording r = new Recording()) { - r.start(); - List emitters = new ArrayList<>(); - for (int i = 0; i < THREAD_COUNT; i++) { - Emitter e = new Emitter(barrier); - e.start(); - emitters.add(e); - } - // Thread buffers should now have one event each - barrier.await(); - // Add another event to each thread buffer, so - // events are bound to come out of order when they - // are flushed - for (Emitter e : emitters) { - e.join(); + while (true) { + CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); + try (Recording r = new Recording()) { + r.start(); + List emitters = new ArrayList<>(); + for (int i = 0; i < THREAD_COUNT; i++) { + Emitter e = new Emitter(barrier); + e.start(); + emitters.add(e); + } + // Thread buffers should now have one event each + barrier.await(); + // Add another event to each thread buffer, so + // events are bound to come out of order when they + // are flushed + for (Emitter e : emitters) { + e.join(); + } + r.stop(); + Path p = Utils.createTempFile("recording", ".jfr"); + r.dump(p); + // Order is only guaranteed within a segment. + int segments = countSegments(p); + if (segments < 2) { + return p; + } + System.out.println("File contains more than one segment (" + segments + "). Retrying."); } - r.stop(); - Path p = Utils.createTempFile("recording", ".jfr"); - r.dump(p); - return p; + } + } + + private static int countSegments(Path file) throws Exception { + AtomicInteger segments = new AtomicInteger(); + try (EventStream es = EventStream.openFile(file)) { + es.onFlush(segments::incrementAndGet); + es.start(); + return segments.get(); } } } diff --git a/test/jdk/jdk/jfr/event/oldobject/TestListenerLeak.java b/test/jdk/jdk/jfr/event/oldobject/TestListenerLeak.java index 67ef11b2740..92610283525 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestListenerLeak.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestListenerLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * 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,15 +71,17 @@ public void onListen() { public static void main(String[] args) throws Exception { WhiteBox.setWriteAllObjectSamples(true); - - try (Recording r = new Recording()) { - r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity"); - r.start(); - listenerLeak(); - r.stop(); - List events = Events.fromRecording(r); - if (OldObjects.countMatchingEvents(events, Stuff[].class, null, null, -1, "listenerLeak") == 0) { - throw new Exception("Could not find leak with " + Stuff[].class); + while (true) { + try (Recording r = new Recording()) { + r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity"); + r.start(); + listenerLeak(); + r.stop(); + List events = Events.fromRecording(r); + if (OldObjects.countMatchingEvents(events, Stuff[].class, null, null, -1, "listenerLeak") != 0) { + return; // Success + } + System.out.println("Could not find leak with " + Stuff[].class + ". Retrying."); } } } diff --git a/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java b/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java index d3d8377183d..7480acb1d1d 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ * @requires vm.hasJFR * @library /test/lib /test/jdk * @summary Purpose of this test is to run leak profiler without command line tweaks or WhiteBox hacks until we succeed - * @run main/othervm jdk.jfr.event.oldobject.TestSanityDefault + * @run main/othervm -Xmx1G jdk.jfr.event.oldobject.TestSanityDefault */ public class TestSanityDefault { diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java index 889926077a9..307ee9b212b 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java @@ -533,6 +533,28 @@ * @run main/othervm/manual -Djava.security.debug=certpath CAInterop globalsigne46 CRL */ +/* + * @test id=ssltlsrootecc2022 + * @bug 8341057 + * @summary Interoperability tests with SSL TLS 2022 root CAs + * @library /test/lib + * @build jtreg.SkippedException ValidatePathWithURL CAInterop + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop ssltlsrootecc2022 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop ssltlsrootecc2022 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop ssltlsrootecc2022 CRL + */ + +/* + * @test id=ssltlsrootrsa2022 + * @bug 8341057 + * @summary Interoperability tests with SSL TLS 2022 root CAs + * @library /test/lib + * @build jtreg.SkippedException ValidatePathWithURL CAInterop + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop ssltlsrootrsa2022 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop ssltlsrootrsa2022 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop ssltlsrootrsa2022 CRL + */ + /** * Collection of certificate validation tests for interoperability with external CAs. * These tests are marked as manual as they depend on external infrastructure and may fail @@ -711,6 +733,13 @@ private CATestURLs getTestURLs(String alias) { new CATestURLs("https://valid.e46.roots.globalsign.com", "https://revoked.e46.roots.globalsign.com"); + case "ssltlsrootecc2022" -> + new CATestURLs("https://test-root-2022-ecc.ssl.com", + "https://revoked-root-2022-ecc.ssl.com"); + case "ssltlsrootrsa2022" -> + new CATestURLs("https://test-root-2022-rsa.ssl.com", + "https://revoked-root-2022-rsa.ssl.com"); + default -> throw new RuntimeException("No test setup found for: " + alias); }; } diff --git a/test/jdk/sun/java2d/marlin/ScaleTest.java b/test/jdk/sun/java2d/marlin/ScaleTest.java index bfd56422ba4..c9778a6477a 100644 --- a/test/jdk/sun/java2d/marlin/ScaleTest.java +++ b/test/jdk/sun/java2d/marlin/ScaleTest.java @@ -21,13 +21,17 @@ * questions. */ +/* @test + * @summary Circle is rendered in C shape + * @bug 6829659 8311666 + */ + import java.awt.*; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; - public class ScaleTest { public static void main(String[] args) throws Exception { BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB); diff --git a/test/jdk/sun/java2d/marlin/StrokeShapeTest.java b/test/jdk/sun/java2d/marlin/StrokeShapeTest.java index 41413bff3e4..bc23f29e15d 100644 --- a/test/jdk/sun/java2d/marlin/StrokeShapeTest.java +++ b/test/jdk/sun/java2d/marlin/StrokeShapeTest.java @@ -20,6 +20,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/* @test + * @summary StrokeShapeTest: createStrokedShape() behaves differently + * @bug 6829678 8311666 + */ + import java.awt.*; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; diff --git a/test/jdk/sun/java2d/marlin/ThinLineTest.java b/test/jdk/sun/java2d/marlin/ThinLineTest.java index a1a033c0bd4..7450f4e421d 100644 --- a/test/jdk/sun/java2d/marlin/ThinLineTest.java +++ b/test/jdk/sun/java2d/marlin/ThinLineTest.java @@ -20,6 +20,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/* @test + * @summary ThinLineTest: A line < 1 pixel disappears. + * @bug 6829673 8311666 + */ + import java.awt.*; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; diff --git a/test/jdk/sun/management/jmxremote/bootstrap/RmiRegistrySslTest.java b/test/jdk/sun/management/jmxremote/bootstrap/RmiRegistrySslTest.java index 40bb525d1b0..6cc5708b385 100644 --- a/test/jdk/sun/management/jmxremote/bootstrap/RmiRegistrySslTest.java +++ b/test/jdk/sun/management/jmxremote/bootstrap/RmiRegistrySslTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -195,7 +195,7 @@ private int doTest(String... args) throws Exception { System.out.println("test output:"); System.out.println(output.getOutput()); - if (!output.getOutput().contains("Exception thrown by the agent : " + + if (!output.getOutput().contains("Exception thrown by the agent: " + "java.rmi.server.ExportException: Port already in use")) { return output.getExitValue(); } diff --git a/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java b/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java index 2d275ebfc9e..b9b9de57cdf 100644 --- a/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java +++ b/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,9 @@ /* * @test * @bug 5045306 6356004 6993490 8255124 + * @summary Http keep-alive implementation is not efficient * @library /test/lib * @run main/othervm B5045306 - * @summary Http keep-alive implementation is not efficient */ import java.io.IOException; @@ -42,14 +42,17 @@ import java.net.URL; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; +import jdk.test.lib.net.URIBuilder; + /* Part 1: - * The http client makes a connection to a URL whos content contains a lot of + * The http client makes a connection to a URL whose content contains a lot of * data, more than can fit in the socket buffer. The client only reads * 1 byte of the data from the InputStream leaving behind more data than can * fit in the socket buffer. The client then makes a second call to the http @@ -63,150 +66,166 @@ public class B5045306 { static HttpServer server; - - public static void main(String[] args) { - startHttpServer(); - clientHttpCalls(); - } + static ExecutorService executor = Executors.newSingleThreadExecutor(); public static void startHttpServer() { try { - server = HttpServer.create(new InetSocketAddress(InetAddress.getLocalHost(), 0), 10, "/", new SimpleHttpTransactionHandler()); - server.setExecutor(Executors.newSingleThreadExecutor()); - server.start(); + server = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 10, "/", new SimpleHttpTransactionHandler()); } catch (IOException e) { - e.printStackTrace(); + throw new RuntimeException(e); } + server.setExecutor(executor); + server.start(); + System.out.println("http server listens on: " + server.getAddress()); } - public static void clientHttpCalls() { + public static void stopHttpServer() { + server.stop(1); + executor.shutdown(); + } + + public static void clientHttpCalls() throws Exception { List uncaught = new ArrayList<>(); Thread.setDefaultUncaughtExceptionHandler((t, ex) -> { uncaught.add(ex); }); - try { - System.out.println("http server listen on: " + server.getAddress().getPort()); - String hostAddr = InetAddress.getLocalHost().getHostAddress(); - if (hostAddr.indexOf(':') > -1) hostAddr = "[" + hostAddr + "]"; - String baseURLStr = "http://" + hostAddr + ":" + server.getAddress().getPort() + "/"; - URL bigDataURL = new URL (baseURLStr + "firstCall"); - URL smallDataURL = new URL (baseURLStr + "secondCall"); + URL bigDataURL = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(server.getAddress().getPort()) + .path("/firstCall") + .toURL(); + + URL smallDataURL = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(server.getAddress().getPort()) + .path("/secondCall") + .toURL(); - HttpURLConnection uc = (HttpURLConnection)bigDataURL.openConnection(Proxy.NO_PROXY); + HttpURLConnection uc = (HttpURLConnection)bigDataURL.openConnection(Proxy.NO_PROXY); - //Only read 1 byte of response data and close the stream - InputStream is = uc.getInputStream(); + // Only read 1 byte of response data and close the stream + try (InputStream is = uc.getInputStream()) { byte[] ba = new byte[1]; is.read(ba); - is.close(); - - // Allow the KeepAliveStreamCleaner thread to read the data left behind and cache the connection. - try { Thread.sleep(2000); } catch (Exception e) {} - - uc = (HttpURLConnection)smallDataURL.openConnection(Proxy.NO_PROXY); - uc.getResponseCode(); - - if (SimpleHttpTransactionHandler.failed) - throw new RuntimeException("Failed: Initial Keep Alive Connection is not being reused"); - - // Part 2 - URL part2Url = new URL (baseURLStr + "part2"); - uc = (HttpURLConnection)part2Url.openConnection(Proxy.NO_PROXY); - is = uc.getInputStream(); - is.close(); - - // Allow the KeepAliveStreamCleaner thread to try and read the data left behind and cache the connection. - try { Thread.sleep(2000); } catch (Exception e) {} - - ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); - if (threadMXBean.isThreadCpuTimeSupported()) { - long[] threads = threadMXBean.getAllThreadIds(); - ThreadInfo[] threadInfo = threadMXBean.getThreadInfo(threads); - for (int i=0; i= 1000000000) // 1 second, or 1 billion nanoseconds - throw new RuntimeException("Failed: possible recursive loop in Keep-Alive-SocketCleaner"); - } + } + + // Allow the KeepAliveStreamCleaner thread to read the data left behind and cache the connection. + try { Thread.sleep(2000); } catch (Exception e) {} + + uc = (HttpURLConnection)smallDataURL.openConnection(Proxy.NO_PROXY); + uc.getResponseCode(); + + if (SimpleHttpTransactionHandler.failed) + throw new RuntimeException("Failed: Initial Keep Alive Connection is not being reused"); + + // Part 2 + URL part2Url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(server.getAddress().getPort()) + .path("/part2") + .toURL(); + + uc = (HttpURLConnection)part2Url.openConnection(Proxy.NO_PROXY); + try (InputStream is = uc.getInputStream()) {} + + // Allow the KeepAliveStreamCleaner thread to try and read the data left behind and cache the connection. + try { Thread.sleep(2000); } catch (Exception e) {} + + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + if (threadMXBean.isThreadCpuTimeSupported()) { + long[] threads = threadMXBean.getAllThreadIds(); + ThreadInfo[] threadInfo = threadMXBean.getThreadInfo(threads); + for (int i = 0; i < threadInfo.length; i++) { + if (threadInfo[i].getThreadName().equals("Keep-Alive-SocketCleaner")) { + System.out.println("Found Keep-Alive-SocketCleaner thread"); + long threadID = threadInfo[i].getThreadId(); + long before = threadMXBean.getThreadCpuTime(threadID); + try { Thread.sleep(2000); } catch (Exception e) {} + long after = threadMXBean.getThreadCpuTime(threadID); + + if (before ==-1 || after == -1) + break; // thread has died, OK + + // if Keep-Alive-SocketCleaner consumes more than 50% of cpu then we + // can assume a recursive loop. + long total = after - before; + if (total >= 1000000000) // 1 second, or 1 billion nanoseconds + throw new RuntimeException("Failed: possible recursive loop in Keep-Alive-SocketCleaner"); } } - - } catch (IOException e) { - e.printStackTrace(); - } finally { - server.stop(1); } if (!uncaught.isEmpty()) { throw new RuntimeException("Unhandled exception:", uncaught.get(0)); } } -} -class SimpleHttpTransactionHandler implements HttpHandler -{ - static volatile boolean failed = false; + static class SimpleHttpTransactionHandler implements HttpHandler { + static volatile boolean failed = false; - // Need to have enough data here that is too large for the socket buffer to hold. - // Also http.KeepAlive.remainingData must be greater than this value, default is 256K. - static final int RESPONSE_DATA_LENGTH = 128 * 1024; + // Need to have enough data here that is too large for the socket buffer to hold. + // Also http.KeepAlive.remainingData must be greater than this value, default is 256K. + static final int RESPONSE_DATA_LENGTH = 128 * 1024; - int port1; + int port1; - public void handle(HttpExchange trans) { - try { - String path = trans.getRequestURI().getPath(); - if (path.equals("/firstCall")) { - port1 = trans.getRemoteAddress().getPort(); - System.out.println("First connection on client port = " + port1); - - byte[] responseBody = new byte[RESPONSE_DATA_LENGTH]; - for (int i=0; i passed = new CompletableFuture<>(); - static class Server extends Thread { - final ServerSocket serverSocket; - final int port; + static class Server extends Thread implements AutoCloseable { final String param; // the parameter to test "max" or "timeout" + final ServerSocket serverSocket = new ServerSocket(0); + final int port; volatile Socket s; public Server(String param) throws IOException { - serverSocket = new ServerSocket(0); + this.param = param; port = serverSocket.getLocalPort(); setDaemon(true); - this.param = param; } public int getPort() { return port; } - public void close() { - try { - serverSocket.close(); - if (s != null) - s.close(); - } catch (IOException e) {} + public void close() throws IOException { + serverSocket.close(); + if (s != null) + s.close(); } static final byte[] requestEnd = new byte[] {'\r', '\n', '\r', '\n' }; @@ -125,28 +127,29 @@ public void run() { } } - public static void main(String[] args) throws Exception { - Server server = new Server(args[0]); - int port = server.getPort(); - server.start(); - URL url = new URL("http://127.0.0.1:" + Integer.toString(port) + "/"); - HttpURLConnection urlc = (HttpURLConnection) url.openConnection(); - InputStream i = urlc.getInputStream(); - int c,count=0; - byte[] buf = new byte[256]; - while ((c=i.read(buf)) != -1) { - count+=c; - } - i.close(); - System.out.println("Read " + count ); - try { + public static void runTest(String param) throws Exception { + try (Server server = new Server(param)) { + server.start(); + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(server.getPort()) + .path("/") + .toURL(); + HttpURLConnection urlc = (HttpURLConnection) url.openConnection(); + try (InputStream i = urlc.getInputStream()) { + System.out.println("Read " + i.readAllBytes().length); + } if (!passed.get()) { throw new RuntimeException("Test failed"); } else { System.out.println("Test passed"); } - } finally { - server.close(); } } + + public static void main(String[] args) throws Exception { + runTest("timeout"); + runTest("max"); + } } diff --git a/test/jdk/sun/net/www/http/KeepAliveCache/B8293562.java b/test/jdk/sun/net/www/http/KeepAliveCache/B8293562.java index 2e6dbb84e2d..e17d0586256 100644 --- a/test/jdk/sun/net/www/http/KeepAliveCache/B8293562.java +++ b/test/jdk/sun/net/www/http/KeepAliveCache/B8293562.java @@ -24,20 +24,11 @@ /* * @test * @bug 8293562 + * @summary Http keep-alive thread should close sockets without holding a lock * @library /test/lib * @run main/othervm -Dhttp.keepAlive.time.server=1 B8293562 - * @summary Http keep-alive thread should close sockets without holding a lock */ -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; - -import javax.net.ssl.HandshakeCompletedListener; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -53,6 +44,18 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; + +import jdk.test.lib.net.URIBuilder; + public class B8293562 { static HttpServer server; static CountDownLatch closing = new CountDownLatch(1); @@ -73,12 +76,13 @@ public static void startHttpServer() throws Exception { public static void clientHttpCalls() throws Exception { try { - System.out.println("http server listen on: " + server.getAddress().getPort()); - String hostAddr = InetAddress.getLoopbackAddress().getHostAddress(); - if (hostAddr.indexOf(':') > -1) hostAddr = "[" + hostAddr + "]"; - String baseURLStr = "https://" + hostAddr + ":" + server.getAddress().getPort() + "/"; + System.out.println("http server listens on: " + server.getAddress().getPort()); - URL testUrl = new URL (baseURLStr); + URL testUrl = URIBuilder.newBuilder() + .scheme("https") + .loopback() + .port(server.getAddress().getPort()) + .toURL(); // SlowCloseSocketFactory is not a real SSLSocketFactory; // it produces regular non-SSL sockets. Effectively, the request diff --git a/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveProperty.java b/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveProperty.java index 83491ad4e38..0e065b1224c 100644 --- a/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveProperty.java +++ b/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,18 +23,29 @@ /* * @test - * @library /test/lib * @bug 8278067 + * @library /test/lib * @run main/othervm -Dhttp.keepAlive.time.server=30 KeepAliveProperty long * @run main/othervm -Dhttp.keepAlive.time.server=1 KeepAliveProperty short * @run main/othervm -ea -Dhttp.keepAlive.time.server=0 KeepAliveProperty short */ -import java.net.*; -import java.io.*; -import java.nio.charset.*; -import java.util.logging.*; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; + import jdk.test.lib.net.URIBuilder; + import static java.net.Proxy.NO_PROXY; public class KeepAliveProperty { diff --git a/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveTimerThread.java b/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveTimerThread.java index 5568f0c54a9..44130b2a820 100644 --- a/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveTimerThread.java +++ b/test/jdk/sun/net/www/http/KeepAliveCache/KeepAliveTimerThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,16 +23,26 @@ /* * @test - * @library /test/lib * @bug 4701299 * @summary Keep-Alive-Timer thread management in KeepAliveCache causes memory leak + * @library /test/lib * @run main KeepAliveTimerThread * @run main/othervm -Djava.net.preferIPv6Addresses=true KeepAliveTimerThread */ -import java.net.*; -import java.io.*; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.net.URL; + import jdk.test.lib.net.URIBuilder; + import static java.net.Proxy.NO_PROXY; public class KeepAliveTimerThread { @@ -131,8 +141,5 @@ public static void main(String args[]) throws Exception { if (grp.activeCount() > 0) { throw new RuntimeException("Keep-alive thread started in wrong thread group"); } - - grp.destroy(); } - } diff --git a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java index 83427f1a33a..d64c5d7c52b 100644 --- a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java +++ b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java @@ -19,17 +19,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. - * */ -/** +/* * @test * @bug 8189131 8198240 8191844 8189949 8191031 8196141 8204923 8195774 8199779 * 8209452 8209506 8210432 8195793 8216577 8222089 8222133 8222137 8222136 * 8223499 8225392 8232019 8234245 8233223 8225068 8225069 8243321 8243320 * 8243559 8225072 8258630 8259312 8256421 8225081 8225082 8225083 8245654 * 8305975 8304760 8307134 8295894 8314960 8317373 8317374 8318759 8319187 - * 8321408 8316138 + * 8321408 8316138 8341057 * @summary Check root CA entries in cacerts file */ import java.io.ByteArrayInputStream; @@ -48,12 +47,12 @@ public class VerifyCACerts { + File.separator + "security" + File.separator + "cacerts"; // The numbers of certs now. - private static final int COUNT = 110; + private static final int COUNT = 112; // SHA-256 of cacerts, can be generated with // shasum -a 256 cacerts | sed -e 's/../&:/g' | tr '[:lower:]' '[:upper:]' | cut -c1-95 private static final String CHECKSUM - = "BD:80:65:81:68:E5:6C:51:64:ED:B9:08:53:9F:BB:2F:D9:6C:5D:D4:06:D4:16:59:39:10:8E:F8:24:81:8B:78"; + = "21:68:E7:16:5B:94:23:D2:60:5C:BB:F2:AF:C1:66:5C:EC:36:BC:20:FF:5C:54:AF:91:D1:2C:38:AE:55:D3:27"; // Hex formatter to upper case with ":" delimiter private static final HexFormat HEX = HexFormat.ofDelimiter(":").withUpperCase(); @@ -282,6 +281,10 @@ public class VerifyCACerts { "4F:A3:12:6D:8D:3A:11:D1:C4:85:5A:4F:80:7C:BA:D6:CF:91:9D:3A:5A:88:B0:3B:EA:2C:63:72:D9:3C:40:C9"); put("globalsigne46 [jdk]", "CB:B9:C4:4D:84:B8:04:3E:10:50:EA:31:A6:9F:51:49:55:D7:BF:D2:E2:C6:B4:93:01:01:9A:D6:1D:9F:50:58"); + put("ssltlsrootecc2022 [jdk]", + "C3:2F:FD:9F:46:F9:36:D1:6C:36:73:99:09:59:43:4B:9A:D6:0A:AF:BB:9E:7C:F3:36:54:F1:44:CC:1B:A1:43"); + put("ssltlsrootrsa2022 [jdk]", + "8F:AF:7D:2E:2C:B4:70:9B:B8:E0:B3:36:66:BF:75:A5:DD:45:B5:DE:48:0F:8E:A8:D4:BF:E6:BE:BC:17:F2:ED"); } }; diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java index 4778cc217ba..ea7f4895785 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ * @library /test/lib /javax/net/ssl/templates * @summary Test that a New Session Ticket will be generated when a * SSLSessionBindingListener is set (boundValues) - * @key intermittent * @run main/othervm ResumptionUpdateBoundValues */ @@ -238,7 +237,7 @@ private void run() throws Exception { Thread t; while ((t = threads.take()) != Thread.currentThread()) { System.out.printf(" joining: %s%n", t); - t.join(1000L); + t.join(4000L); } serverReady = false; System.gc(); diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java b/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java index abad01099bc..f7e677bbbd0 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,9 +34,12 @@ */ import java.net.ServerSocket; +import java.net.BindException; public class ReuseAddr extends SSLSocketTemplate { + private static final int MAX_ATTEMPTS = 3; + @Override protected void doServerSide() throws Exception { super.doServerSide(); @@ -50,6 +53,21 @@ protected void doServerSide() throws Exception { } public static void main(String[] args) throws Exception { - new ReuseAddr().run(); + for (int i=1 ; i <= MAX_ATTEMPTS; i++) { + try { + new ReuseAddr().run(); + System.out.println("Test succeeded at attempt " + i); + break; + } catch (BindException x) { + System.out.println("attempt " + i + " failed: " + x); + if (i == MAX_ATTEMPTS) { + String msg = "Could not succeed after " + i + " attempts"; + System.err.println(msg); + throw new AssertionError("Failed to reuse address: " + msg, x); + } else { + System.out.println("Retrying..."); + } + } + } } } diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/Distrust.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/Distrust.java new file mode 100644 index 00000000000..1c1fcee3609 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/Distrust.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.*; +import java.math.BigInteger; +import java.security.*; +import java.security.cert.*; +import java.time.*; +import java.util.*; +import javax.net.ssl.*; +import sun.security.validator.Validator; +import sun.security.validator.ValidatorException; + +import jdk.test.lib.security.SecurityUtils; + +/** + * @test + * @bug 8337664 8341059 + * @summary Check that TLS Server certificates chaining back to distrusted + * Entrust roots are invalid + * @library /test/lib + * @modules java.base/sun.security.validator + * @run main/othervm Distrust after policyOn invalid + * @run main/othervm Distrust after policyOff valid + * @run main/othervm Distrust before policyOn valid + * @run main/othervm Distrust before policyOff valid + */ + +public class Distrust { + + private static final String TEST_SRC = System.getProperty("test.src", "."); + private static CertificateFactory cf; + + // Each of the roots have a test certificate chain stored in a file + // named "-chain.pem". + private static String[] rootsToTest = new String[] { + "entrustevca", "entrustrootcaec1", "entrustrootcag2", "entrustrootcag4", + "entrust2048ca", "affirmtrustcommercialca", "affirmtrustnetworkingca", + "affirmtrustpremiumca", "affirmtrustpremiumeccca" }; + + // A date that is after the restrictions take effect + private static final Date NOVEMBER_12_2024 = + Date.from(LocalDate.of(2024, 11, 12) + .atStartOfDay(ZoneOffset.UTC) + .toInstant()); + + // A date that is a second before the restrictions take effect + private static final Date BEFORE_NOVEMBER_12_2024 = + Date.from(LocalDate.of(2024, 11, 12) + .atStartOfDay(ZoneOffset.UTC) + .minusSeconds(1) + .toInstant()); + + public static void main(String[] args) throws Exception { + + cf = CertificateFactory.getInstance("X.509"); + + boolean before = args[0].equals("before"); + boolean policyOn = args[1].equals("policyOn"); + boolean isValid = args[2].equals("valid"); + + if (!policyOn) { + // disable policy (default is on) + Security.setProperty("jdk.security.caDistrustPolicies", ""); + } + + Date notBefore = before ? BEFORE_NOVEMBER_12_2024 : NOVEMBER_12_2024; + + X509TrustManager pkixTM = getTMF("PKIX", null); + X509TrustManager sunX509TM = getTMF("SunX509", null); + for (String test : rootsToTest) { + System.err.println("Testing " + test); + X509Certificate[] chain = loadCertificateChain(test); + + testTM(sunX509TM, chain, notBefore, isValid); + testTM(pkixTM, chain, notBefore, isValid); + } + } + + private static X509TrustManager getTMF(String type, + PKIXBuilderParameters params) throws Exception { + TrustManagerFactory tmf = TrustManagerFactory.getInstance(type); + if (params == null) { + tmf.init((KeyStore)null); + } else { + tmf.init(new CertPathTrustManagerParameters(params)); + } + TrustManager[] tms = tmf.getTrustManagers(); + for (TrustManager tm : tms) { + X509TrustManager xtm = (X509TrustManager)tm; + return xtm; + } + throw new Exception("No TrustManager for " + type); + } + + private static PKIXBuilderParameters getParams() throws Exception { + PKIXBuilderParameters pbp = + new PKIXBuilderParameters(SecurityUtils.getCacertsKeyStore(), + new X509CertSelector()); + pbp.setRevocationEnabled(false); + return pbp; + } + + private static void testTM(X509TrustManager xtm, X509Certificate[] chain, + Date notBefore, boolean valid) throws Exception { + // Check if TLS Server certificate (the first element of the chain) + // is issued after the specified notBefore date (should be rejected + // unless distrust property is false). To do this, we need to + // fake the notBefore date since none of the test certs are issued + // after then. + chain[0] = new DistrustedTLSServerCert(chain[0], notBefore); + + try { + xtm.checkServerTrusted(chain, "ECDHE_RSA"); + if (!valid) { + throw new Exception("chain should be invalid"); + } + } catch (CertificateException ce) { + // expired TLS certificates should not be treated as failure + if (expired(ce)) { + System.err.println("Test is N/A, chain is expired"); + return; + } + if (valid) { + throw new Exception("Unexpected exception, chain " + + "should be valid", ce); + } + if (ce instanceof ValidatorException) { + ValidatorException ve = (ValidatorException)ce; + if (ve.getErrorType() != ValidatorException.T_UNTRUSTED_CERT) { + ce.printStackTrace(System.err); + throw new Exception("Unexpected exception: " + ce); + } + } else { + throw new Exception("Unexpected exception: " + ce); + } + } + } + + // check if a cause of exception is an expired cert + private static boolean expired(CertificateException ce) { + if (ce instanceof CertificateExpiredException) { + return true; + } + Throwable t = ce.getCause(); + while (t != null) { + if (t instanceof CertificateExpiredException) { + return true; + } + t = t.getCause(); + } + return false; + } + + private static X509Certificate[] loadCertificateChain(String name) + throws Exception { + try (InputStream in = new FileInputStream(TEST_SRC + File.separator + + name + "-chain.pem")) { + Collection certs = + (Collection)cf.generateCertificates(in); + return certs.toArray(new X509Certificate[0]); + } + } + + private static class DistrustedTLSServerCert extends X509Certificate { + private final X509Certificate cert; + private final Date notBefore; + DistrustedTLSServerCert(X509Certificate cert, Date notBefore) { + this.cert = cert; + this.notBefore = notBefore; + } + public Set getCriticalExtensionOIDs() { + return cert.getCriticalExtensionOIDs(); + } + public byte[] getExtensionValue(String oid) { + return cert.getExtensionValue(oid); + } + public Set getNonCriticalExtensionOIDs() { + return cert.getNonCriticalExtensionOIDs(); + } + public boolean hasUnsupportedCriticalExtension() { + return cert.hasUnsupportedCriticalExtension(); + } + public void checkValidity() throws CertificateExpiredException, + CertificateNotYetValidException { + // always pass + } + public void checkValidity(Date date) throws CertificateExpiredException, + CertificateNotYetValidException { + // always pass + } + public int getVersion() { return cert.getVersion(); } + public BigInteger getSerialNumber() { return cert.getSerialNumber(); } + public Principal getIssuerDN() { return cert.getIssuerDN(); } + public Principal getSubjectDN() { return cert.getSubjectDN(); } + public Date getNotBefore() { return notBefore; } + public Date getNotAfter() { return cert.getNotAfter(); } + public byte[] getTBSCertificate() throws CertificateEncodingException { + return cert.getTBSCertificate(); + } + public byte[] getSignature() { return cert.getSignature(); } + public String getSigAlgName() { return cert.getSigAlgName(); } + public String getSigAlgOID() { return cert.getSigAlgOID(); } + public byte[] getSigAlgParams() { return cert.getSigAlgParams(); } + public boolean[] getIssuerUniqueID() { + return cert.getIssuerUniqueID(); + } + public boolean[] getSubjectUniqueID() { + return cert.getSubjectUniqueID(); + } + public boolean[] getKeyUsage() { return cert.getKeyUsage(); } + public int getBasicConstraints() { return cert.getBasicConstraints(); } + public byte[] getEncoded() throws CertificateEncodingException { + return cert.getEncoded(); + } + public void verify(PublicKey key) throws CertificateException, + InvalidKeyException, NoSuchAlgorithmException, + NoSuchProviderException, SignatureException { + cert.verify(key); + } + public void verify(PublicKey key, String sigProvider) throws + CertificateException, InvalidKeyException, NoSuchAlgorithmException, + NoSuchProviderException, SignatureException { + cert.verify(key, sigProvider); + } + public PublicKey getPublicKey() { return cert.getPublicKey(); } + public String toString() { return cert.toString(); } + } +} diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustcommercialca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustcommercialca-chain.pem new file mode 100644 index 00000000000..76aa6d14338 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustcommercialca-chain.pem @@ -0,0 +1,77 @@ +Root Certificate: + Version: 3 (0x2) + Serial Number: 8608355977964138876 (0x7777062726a9b17c) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=AffirmTrust, CN=AffirmTrust Commercial + Validity + Not Before: Jan 29 14:06:06 2010 GMT + Not After : Dec 31 14:06:06 2030 GMT + +-----BEGIN CERTIFICATE----- +MIIHHjCCBgagAwIBAgIQAWZjFOyCvT00u/gtkCvS2TANBgkqhkiG9w0BAQsFADCB +gzELMAkGA1UEBhMCQ0ExFDASBgNVBAoTC0FmZmlybVRydXN0MSswKQYDVQQLEyJT +ZWUgd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MTEwLwYDVQQDEyhBZmZp +cm1UcnVzdCBFeHRlbmRlZCBWYWxpZGF0aW9uIENBIC0gRVYxMB4XDTI0MDYyODIx +MzgwNVoXDTI1MDcyODIxMzgwNFowgdgxCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdP +bnRhcmlvMQ8wDQYDVQQHEwZPdHRhd2ExEzARBgsrBgEEAYI3PAIBAxMCQ0ExGDAW +BgsrBgEEAYI3PAIBAhMHT250YXJpbzEcMBoGA1UEChMTQWZmaXJtdHJ1c3QgTGlt +aXRlZDEdMBsGA1UEDxMUUHJpdmF0ZSBPcmdhbml6YXRpb24xEDAOBgNVBAUTBzI1 +NDA1NDcxKDAmBgNVBAMTH3ZhbGlkY29tbWVyY2lhbC5hZmZpcm10cnVzdC5jb20w +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDeIT2XO0hJ5wDSbIiIcMvs +P3NpQc7O7v5DqldpME6+Qn2sF5b9hc6j72hgTXREa77uUcP5u1JcMWCSWwYQHMpJ +kFzmIzijhS60wW1epb5QyTgM3ZYh1WKvttFCbHUcrTtd+LoPFYsjw9ZK//K9tPp+ +ddn06/ivWvUO5y5vn0wrCaB9tuLdDn4RCQzK2XoZdDuqhPlBBogJX0vM6lsXjgLy +EbvE+/sKYps/In6VtRvCoYavg3OqaIMeaA7gTiYTb1ZGFOAiltnq7fcp6SZUohK3 +QNihv1DadVc+n8LnEUKKDkgG2YgWEFczaE3qwG3ef6L3MzLGrkgVY+qGHyyv2IE7 +AgMBAAGjggM1MIIDMTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBT4ARNL47hAsOpa +96VMgKEY3sLIAjAfBgNVHSMEGDAWgBTb72U3C+VHyzXRkB8DwbyIx6fqgDBsBggr +BgEFBQcBAQRgMF4wJwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3NwLmFmZmlybXRydXN0 +LmNvbTAzBggrBgEFBQcwAoYnaHR0cDovL2FpYS5hZmZpcm10cnVzdC5jb20vYWZ0 +ZXYxY2EuY3J0MDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuYWZmaXJtdHJ1 +c3QuY29tL2NybC9hZnRldjFjYS5jcmwwKgYDVR0RBCMwIYIfdmFsaWRjb21tZXJj +aWFsLmFmZmlybXRydXN0LmNvbTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI +KwYBBQUHAwEGCCsGAQUFBwMCMFYGA1UdIARPME0wBwYFZ4EMAQEwQgYKKwYBBAGC +jwkCATA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5hZmZpcm10cnVzdC5jb20v +cmVwb3NpdG9yeTCCAYAGCisGAQQB1nkCBAIEggFwBIIBbAFqAHcAEvFONL1TckyE +BhnDjz96E/jntWKHiJxtMAWE6+WGJjoAAAGQYMi3wQAABAMASDBGAiEAjvdsU4G2 +o4BZSOOjaH6gOp7zhKtXQByQUvfHfsi2ePcCIQDnnIO2qlHBm+sskUDlXfR0lCUW +yFPVr9nFZ0L9YPpozgB2AA3h8jAr0w3BQGISCepVLvxHdHyx1+kw7w5CHrR+Tqo0 +AAABkGDIt9MAAAQDAEcwRQIhANh1zS3Qeo9yKF+j3G52JhmDRYBS+1TM0wykoXCY +llpxAiAG+LAlKSbwwgrboUSTDDXWNeoRYZ7fKbU72kKfHrpZvwB3ABoE/0nQVB1A +r/agw7/x2MRnL07s7iNAaJhrF0Au3Il9AAABkGDIt9sAAAQDAEgwRgIhAN8OoC4I +zw8bFJy8ACgK40c9ZfsIfFhePTc9CyrL5uDsAiEA4Jn/IqBB9L5DeTgqw9hBaYag +FmY/2gWDip36ga0WUsAwDQYJKoZIhvcNAQELBQADggEBABywPLJP097Emz6LNeFU +/HvfhaUKv2pgIHf/Kvjs5x78RK9G605THPEHr/TeUjNZ4PBd48WBNVWzyd/8FuOt +r+FsYkRJb9CnrOhZHuCwlcdWXvuY8PiuBmT+xB16BWR5yhYbbiGe4hea0Pf6CfHh +jJoGJw4dQKfgneZOV7IcaWnNTKYawlcZOgxvEwFvj+iZM31WphEPKRAV+N+Tp+ZR +nxlEdjmdbOjqBydlYIEzuFIgxgtnPdK5wqCOWb+z2cARUAO/AkiWrOLTPDc7ydQK +GcfDrSqffHOlwaee08C6STFaJWIcpqxZdXE6Jc+8/85bfPEAG1UepgfnBTqW9RGT +Q3s= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEqDCCA5CgAwIBAgIQFylVHtaOf7Ht9XMA811/1TANBgkqhkiG9w0BAQsFADBE +MQswCQYDVQQGEwJVUzEUMBIGA1UECgwLQWZmaXJtVHJ1c3QxHzAdBgNVBAMMFkFm +ZmlybVRydXN0IENvbW1lcmNpYWwwHhcNMTkwMzIxMjAyNzU0WhcNMzAxMjAyMDQw +MDAwWjCBgzELMAkGA1UEBhMCQ0ExFDASBgNVBAoTC0FmZmlybVRydXN0MSswKQYD +VQQLEyJTZWUgd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MTEwLwYDVQQD +EyhBZmZpcm1UcnVzdCBFeHRlbmRlZCBWYWxpZGF0aW9uIENBIC0gRVYxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuPBMIa9VuXJGAw0MHvieGciPFA11 +b9T49YJ7T+zVpoMMQO+ueUKVHb2l26oeCiwIhXMQ5LquOVcx+rofouzcKXY3wKDZ +zHIOnAkU+23Ucn/3dRH7aHJULsBufZq+NvwgYSgJJEDKfqvIV/c5HiRyZ2H+nAI5 +10Q2xC0UxgSBsufccQ+Fwkg6BAGDlTXrvi8wi75UaGue6jv/qcKLybeVUrgqKE64 +d9oa9PG5/g89QwSdsIQEdVSFzFvFpOG9YhJbJ177Zg6DGCxU0lWwFrVpyH/2vnXl +jhMQScn8UxzCJdDg3EDqjgaV0JH2yoLug+QVYgURPu5BEb5ut9vAdP7cLwIDAQAB +o4IBVDCCAVAwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8vb2Nz +cC5hZmZpcm10cnVzdC5jb20wHQYDVR0OBBYEFNvvZTcL5UfLNdGQHwPBvIjHp+qA +MBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUnZPGU4teyq8/nx4P5ZmV +vCT2lI8wRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8v +d3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MEkGA1UdHwRCMEAwPqA8oDqG +OGh0dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2NybC9BZmZpcm1UcnVzdENvbW1l +cmNpYWwuY3JsMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYI +KwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAATH11fMrINGmQGQqQW0ATteVnUG +LrmRSN2OlmRm+dkUwKXhcQQEfYYlEggPqgvxSUpw13fXSOqVHqAcj3BIqF957kh+ +m3DmC0RX9KaEKD165pf77P5nZcRmZpBl9cctvzIxN19uzcminchusYwLyeWhBtTZ +xpER9LbrfMNaQ7GnrgalMx54QvdjOhw/GJs9/SqEzYmPshL+DzgZX/oAzY63rQIh +rBblf6/2talZqci96oFzNst8rGfPy/xQ7lgkki1hwIYbORMfloBhP+vAZJo0mxdM +ipu3Z0ToK+KU2iqnBxXVr2/kod+CpkHnjUHa1wnQuSaefng3XwZ/vqtSL9c= +-----END CERTIFICATE----- diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustnetworkingca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustnetworkingca-chain.pem new file mode 100644 index 00000000000..7384d31152e --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustnetworkingca-chain.pem @@ -0,0 +1,76 @@ +Root Certificate: + Version: 3 (0x2) + Serial Number: 8957382827206547757 (0x7c4f04391cd4992d) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=AffirmTrust, CN=AffirmTrust Networking + Validity + Not Before: Jan 29 14:08:24 2010 GMT + Not After : Dec 31 14:08:24 2030 GMT + +-----BEGIN CERTIFICATE----- +MIIHGjCCBgKgAwIBAgIQX2vGPaCJ1tS0ncp2OlBMFjANBgkqhkiG9w0BAQsFADCB +gzELMAkGA1UEBhMCQ0ExFDASBgNVBAoTC0FmZmlybVRydXN0MSswKQYDVQQLEyJT +ZWUgd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MTEwLwYDVQQDEyhBZmZp +cm1UcnVzdCBFeHRlbmRlZCBWYWxpZGF0aW9uIENBIC0gRVYzMB4XDTI0MDYyODIx +NDU0OVoXDTI1MDcyODIxNDU0OFowgdgxCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdP +bnRhcmlvMQ8wDQYDVQQHEwZPdHRhd2ExEzARBgsrBgEEAYI3PAIBAxMCQ0ExGDAW +BgsrBgEEAYI3PAIBAhMHT250YXJpbzEcMBoGA1UEChMTQWZmaXJtdHJ1c3QgTGlt +aXRlZDEdMBsGA1UEDxMUUHJpdmF0ZSBPcmdhbml6YXRpb24xEDAOBgNVBAUTBzI1 +NDA1NDcxKDAmBgNVBAMTH3ZhbGlkbmV0d29ya2luZy5hZmZpcm10cnVzdC5jb20w +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCkGknE8kFr+CaIybQrDPRw +z9OKXq77p4CnrkF1/g9w/HiIs6Ps8YqTjsiTKM3wYLbvPA+TbO9DpCSyCP2bVyLf +AjUE617KZSpfy9RqzvGjn/1qH/cBKohhEliMfDj4ZHfY4x+1WYTZPVK/g0Ny5RAP +wz9lJHR2SsVGLvpqXzWaVoxifJ8HZWD7n5z/75WeYko+Hubx3WvzJZcN2Xjn+q6a +7wkDaXPayrvn5uWGPlOLQHqJ5z7wts21jASMTfJAToFyzH6dGwvqxkP3bVJGJ8AF +vtMfqVjcOcjWgmmOEHMPAAqs5QKrYuSLccH6hFTwFEUCdMwVqfloznt2sNUSBoKj +AgMBAAGjggMxMIIDLTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTrE0z4fRyx9P9M +0FfA6VgGkJiYVDAfBgNVHSMEGDAWgBR5HrHJF8cerLHHFNfD6H+8uVCbFTBsBggr +BgEFBQcBAQRgMF4wJwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3NwLmFmZmlybXRydXN0 +LmNvbTAzBggrBgEFBQcwAoYnaHR0cDovL2FpYS5hZmZpcm10cnVzdC5jb20vYWZ0 +ZXYzY2EuY3J0MDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuYWZmaXJtdHJ1 +c3QuY29tL2NybC9hZnRldjNjYS5jcmwwKgYDVR0RBCMwIYIfdmFsaWRuZXR3b3Jr +aW5nLmFmZmlybXRydXN0LmNvbTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI +KwYBBQUHAwEGCCsGAQUFBwMCMFYGA1UdIARPME0wBwYFZ4EMAQEwQgYKKwYBBAGC +jwkCAjA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5hZmZpcm10cnVzdC5jb20v +cmVwb3NpdG9yeTCCAXwGCisGAQQB1nkCBAIEggFsBIIBaAFmAHYADeHyMCvTDcFA +YhIJ6lUu/Ed0fLHX6TDvDkIetH5OqjQAAAGQYM/MjQAABAMARzBFAiBjnehs1mvh +5Xm3uXZ7Bq8gijwiXThwnLSYROQxnWrnbAIhALbgJG+PRZQfzTBbgM/zAwNsBjhe +F5iENnaajJCxzOhaAHUAEvFONL1TckyEBhnDjz96E/jntWKHiJxtMAWE6+WGJjoA +AAGQYM/MgQAABAMARjBEAiAsWOm1IIjaxQP9uaPI9tQmkiJPUOTrBTsTDO+jkgiG ++QIgVNhND82rsFGjrtAAHzzgCVzLDUM3zaHxnP/z3BNuO4QAdQAaBP9J0FQdQK/2 +oMO/8djEZy9O7O4jQGiYaxdALtyJfQAAAZBgz8zLAAAEAwBGMEQCIBIGxtjk7Lw8 +i+oggK7VrPMNTB632t321cwhEm517BbZAiBws3+uytwh59N6qGJUuSFQnOZNPOPj +eQnH2fSdT1J2sDANBgkqhkiG9w0BAQsFAAOCAQEAcSzitESRKlbcUvxvUB7FjK0I +CaBU1Nyu0xDFCoG2pmp7GASJz34wtPYfsiX5+j4hDh/noMcgk7WlD8pzgWYw15Rk ++5kTv2v4U85y/JFjzMOHbz64KjQdGebqhjvC/E/EXxK+AZf4H574/w7rbyJ30vFL +gNvPF9AxS1MuYIO55jXrHMByKnFoQZgPsmAY/x+n+OzMxWOdR18PupypCB5TyJZ8 +pQzwoxmX7qeZHiXyJ8jQUwe1qoQc2SbwfQxfwSPUPSJuQo90N+5nyQMe7vvPBM0Y +/CXaFpfPqh71D4C0Ey+0hYxSt99gYs4P9twUByjIlP0wTyhaoEpt3zw9DdZypQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEqDCCA5CgAwIBAgIQNCSh7Pjwo1/nRrcBHEPoRDANBgkqhkiG9w0BAQsFADBE +MQswCQYDVQQGEwJVUzEUMBIGA1UECgwLQWZmaXJtVHJ1c3QxHzAdBgNVBAMMFkFm +ZmlybVRydXN0IE5ldHdvcmtpbmcwHhcNMTkwMzIxMjAzODU5WhcNMzAxMjAyMDQw +MDAwWjCBgzELMAkGA1UEBhMCQ0ExFDASBgNVBAoTC0FmZmlybVRydXN0MSswKQYD +VQQLEyJTZWUgd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MTEwLwYDVQQD +EyhBZmZpcm1UcnVzdCBFeHRlbmRlZCBWYWxpZGF0aW9uIENBIC0gRVYzMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmHDl/3xr1qiHoe0Rzb3AGLw56e9J +l2a3X59+PAfI5wGBHuK9Dl7XsyoH65X6QIC/rXyVpuNgKbbwIGHB+rCSplyHzGyC +WeM3LXa2q1US7VteeFDS959nxJVRFfwATR9xAK6YTUWQ/yWdw0dZSm0lQNmEMBwS +qi0ufWokiWXZUzWHOu7A6driCohu9sFDwe1INJUPH6uIlovmzGvG3UYbUSymJcjs +Ka0fXXX9zukco8exlOIKWRJSNLxKtSSPDVASrGLQ1xi3qkiLTKci3+jKMNDFf1vw +foZN99HhUcWKXfr2KlWfANdjTMlsTKCfuhfWl1OBVNHGRrACAQCXI/ji0wIDAQAB +o4IBVDCCAVAwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8vb2Nz +cC5hZmZpcm10cnVzdC5jb20wHQYDVR0OBBYEFHkesckXxx6ssccU18Pof7y5UJsV +MBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUBx/S55zawm6iQLSwelAQ +UHTEyL0wRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8v +d3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MEkGA1UdHwRCMEAwPqA8oDqG +OGh0dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2NybC9BZmZpcm1UcnVzdE5ldHdv +cmtpbmcuY3JsMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYI +KwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAAhmE4I56hNpnWXQ2Si8a/TgQUZr +X5Jlv1LDvl3rkDyfEIHNZ8dth17SakJYJBWHExph/iIYjCJ9YmeyhghV5rPqT+wF +4yyE2ngenIusfnWT2bTpT9u2VZbCNeACE5XnN2UHSA0J9idPjfLuthViWEvSZZUh +DJ53bX+exO366nDY4AI7owIyhz8hdsWyhZ/0ST+eD+kbgd8osd+GdxzRmyKcfl84 +D1K1uff01T9w2dyUaZglQsFljkaO6xmeXZJsPnhwCp/HlMHWzhAneUQ7I9FZSOW+ +WiYbt4RitmBpysadBReikWM4knECzJQ/fMT9vC0k9BLlqUYRwCH9vr0UnZo= +-----END CERTIFICATE----- diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustpremiumca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustpremiumca-chain.pem new file mode 100644 index 00000000000..6f108bc1229 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustpremiumca-chain.pem @@ -0,0 +1,88 @@ +Root Certificate: + Version: 3 (0x2) + Serial Number: 7893706540734352110 (0x6d8c1446b1a60aee) + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=US, O=AffirmTrust, CN=AffirmTrust Premium + Validity + Not Before: Jan 29 14:10:36 2010 GMT + Not After : Dec 31 14:10:36 2040 GMT + +-----BEGIN CERTIFICATE----- +MIIIFjCCBv6gAwIBAgIQQVOTWr7tEAJXmRDkCSxkajANBgkqhkiG9w0BAQsFADCB +gzELMAkGA1UEBhMCQ0ExFDASBgNVBAoTC0FmZmlybVRydXN0MSswKQYDVQQLEyJT +ZWUgd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MTEwLwYDVQQDEyhBZmZp +cm1UcnVzdCBFeHRlbmRlZCBWYWxpZGF0aW9uIENBIC0gRVYyMB4XDTI0MDYyODIx +NDgyN1oXDTI1MDcyODIxNDgyNlowgdUxCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdP +bnRhcmlvMQ8wDQYDVQQHEwZPdHRhd2ExEzARBgsrBgEEAYI3PAIBAxMCQ0ExGDAW +BgsrBgEEAYI3PAIBAhMHT250YXJpbzEcMBoGA1UEChMTQWZmaXJtdHJ1c3QgTGlt +aXRlZDEdMBsGA1UEDxMUUHJpdmF0ZSBPcmdhbml6YXRpb24xEDAOBgNVBAUTBzI1 +NDA1NDcxJTAjBgNVBAMTHHZhbGlkcHJlbWl1bS5hZmZpcm10cnVzdC5jb20wggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVRMzwbDq47ivHOKqJdiEJNL2+ +g9Snj/BRctqcQTrIV99RP0pmAh5fHg7vnhVsHqc9sRLVcQWTJk9NuRJ2VnDKWsBa +Xrp5UWaNjS0vaFA4jzCi1gWzTTZgPTQn3VRG3JP1F5CZb405/mtWDaw/CfWkcUqQ +VSilqFlJRsjcPCzQh7ZaXAo+FmzJxNSwjxdP6JSYMeTDRCUpSb3T8PypVI1CEmLZ +jsxrg5oIZn25591g/pzgLE56N0stNY4d3q4YD1t5x46RsqYAJYSkk8rcTN+kHzsY +VSqaRDyPkGbmuCeJUvW24wJ30yQtXQWA+U0dMYLe7LyglJ7dkOzvWNbqrIcvM8My +hxH/wwVH7e4dL/1E58yr1BHENUk7Mp9rzIXj496eLkF5G1lMkNnuVRQqCAOW0rPY +V0rI8yrCMTK52s4mNjQo2J7JOYdTUvAWZ92MKvEjjhQlMH8eK72Km/+mkxpsgGmr +3c6u+Gom7oI5VaLZ+3p2uWaOsutk1tkzWjhzY4L27hwmIdWujfrWMRx8uxcfoJxX +gQ40d1QiSN51BtCPE5UnpLU/YUxMdzWmtUoGUfYIGVqDVToBnunIFMdmFjC0IrNl +hquDQi/OGMpzuOvxX1FoXb+rRwOhhdrcR0BQqUVRTV0U5LlcsDeNMqmqPE9mzGtJ +W69Fsh7crntng/L72wIDAQABo4IDMDCCAywwDAYDVR0TAQH/BAIwADAdBgNVHQ4E +FgQU3PWyi/4usZghgahc/Tj+Q60QLOcwHwYDVR0jBBgwFoAUc3yaOGg8UXxBCP6h +HyoetGHbzTwwbAYIKwYBBQUHAQEEYDBeMCcGCCsGAQUFBzABhhtodHRwOi8vb2Nz +cC5hZmZpcm10cnVzdC5jb20wMwYIKwYBBQUHMAKGJ2h0dHA6Ly9haWEuYWZmaXJt +dHJ1c3QuY29tL2FmdGV2MmNhLmNydDA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8v +Y3JsLmFmZmlybXRydXN0LmNvbS9jcmwvYWZ0ZXYyY2EuY3JsMCcGA1UdEQQgMB6C +HHZhbGlkcHJlbWl1bS5hZmZpcm10cnVzdC5jb20wDgYDVR0PAQH/BAQDAgWgMB0G +A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBWBgNVHSAETzBNMAcGBWeBDAEB +MEIGCisGAQQBgo8JAgMwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuYWZmaXJt +dHJ1c3QuY29tL3JlcG9zaXRvcnkwggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB2 +ABoE/0nQVB1Ar/agw7/x2MRnL07s7iNAaJhrF0Au3Il9AAABkGDSN7EAAAQDAEcw +RQIgVDWwhv7yG6RNnkMZnVq1YYA7ypn/GSH0ibUKnESHRpYCIQCY8gyCX7VFONUI +QuR8daz7ra2FCUI9TwylrR3eFfIgGgB3AN3cyjSV1+EWBeeVMvrHn/g9HFDf2wA6 +FBJ2Ciysu8gqAAABkGDSN5cAAAQDAEgwRgIhAM1edsSyFUKU0Dj1WxTGwziE6fCW +g2ByfL8kDrP260YXAiEA6YQOpJf04N13Nn263BxAl+laH9Ar0eo03fArlv743TQA +dQAN4fIwK9MNwUBiEgnqVS78R3R8sdfpMO8OQh60fk6qNAAAAZBg0je+AAAEAwBG +MEQCIExqK4katETAQo+H0+ImuNJCSeFEI9C+9wrjhl6ZnWb9AiBwkC1vpLYOIm/1 +YCLCQIOmTdg2wf8LITlrQNJA8vbBljANBgkqhkiG9w0BAQsFAAOCAQEASOmPu7ot +yl6MoMns19uI6H2KSUjMFh3/fKMcY/ettmEYalgrytexFMrLnD2UniBlD+nJEshp +5/z7o0YDiRoiLhMAs7VqIdX3erNu/ghNh7P2bDnoMWShSoAKxez1XOGL3rRE0NAi +DsWCaNRHH9rnC97275sbGnua7ZYg+8BiF62vpJlqjrxDHjGiej8qAWSjztbB43Af +bwRscpXTxNkMvOBuRFMH+rSxB8CrOV68W+yxmzPuPxVjM7oJH8Qk5BC53NRqFsVz +JhbNfot0+/drj7JT3jlacUVQcD/BzDuC3+qczQlLjLdHgQM2/e4fXsD6C5S6B11d +BDx6ipGpaASofA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIQU3HI6weE/VEI5dTz4yPsRjANBgkqhkiG9w0BAQsFADBB +MQswCQYDVQQGEwJVUzEUMBIGA1UECgwLQWZmaXJtVHJ1c3QxHDAaBgNVBAMME0Fm +ZmlybVRydXN0IFByZW1pdW0wHhcNMTkwMzIxMjA0NjM1WhcNMzAxMjAyMDQwMDAw +WjCBgzELMAkGA1UEBhMCQ0ExFDASBgNVBAoTC0FmZmlybVRydXN0MSswKQYDVQQL +EyJTZWUgd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MTEwLwYDVQQDEyhB +ZmZpcm1UcnVzdCBFeHRlbmRlZCBWYWxpZGF0aW9uIENBIC0gRVYyMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvDDZHfxkB1nAGFKdw0VCgV+B/eBtW1o+ +bXzwRcpeFh5saDI+tv1RAMrYFq+AJkXCCJopgMF2Wqfv5myE3JMgxEHuuKUpJz7H +FprrFckVOGCtJKH8Iy9AWPjBwt8lKmxGJF7EZst+QoVt4hMe0qhL0WEKbATFPe41 +DcM7UsyQv6Bvpn424uePy3/1ATIsVL3YmvAbUNR0aqVxYAJzTefvyIet/761bKGc +NyqdOVWFFeTDtr8iL1TBXToAgl0GJ39bFQZsP19VcCpfk9Zj3YHTPRPq5wZOZuUN +F7jiBUEi6DaVOi3Wy4vdySHtWPeBHRYif1I6fcUfdCNORMc4ee6KewIDAQABo4IB +UTCCAU0wNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5h +ZmZpcm10cnVzdC5jb20wHQYDVR0OBBYEFHN8mjhoPFF8QQj+oR8qHrRh2808MBIG +A1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAUncBnpgwi2Sb1RaumZVIRJ9hF +rGMwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3 +LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MEYGA1UdHwQ/MD0wO6A5oDeGNWh0 +dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2NybC9BZmZpcm1UcnVzdFByZW1pdW0u +Y3JsMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH +AwIwDQYJKoZIhvcNAQELBQADggIBABi64UEwl3l0yIiuSACyVQQIBI60BUmhseac +4BzCAsJrR5tE/2U9QAa2y6JpR1nqm76DJvw1QQgvFcNe+fkwpvoViCaSTbZkGGwD +mQe2xRSYJcDSMQUc/GgzLcX2c1CrexQXE1vwV/q33af1en5s1GzLl915aNS/k1ch +G7EMruJ/D4cuH9j4j2i+b+llmVBzavBwelN5rc693o+Ot9id/1sTWNugwAu3uXGb +VlhETMnjXGIciegOLdWYhWBln0izYlt9IwlDEpjMVaZ0HZlj2JBGaSe4PfEFpJPO +beuPcQpLQGw2XpW2ZMG5JcRYaoKWjixXAGktRA3H9nvVW92jvzx/RX484w2ZM5Rt +E+I1ikAuQLAyWG7clht387e2RuC3NZTtefSyjE3L9gQDOPC+Z9ycwr0WJHRsxFvh +FJQi3JnxgFZf5mc5n2mh3qAgALTNOUHuDiHrerjTOWbpF/1/NJmo/c/YZ63vZIhc +EaER4HuhbBqlpf6z3WOIQdZm1ChwXYHrEcLDgfwm9cXoaVK2HZapkMwQbPffPlT1 +E+AxRFB4YmT1y2WzdaHfhFA9nH6ByUdL5+FfrDoIIUO2e8OLOAcrJsf5+unhAhc0 +v7N48JWdmpstjkXCaCIaidrZLJxS+pikNgHB1dXF/TxokLTiPB9jcYKdGaYs3XHb +YKLdwubu +-----END CERTIFICATE----- diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustpremiumeccca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustpremiumeccca-chain.pem new file mode 100644 index 00000000000..37b1b787084 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustpremiumeccca-chain.pem @@ -0,0 +1,63 @@ +Root Certificate: + Version: 3 (0x2) + Serial Number: 8401224907861490260 (0x7497258ac73f7a54) + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=US, O=AffirmTrust, CN=AffirmTrust Premium ECC + Validity + Not Before: Jan 29 14:20:24 2010 GMT + Not After : Dec 31 14:20:24 2040 GMT + +-----BEGIN CERTIFICATE----- +MIIF0zCCBVmgAwIBAgIQFVwk9nYUM5SYOnBd+IoGtzAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCQ0ExFDASBgNVBAoTC0FmZmlybVRydXN0MSswKQYDVQQLEyJTZWUg +d3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5MTMwMQYDVQQDEypBZmZpcm1U +cnVzdCBFeHRlbmRlZCBWYWxpZGF0aW9uIENBIC0gRVZFQzEwHhcNMjQwNjI4MjE0 +OTUwWhcNMjUwNzI4MjE0OTQ4WjCB2DELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09u +dGFyaW8xDzANBgNVBAcTBk90dGF3YTETMBEGCysGAQQBgjc8AgEDEwJDQTEYMBYG +CysGAQQBgjc8AgECEwdPbnRhcmlvMRwwGgYDVQQKExNBZmZpcm10cnVzdCBMaW1p +dGVkMR0wGwYDVQQPExRQcml2YXRlIE9yZ2FuaXphdGlvbjEQMA4GA1UEBRMHMjU0 +MDU0NzEoMCYGA1UEAxMfdmFsaWRwcmVtaXVtZWNjLmFmZmlybXRydXN0LmNvbTB2 +MBAGByqGSM49AgEGBSuBBAAiA2IABEkLBzBYSJPRENKDaA1iBPQz+jZUV+OoM9nJ +sr9sMfmHaqr3nlWxAMM99b9/usVfYyUxqyi+YL2Z3ZSxjX2dpyhwMtPpIQkL1pMW +Iv55XBIcYRyl2NjcADS9B06G+nnix6OCAzcwggMzMAwGA1UdEwEB/wQCMAAwHQYD +VR0OBBYEFP+37ywf2YJJ/4CEVy1GY4ioGm1yMB8GA1UdIwQYMBaAFMaQjAKD113j +vjucLtVlfSoQYO7lMG4GCCsGAQUFBwEBBGIwYDAnBggrBgEFBQcwAYYbaHR0cDov +L29jc3AuYWZmaXJtdHJ1c3QuY29tMDUGCCsGAQUFBzAChilodHRwOi8vYWlhLmFm +ZmlybXRydXN0LmNvbS9hZnRldmVjMWNhLmNydDA+BgNVHR8ENzA1MDOgMaAvhi1o +dHRwOi8vY3JsLmFmZmlybXRydXN0LmNvbS9jcmwvYWZ0ZXZlYzFjYS5jcmwwKgYD +VR0RBCMwIYIfdmFsaWRwcmVtaXVtZWNjLmFmZmlybXRydXN0LmNvbTAOBgNVHQ8B +Af8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMFYGA1UdIARP +ME0wBwYFZ4EMAQEwQgYKKwYBBAGCjwkCBDA0MDIGCCsGAQUFBwIBFiZodHRwczov +L3d3dy5hZmZpcm10cnVzdC5jb20vcmVwb3NpdG9yeTCCAX4GCisGAQQB1nkCBAIE +ggFuBIIBagFoAHUA5tIxY0B3jMEQQQbXcbnOwdJA9paEhvu6hzId/R43jlAAAAGQ +YNN5tQAABAMARjBEAiAnainEoBGI9czVh+c9QLPL30S3Rtov8zrnhlXfeKLzZQIg +UGkntBMux0MqHt9Aj60qMsS/C4ZWF7AihVVaUKcrEVgAdgAN4fIwK9MNwUBiEgnq +VS78R3R8sdfpMO8OQh60fk6qNAAAAZBg03m1AAAEAwBHMEUCIGI9kBByoozH4cfS +ECW/O2N/ElkdATkt7EwQ52kcc4ICAiEA9QTh8JlJTb/ytYC1ECX0vQbrYVexg+fu +dw7dfToF9nAAdwAS8U40vVNyTIQGGcOPP3oT+Oe1YoeInG0wBYTr5YYmOgAAAZBg +03ndAAAEAwBIMEYCIQCox5nSCcVB2AfNYXco77zsJnYP7KAU2I4VA2GNL7I4wQIh +AP6WEzyfBoGpYYqFmNnJUavyhKBmeNiR7eNtaFwpSc+UMAoGCCqGSM49BAMDA2gA +MGUCMAGSNMXAAKDRk0ZOtydN95Rkja97+70TatCIIxEAsJD8Hu7lfj2LHCYFQjVY +oaWTrQIxAKUudx7E/JnjsthuL6sNqKVHfD3iLUJyQNK9wE0SVt1xAm7Cu1JXZORE +M64KMKoQFQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXDCCAuKgAwIBAgIQAgKlhME0Bk3J8y0gfqNymDAKBggqhkjOPQQDAzBFMQsw +CQYDVQQGEwJVUzEUMBIGA1UECgwLQWZmaXJtVHJ1c3QxIDAeBgNVBAMMF0FmZmly +bVRydXN0IFByZW1pdW0gRUNDMB4XDTE5MDMyMTIwNTUwN1oXDTMwMTIwMjA0MDAw +MFowgYUxCzAJBgNVBAYTAkNBMRQwEgYDVQQKEwtBZmZpcm1UcnVzdDErMCkGA1UE +CxMiU2VlIHd3dy5hZmZpcm10cnVzdC5jb20vcmVwb3NpdG9yeTEzMDEGA1UEAxMq +QWZmaXJtVHJ1c3QgRXh0ZW5kZWQgVmFsaWRhdGlvbiBDQSAtIEVWRUMxMHYwEAYH +KoZIzj0CAQYFK4EEACIDYgAEu9f5NkumdaVlmaNaxpDB+rBk/S6lhqcUU1zTLcRz +4G0dr4290hezjrvZJxGJ/X15aexpdD2V9cwaPD/yuEJcaaz+rg/qDoqQF3+AFqVc +41jw1E0S59+57XVKLtXI7Xh6o4IBVDCCAVAwNwYIKwYBBQUHAQEEKzApMCcGCCsG +AQUFBzABhhtodHRwOi8vb2NzcC5hZmZpcm10cnVzdC5jb20wHQYDVR0OBBYEFMaQ +jAKD113jvjucLtVlfSoQYO7lMBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgw +FoAUmq8pesARNTUmUTAAw2r+QNWu1jwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYI +KwYBBQUHAgEWJmh0dHBzOi8vd3d3LmFmZmlybXRydXN0LmNvbS9yZXBvc2l0b3J5 +MEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmwuYWZmaXJtdHJ1c3QuY29tL2Ny +bC9BZmZpcm1UcnVzdFByZW1pdW1FQ0MuY3JsMA4GA1UdDwEB/wQEAwIBhjAdBgNV +HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwCgYIKoZIzj0EAwMDaAAwZQIwHJ5g +a6sHvQ51DGr0bWq34awuwlWbybC2grHoNp5uYapcXr/qTJusb/6n+dczqFdaAjEA +7VQY06fE9ifMnTgT9824jc3+H6kfhMk4PoIj9ouWdYfc1DyTBS/low9Hb8liQyFr +-----END CERTIFICATE----- diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrust2048ca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrust2048ca-chain.pem new file mode 100644 index 00000000000..253072d00ed --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrust2048ca-chain.pem @@ -0,0 +1,76 @@ +Root Certificate: + Version: 3 (0x2) + Serial Number: 946069240 (0x3863def8) + Signature Algorithm: sha1WithRSAEncryption + Issuer: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048) + Validity + Not Before: Dec 24 17:50:51 1999 GMT + Not After : Jul 24 14:15:12 2029 GMT + +-----BEGIN CERTIFICATE----- +MIIGiDCCBXCgAwIBAgIQS5P8oVcgTBT74PnIwDQivjANBgkqhkiG9w0BAQsFADCB +ujELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsT +H1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAy +MDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEuMCwG +A1UEAxMlRW50cnVzdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEwxSzAeFw0y +MzEwMDIxOTE4MTBaFw0yNDExMDIxOTE4MDlaMGkxCzAJBgNVBAYTAkNBMRAwDgYD +VQQIEwdPbnRhcmlvMQ8wDQYDVQQHEwZPdHRhd2ExGDAWBgNVBAoTD0VudHJ1c3Qg +TGltaXRlZDEdMBsGA1UEAxMUMjA0OHRlc3QuZW50cnVzdC5uZXQwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgkrsKoDEHyJjll/fu7mjvtbookb50rzTI +i+jQzvtL8AJOcCfxJL1cVriufc/zRYdSQeRJxkbUb+SqIJkec+27onPpY3xOjJAK +bWdmac1Iv9JPXYMpKJXnOGrooeXEtCcKSKphx4VhHnLA67BGfSNfHLm4JwghX4jY +VpZ8P89gmh8l1eLRP+b3y7OzEkFliwmErALSD8i/bkzE+GxYMnpg/HI2Iw1lakxE +wZOg0ydgl7jHWZUDdnxhAvLS/hfzPVhi9ZwgoXQJiUXUp0JJo6QgVOIC5IztpdZa +3HW1VK7a0eTLhmdFRx39ARn/GbbIyoIqUzLOhAa2cbsGIJjtXjhrAgMBAAGjggLY +MIIC1DAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRHn0CebGnHRqTZTeTYCbPHhiVB +MzAfBgNVHSMEGDAWgBSConB03bxTP8971PfNf6dgxgpMvzBoBggrBgEFBQcBAQRc +MFowIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDMGCCsGAQUF +BzAChidodHRwOi8vYWlhLmVudHJ1c3QubmV0L2wxay1jaGFpbjI1Ni5jZXIwMwYD +VR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbnRydXN0Lm5ldC9sZXZlbDFrLmNy +bDAfBgNVHREEGDAWghQyMDQ4dGVzdC5lbnRydXN0Lm5ldDAOBgNVHQ8BAf8EBAMC +BaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBMGA1UdIAQMMAowCAYG +Z4EMAQICMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdwA/F0tP1yJHWJQdZRyE +vg0S7ZA3fx+FauvBvyiF7PhkbgAAAYrx05lbAAAEAwBIMEYCIQDbMXKdzSr90jM+ +TekjpqVTEBDDvub7+AEx/kQYzf9gugIhAKPCjJmIh1NZrKkwK8MsOEL4jkN6FJ/h +4kiiJoze3fB/AHYAdv+IPwq2+5VRwmHM9Ye6NLSkzbsp3GhCCp/mZ0xaOnQAAAGK +8dOZVAAABAMARzBFAiAW11p7sV2byjrpk6AMQrMGwV2CuT3AKNuQVyxva7XQPAIh +AP1P7DfYsZ1aR12Tkg2x2BYjFrlsJCl36n5I/565xQk4AHUA2ra/az+1tiKfm8K7 +XGvocJFxbLtRhIU0vaQ9MEjX+6sAAAGK8dOZnwAABAMARjBEAiA43NURCcnHNpkH +XggwpVY9QYNIEAjpHEcPmyXJuQ9y8QIgPqx0MnlKXLuJVReuI5Hzc3iFtcYo070d +UYWH2AuVaFwwDQYJKoZIhvcNAQELBQADggEBAIZoSHApNF6DNYvGKHZJX411QkA0 +5zkq3dcm95BFomaqroEp1QeUeQ8e6xofUs84CURzopE9P81JBHX2Qzb/VeBzZOKy +dekaoz4NGW5ZvpMh7HXXaUpHKU/xZ5uUHVSatBU+cnidPhgn1czntqOwjzsgEZNW +/wbPEjqvIrZvAW4DPak/MSwlENys4ty5gX4453S5gwd18b+NFBq44O/FofR8bvWU +3lJ3VcVeONDzTcXPv+Yd1SlyO1/eXdWlFqloYFjkpcQ4wSLbOEeiWWITkZ0xCAxQ +j8uWuDOSyFQLpaPJvEuG1dlho7RZdor0flUIxYfqg2Nr4Svq1ezskwrdQm0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFKjCCBBKgAwIBAgIQLgRRzl0kJMcrXWV2cWUG2DANBgkqhkiG9w0BAQsFADCB +tDEUMBIGA1UEChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5l +dC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNV +BAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1 +c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw0yMjExMjUy +MTE5NDNaFw0yOTA3MjMwMDAwMDBaMIG6MQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +RW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2VlIHd3dy5lbnRydXN0Lm5ldC9sZWdh +bC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMTIgRW50cnVzdCwgSW5jLiAtIGZvciBh +dXRob3JpemVkIHVzZSBvbmx5MS4wLAYDVQQDEyVFbnRydXN0IENlcnRpZmljYXRp +b24gQXV0aG9yaXR5IC0gTDFLMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA2j+W0E25L0Tn2zlem1DuXKVh2kFnUwmqAJqOV38pa9vH4SEkqjrQjUcj0u1y +FvCRIdJdt7hLqIOPt5EyaM/OJZMssn2XyP7BtBe6CZ4DkJN7fEmDImiKm95HwzGY +ei59QAvS7z7Tsoyqj0ip/wDoKVgG97aTWpRzJiatWA7lQrjV6nN5ZGhTJbiEz5R6 +rgZFDKNrTdDGvuoYpDbwkrK6HIiPOlJ/915tgxyd8B/lw9bdpXiSPbBtLOrJz5RB +GXFEaLpHPATpXbo+8DX3Fbae8i4VHj9HyMg4p3NFXU2wO7GOFyk36t0FASK7lDYq +jVs1/lMZLwhGwSqzGmIdTivZGwIDAQABo4IBLjCCASowEgYDVR0TAQH/BAgwBgEB +/wIBADAdBgNVHQ4EFgQUgqJwdN28Uz/Pe9T3zX+nYMYKTL8wHwYDVR0jBBgwFoAU +VeSB0RGAvtiJuQijMfmhJAkWuXAwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzAB +hhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAyBgNVHR8EKzApMCegJaAjhiFodHRw +Oi8vY3JsLmVudHJ1c3QubmV0LzIwNDhjYS5jcmwwDgYDVR0PAQH/BAQDAgEGMB0G +A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA8BgNVHSAENTAzMDEGBFUdIAAw +KTAnBggrBgEFBQcCARYbaHR0cHM6Ly93d3cuZW50cnVzdC5uZXQvcnBhMA0GCSqG +SIb3DQEBCwUAA4IBAQAuAlHLO8CoKt2a4I23UDkKc7kQI3nUkWqq2RxRh8a/4TEF +C9WSF03EHVBW9JZZcrZ3ZdTDRsNF8vSqmCABz1FLu6vw3D3bEXELonAYlkmeFFV7 +1hiW9AdyMJD92XsXiU0Yr9J76Tk4iknMTTHiZXdZOcPMOXlMwPy++HS5tTIyqO0d +zl1PS8tlCcZrKaNNKbmiIWPhmBUSog9IQt2VKpoAIP8tlvRt5tHf5qW5m7vp7qmG +HF2ou54+qQIXO6jIP8CQ4xWvj0aiLklTNMkvXesaVq0xzNgRkx9ZzhREfbuM6eWc +GQHwG7m+JmfL+u1dCAZhh4Uyn5oLU9gogFM6v4jX +-----END CERTIFICATE----- diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustevca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustevca-chain.pem new file mode 100644 index 00000000000..e9c06b19c69 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustevca-chain.pem @@ -0,0 +1,79 @@ +Root Certificate: + Version: 3 (0x2) + Serial Number: 1164660820 (0x456b5054) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Entrust, Inc., OU=www.entrust.net/CPS is incorporated by reference, OU=(c) 2006 Entrust, Inc., CN=Entrust Root Certification Authority + Validity + Not Before: Nov 27 20:23:42 2006 GMT + Not After : Nov 27 20:53:42 2026 GMT + +-----BEGIN CERTIFICATE----- +MIIHEjCCBfqgAwIBAgIQFhH4VGskTR+tQK3JbN63kTANBgkqhkiG9w0BAQsFADCB +sTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsT +MHd3dy5lbnRydXN0Lm5ldC9ycGEgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5j +ZTEfMB0GA1UECxMWKGMpIDIwMDkgRW50cnVzdCwgSW5jLjEuMCwGA1UEAxMlRW50 +cnVzdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEwxRTAeFw0yNDA2MjgyMTQw +NDVaFw0yNTA3MjgyMTQwNDRaMIHIMQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250 +YXJpbzEPMA0GA1UEBxMGT3R0YXdhMRMwEQYLKwYBBAGCNzwCAQMTAkNBMRgwFgYL +KwYBBAGCNzwCAQITB09udGFyaW8xGDAWBgNVBAoTD0VudHJ1c3QgTGltaXRlZDEd +MBsGA1UEDxMUUHJpdmF0ZSBPcmdhbml6YXRpb24xEDAOBgNVBAUTBzE5MTM2MDUx +HDAaBgNVBAMTE3ZhbGlkZXYuZW50cnVzdC5uZXQwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDL2vkrBEZ5qeVdac1C01bcNnoeCU3AVU3Fh1Ifldic9/Gw +xqNVOFYQNzTk8M62FnPUvas4MnXmeBkPhhym+dnjsM22EeS2p6gTlvOGtJFVr+Ix +vq1UAKtqK0gYGriW6SexroSYiG1O0aeqEnKSLlEBHYhmacj2jlbx0ToxMfdBMRRq +4UjnIrh/CBochxt7aKv525tChnZGMT06QKAjx71w2cou0C05v83KJ75EI4EAmTfE +z9sKJeST5pH5MI3WKcP6ZmXynKYSIpIGb4Z8B9Ftp8HdzdR9EafOSlRlbIkEn3lm +nq4UCph48/PsUcJoViBCoY6zDLcPGt3gGQVIjq3vAgMBAAGjggMLMIIDBzAMBgNV +HRMBAf8EAjAAMB0GA1UdDgQWBBRF6MZkqXf3sICXuvbrBH1R9I8bAjAfBgNVHSME +GDAWgBRbQYqyxEPBvb/IVEFVneCWrf+5oTBlBggrBgEFBQcBAQRZMFcwIwYIKwYB +BQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDAGCCsGAQUFBzAChiRodHRw +Oi8vYWlhLmVudHJ1c3QubmV0L2wxZS1jaGFpbi5jZXIwMwYDVR0fBCwwKjAooCag +JIYiaHR0cDovL2NybC5lbnRydXN0Lm5ldC9sZXZlbDFlLmNybDAeBgNVHREEFzAV +ghN2YWxpZGV2LmVudHJ1c3QubmV0MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAU +BggrBgEFBQcDAQYIKwYBBQUHAwIwSwYDVR0gBEQwQjAHBgVngQwBATA3BgpghkgB +hvpsCgECMCkwJwYIKwYBBQUHAgEWG2h0dHBzOi8vd3d3LmVudHJ1c3QubmV0L3Jw +YTCCAX0GCisGAQQB1nkCBAIEggFtBIIBaQFnAHUAEvFONL1TckyEBhnDjz96E/jn +tWKHiJxtMAWE6+WGJjoAAAGQYMsp8gAABAMARjBEAiAL794Fw7wyzricvRl+2AON +FbGf2hwDB3wh8RkGLBRQ7AIgTCarii0atho7ZeUO3h66Ug7s7WxnF9onDZrtoMrH +U9MAdQAN4fIwK9MNwUBiEgnqVS78R3R8sdfpMO8OQh60fk6qNAAAAZBgyyoMAAAE +AwBGMEQCIFaXc4M9C9mNukrV68Sc2E5lw9srQ80nMBCGseY99nFxAiAppQmR9FKC +TE/ROlgZRfimx61W4k+SaQ52eek4JNWXXwB3ABoE/0nQVB1Ar/agw7/x2MRnL07s +7iNAaJhrF0Au3Il9AAABkGDLKi0AAAQDAEgwRgIhAPFUevU47H5uJqYL5y1ClFS7 +mEve7E8350JKnR1VykGLAiEArn7VAJcmRNNCDAegsHCCLlpasz9PLHFd9XHQAwvL +IFwwDQYJKoZIhvcNAQELBQADggEBAHfMCQP5Y+7IYzqOh5D/81WqHagmWOqkJYsN +33uux44fhVGqiG1O5ImTQsxJpt/HmDuK1qLEjG31Y9q89U91KAqLQauCQ5iMXrBg +TlwK8kzO1XYC5KkpO5ZWanqfjOahM9mkEKHPV9srwj6xTbInCq9DabRwuWyohj3b +EKrmB016TOT0hJ94jCb8PWl15oQJdsGlEfrG7amtDSRuoDHVA3nXJIJqx5LVnErB +glfsAmP8TPkWYY8kuNE2Rjr2M6P5LRLEvtRELCQF3lPuY0+xxGksGVM207YqhYKv +GzMmA8c7tF3ZclbE0rUA2T8FuBuweAV8tnWq2TaeAHWIJ4nY17s= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFHjCCBAagAwIBAgIRAIZmsCrBy1RAAAAAAFHTWJwwDQYJKoZIhvcNAQELBQAw +gbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkwNwYDVQQL +EzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVu +dHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xOTA2MTkxNjUy +MDhaFw0yNjExMTkxNzIyMDhaMIGxMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNRW50 +cnVzdCwgSW5jLjE5MDcGA1UECxMwd3d3LmVudHJ1c3QubmV0L3JwYSBpcyBpbmNv +cnBvcmF0ZWQgYnkgcmVmZXJlbmNlMR8wHQYDVQQLExYoYykgMjAwOSBFbnRydXN0 +LCBJbmMuMS4wLAYDVQQDEyVFbnRydXN0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gTDFFMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtlsEVHfdDiRm +3Cqh24DMXcdf/VIWWNpflAapuLa5YwxHIILsx5VOi7h3Umo9tYep1uHMdOWmyMDU +Vk+NLtYIPgxMQz7wQZNeRu8559llKgx2UCe9Ww0zMwfg96KpnOERM61m/NIseqqj +cxa+k4V1D9c3jPojt2T440xu7bMFveI223zedkTagnJ2tm7/lKHQhvcQzUpai7B1 +jGZSgE5ITEmDpkDXd4ETTV5yfkhGIqoP4j5llDjhcnH+SnEJujV/VYk9gdW4KAEQ +dzZaEIXSvWCEK0lhlAzeTEBqKsR5YIQkgjJpSphL4lYQugNFUSDTz9qOVBtFtnq6 +l5pa2MbRXwIDAQABo4IBLjCCASowDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG +CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUF +BwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVzdC5uZXQwMwYD +VR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbnRydXN0Lm5ldC9yb290Y2ExLmNy +bDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL3d3dy5l +bnRydXN0Lm5ldC9ycGEwHQYDVR0OBBYEFFtBirLEQ8G9v8hUQVWd4Jat/7mhMB8G +A1UdIwQYMBaAFGiQ5GekplOAx4ZmpPH3S0P7hL1tMA0GCSqGSIb3DQEBCwUAA4IB +AQAPUNBX97sqIXZl/zLu53iv7a0HK7prvD0cVaZM0yRfVptvARgjIZZzTtv32v6X +wSr4fDeRmpLaTWtipBGSqh3fNkTSVT8GGBq6+h1lrPEYv6jnStDf7VLQxVliKt2w +h34JjgRUx9rdia30tk/EpPavkxxPks8vjoLN3f4dbkIY/sfljyZbseqVLx9kl/we +OvqL6jZgaQOapFQLZJze7VwLiPVuUnW8ddK3JIE1a5YCZs0irIW5+96ttznIgPK2 +aUOmHQp/zasi7SFl49HrKGKWtZuyDB9U56e01H6PDTpSSSTPyLsSVg3JALHBPDzS +bBraAU3wuAyc3BQ4OIOmwwnT +-----END CERTIFICATE----- diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcaec1-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcaec1-chain.pem new file mode 100644 index 00000000000..8ea22c05b80 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcaec1-chain.pem @@ -0,0 +1,66 @@ +Root Certificate: + Version: 3 (0x2) + Serial Number: + a6:8b:79:29:00:00:00:00:50:d0:91:f9 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2012 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - EC1 + Validity + Not Before: Dec 18 15:25:36 2012 GMT + Not After : Dec 18 15:55:36 2037 GMT + +-----BEGIN CERTIFICATE----- +MIIFzDCCBVOgAwIBAgIQcbNJ8XJLeT3fV8DU3QNYSDAKBggqhkjOPQQDAzCBujEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1Nl +ZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDE2 +IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEuMCwGA1UE +AxMlRW50cnVzdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEwxSjAeFw0yNDA2 +MjgyMTM5MzVaFw0yNTA3MjgyMTM5MzRaMIHLMQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEPMA0GA1UEBxMGT3R0YXdhMRMwEQYLKwYBBAGCNzwCAQMTAkNB +MRgwFgYLKwYBBAGCNzwCAQITB09udGFyaW8xGDAWBgNVBAoTD0VudHJ1c3QgTGlt +aXRlZDEdMBsGA1UEDxMUUHJpdmF0ZSBPcmdhbml6YXRpb24xEzARBgNVBAUTCjEw +MDA0OTI4NzkxHDAaBgNVBAMTE3ZhbGlkZWMuZW50cnVzdC5uZXQwdjAQBgcqhkjO +PQIBBgUrgQQAIgNiAAS90ZyZ86Gl5Fh1qJ/70UwyQWATu3igiQLeVVvZ4G79SBEG +Xc4TcAn0LzBhfJonAzWFkAS860ARjvFHgUj0otyT+Q2/zC9c8CjOsL3bYp3SNUbC +FWBhIV0vhGGY8NafeXCjggMJMIIDBTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTP +DXJE/iZfi5wUSAo4GN4thBCCHDAfBgNVHSMEGDAWgBTD+UUDvsj5CzxFNfPrcuzn +6OuUmzBjBggrBgEFBQcBAQRXMFUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVu +dHJ1c3QubmV0MC4GCCsGAQUFBzAChiJodHRwOi8vYWlhLmVudHJ1c3QubmV0L2wx +ai1lYzEuY2VyMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW50cnVzdC5u +ZXQvbGV2ZWwxai5jcmwwHgYDVR0RBBcwFYITdmFsaWRlYy5lbnRydXN0Lm5ldDAO +BgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEsG +A1UdIAREMEIwBwYFZ4EMAQEwNwYKYIZIAYb6bAoBAjApMCcGCCsGAQUFBwIBFhto +dHRwczovL3d3dy5lbnRydXN0Lm5ldC9ycGEwggF9BgorBgEEAdZ5AgQCBIIBbQSC +AWkBZwB1AA3h8jAr0w3BQGISCepVLvxHdHyx1+kw7w5CHrR+Tqo0AAABkGDKGokA +AAQDAEYwRAIgZwtzml8YzKjqeP86zX+88q8sHOt//2Qmahr2tk97ozUCIFCOM2nF +s1GJVBjKQZEH8QqkivVp+Cai9pC/57TiOmCOAHUAzPsPaoVxCWX+lZtTzumyfCLp +hVwNl422qX5UwP5MDbAAAAGQYMoamAAABAMARjBEAiEA37X8EgQAUzLxn/Ny1Yx3 +uszQF5D85m8vZ0otf8nHzuwCH168zpAxzKS71Fz6CgmDS0QZOfBSYFBD+Pdcm6e1 +ilkAdwAS8U40vVNyTIQGGcOPP3oT+Oe1YoeInG0wBYTr5YYmOgAAAZBgyhq6AAAE +AwBIMEYCIQCljVuYzRe6oQTZPdx0tGhIQSOwM1JbxoMJu2cW+gEGLAIhAMSSJoni +0KT3KavwtsSWuuHsWjt8atv6TpJtLmVxCIdlMAoGCCqGSM49BAMDA2cAMGQCMBPY +1dn1Js8F9b08aVCZ3vqDGFTKuzTXaxArf/y/WhLtcHdZPLaYVifQcAKzp1WCFQIw +MvpE6RDccmnZi5TX88p16s8ev/qkegpbf7Xuw1JQEfy2NRwrXc+NwA422EjXBTti +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID5zCCA2ygAwIBAgIQCoPUgD5+n1EAAAAAUdTB9zAKBggqhkjOPQQDAzCBvzEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1Nl +ZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEy +IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UE +AxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4X +DTE2MDQwNTIwMTk1NFoXDTM3MTAwNTIwNDk1NFowgboxCzAJBgNVBAYTAlVTMRYw +FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu +bmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNiBFbnRydXN0LCBJbmMu +IC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxLjAsBgNVBAMTJUVudHJ1c3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgLSBMMUowdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AAT14eFXmpQX/dEf7NAxrMH13n0btz1KKvH2S1rROGPAKex2CY8yxznbffK/MbCk +F7ByYXGs1+8kL5xmTysU/c+YmjOZx2mMSAk2DPw30fijJ3tRrwChZ+TBpgtB6+A5 +MsCjggEuMIIBKjAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAz +BggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3Qu +bmV0MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW50cnVzdC5uZXQvZWMx +cm9vdC5jcmwwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6 +Ly93d3cuZW50cnVzdC5uZXQvcnBhMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF +BQcDAjAdBgNVHQ4EFgQUw/lFA77I+Qs8RTXz63Ls5+jrlJswHwYDVR0jBBgwFoAU +t2PnGt2N6QimVYOk4GpQQWURQkkwCgYIKoZIzj0EAwMDaQAwZgIxAPnVAOqxKDd7 +v37EBmpPqWCCWBFPKW6HpRx3GUWc9caeQIw8rO2HXYgf92pb/TsJYAIxAJhI0MpR +z5L42xF1R9UIPfQxCMwgsnWBqIqcfMrMO+2DxQy6GIP3cFFj9gRyxguKWw== +-----END CERTIFICATE----- diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcag2-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcag2-chain.pem new file mode 100644 index 00000000000..5fcbf9ffc2c --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcag2-chain.pem @@ -0,0 +1,80 @@ +Root Certificate: + Version: 3 (0x2) + Serial Number: 1246989352 (0x4a538c28) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2009 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G2 + Validity + Not Before: Jul 7 17:25:54 2009 GMT + Not After : Dec 7 17:55:54 2030 GMT + +-----BEGIN CERTIFICATE----- +MIIHOzCCBiOgAwIBAgIQWFfRPoYcAxEc+S0tOlD+ljANBgkqhkiG9w0BAQsFADCB +ujELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsT +H1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAy +MDE0IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEuMCwG +A1UEAxMlRW50cnVzdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEwxTTAeFw0y +NDA2MjgyMTQyMTRaFw0yNTA3MjgyMTQyMTNaMIHLMQswCQYDVQQGEwJDQTEQMA4G +A1UECBMHT250YXJpbzEPMA0GA1UEBxMGT3R0YXdhMRMwEQYLKwYBBAGCNzwCAQMT +AkNBMRgwFgYLKwYBBAGCNzwCAQITB09udGFyaW8xGDAWBgNVBAoTD0VudHJ1c3Qg +TGltaXRlZDEdMBsGA1UEDxMUUHJpdmF0ZSBPcmdhbml6YXRpb24xEzARBgNVBAUT +CjEwMDA0OTI4NzkxHDAaBgNVBAMTE3ZhbGlkZzIuZW50cnVzdC5uZXQwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCZ66eWZS5ytmbHJeHcA9WfnpbGFC04 +Tov7L0NWiStVRPEFrXrGSn6RPriGci6RwrCz5yn47EWjk2AjSD4e5lySDKHwTg+0 +S9pl3lcSd8tQOTbTwVM0EfOxdUlO4IY0jCOSM8rnZUc1JvEIIrXWXWF9AWoDb4BQ +erTefRm/YykFC558PEzn84vU9KoEmDwIP4upWKVutuzBpHWhZW3q9wagg62KifHN +1yaagv4PUGgdkrVkyA1ZO3D7b2RpQjBreOTk+tsTnWtbAkFGtRBOA/2QrEvyqMU7 +eCnpFZMIaj2tKeSLqhIWxzOnrAGUJNp5wLYmVnnhPhHEv1g79pNsZLR3AgMBAAGj +ggMoMIIDJDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRt85gfkWUjfTKgrLytMp8o +VvOe3zAfBgNVHSMEGDAWgBTD99C1KjCtrw2RIXA5VN28iXDHOjBoBggrBgEFBQcB +AQRcMFowIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDMGCCsG +AQUFBzAChidodHRwOi8vYWlhLmVudHJ1c3QubmV0L2wxbS1jaGFpbjI1Ni5jZXIw +MwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5lbnRydXN0Lm5ldC9sZXZlbDFt +LmNybDA3BgNVHREEMDAughN2YWxpZGcyLmVudHJ1c3QubmV0ghd3d3cudmFsaWRn +Mi5lbnRydXN0Lm5ldDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUH +AwEGCCsGAQUFBwMCMEsGA1UdIAREMEIwBwYFZ4EMAQEwNwYKYIZIAYb6bAoBAjAp +MCcGCCsGAQUFBwIBFhtodHRwczovL3d3dy5lbnRydXN0Lm5ldC9ycGEwggF+Bgor +BgEEAdZ5AgQCBIIBbgSCAWoBaAB3ABLxTjS9U3JMhAYZw48/ehP457Vih4icbTAF +hOvlhiY6AAABkGDMhQQAAAQDAEgwRgIhAMzddgbnWlodtosz6EMh2Y89n0JR4eMO +v+W6tUp2gVwYAiEA6UKa2eFlX0KdzuZCvTlPgi8DeK3ZI2wffyV2bYMXtsIAdgAN +4fIwK9MNwUBiEgnqVS78R3R8sdfpMO8OQh60fk6qNAAAAZBgzIURAAAEAwBHMEUC +IQDmVH2NlaV2/Y3OaPMXhH+BT63zA+Bh/5aCfPiYrJ7K2AIgRADPHzpwS7bfvVZI +k8QxUBSCDXFmZQOrpamBaEko6YIAdQDM+w9qhXEJZf6Vm1PO6bJ8IumFXA2Xjbap +flTA/kwNsAAAAZBgzIUGAAAEAwBGMEQCIA1CHfNw7cCcJSb3s7ik9Wflf3irqE9G +QKxZ+Y9BOIx0AiA6CMvw7OHjG519E1tZgr/HFRXzxKchBp80dfsaEKxY9zANBgkq +hkiG9w0BAQsFAAOCAQEAqvn1CTObiV5zKVY6NWjGK49Wqsr9t1ok/h/yfKRmr36O +UZkMTPANj0uhwM4gtieTze9hnNzEkx1ec6G40JyABRiSX+0dtq3n8wiW3d8G1Qj5 +/s8yZ13/ATrdjjr1mlGOvh0sgWTTPaQpl8ijXTy40GYpZIUXXBK09Rm6W0siq+7m +OHNpJR4APWOBBU4QwiWrHHsFq4KvwxiTjNWWizCOnZwVi3awNBoDD/Iwszn+trOA +8U/1SsHGuPBWKajcGorwi2zQ99JxAwJJ8XNBCekynjbPZYx52KkqfR07Fd2Occbl +3lh3wXrepzzU1a6vdyiQpagX8btyIqQpAzytypzaLQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFLTCCBBWgAwIBAgIMYaHn0gAAAABR02amMA0GCSqGSIb3DQEBCwUAMIG+MQsw +CQYDVQQGEwJVUzEWMBQGA1UEChMNRW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2Vl +IHd3dy5lbnRydXN0Lm5ldC9sZWdhbC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMDkg +RW50cnVzdCwgSW5jLiAtIGZvciBhdXRob3JpemVkIHVzZSBvbmx5MTIwMAYDVQQD +EylFbnRydXN0IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjAeFw0x +NDEyMTUxNTI1MDNaFw0zMDEwMTUxNTU1MDNaMIG6MQswCQYDVQQGEwJVUzEWMBQG +A1UEChMNRW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2VlIHd3dy5lbnRydXN0Lm5l +dC9sZWdhbC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMTQgRW50cnVzdCwgSW5jLiAt +IGZvciBhdXRob3JpemVkIHVzZSBvbmx5MS4wLAYDVQQDEyVFbnRydXN0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5IC0gTDFNMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA0IHBOSPCsdHs91fdVSQ2kSAiSPf8ylIKsKs/M7WwhAf23056sPuY +Ij0BrFb7cW2y7rmgD1J3q5iTvjOK64dex6qwymmPQwhqPyK/MzlG1ZTy4kwFItln +gJHxBEoOm3yiydJs/TwJhL39axSagR3nioPvYRZ1R5gTOw2QFpi/iuInMlOZmcP7 +lhw192LtjL1JcdJDQ6Gh4yEqI3CodT2ybEYGYW8YZ+QpfrI8wcVfCR5uRE7sIZlY +FUj0VUgqtzS0BeN8SYwAWN46lsw53GEzVc4qLj/RmWLoquY0djGqr3kplnjLgRSv +adr7BLlZg0SqCU+01CwBnZuUMWstoc/B5QIDAQABo4IBKzCCAScwDgYDVR0PAQH/ +BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8E +CDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29j +c3AuZW50cnVzdC5uZXQwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL2NybC5lbnRy +dXN0Lm5ldC9nMmNhLmNybDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggrBgEFBQcC +ARYaaHR0cDovL3d3dy5lbnRydXN0Lm5ldC9ycGEwHQYDVR0OBBYEFMP30LUqMK2v +DZEhcDlU3byJcMc6MB8GA1UdIwQYMBaAFGpyJnrQHu995ztpUdRsjZ+QEmarMA0G +CSqGSIb3DQEBCwUAA4IBAQC0h8eEIhopwKR47PVPG7SEl2937tTPWa+oQ5YvHVje +pvMVWy7ZQ5xMQrkXFxGttLFBx2YMIoYFp7Qi+8VoaIqIMthx1hGOjlJ+Qgld2dnA +DizvRGsf2yS89byxqsGK5Wbb0CTz34mmi/5e0FC6m3UAyQhKS3Q/WFOv9rihbISY +Jnz8/DVRZZgeO2x28JkPxLkJ1YXYJKd/KsLak0tkuHB8VCnTglTVz6WUwzOeTTRn +4Dh2ZgCN0C/GqwmqcvrOLzWJ/MDtBgO334wlV/H77yiI2YIowAQPlIFpI+CRKMVe +1QzX1CA778n4wI+nQc1XRG5sZ2L+hN/nYNjvv9QiHg3n +-----END CERTIFICATE----- diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcag4-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcag4-chain.pem new file mode 100644 index 00000000000..e649abf28b3 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcag4-chain.pem @@ -0,0 +1,92 @@ +Root Certificate: + Version: 3 (0x2) + Serial Number: + d9:b5:43:7f:af:a9:39:0f:00:00:00:00:55:65:ad:58 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2015 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G4 + Validity + Not Before: May 27 11:11:16 2015 GMT + Not After : Dec 27 11:41:16 2037 GMT + +-----BEGIN CERTIFICATE----- +MIIIIzCCBwugAwIBAgIQDD4I8FgD7+DVcBLMBwa39jANBgkqhkiG9w0BAQsFADCB +ujELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsT +H1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAy +MDE0IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEuMCwG +A1UEAxMlRW50cnVzdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEwxTjAeFw0y +NDA2MjgyMTQzNTRaFw0yNTA3MjgyMTQzNTNaMIHLMQswCQYDVQQGEwJDQTEQMA4G +A1UECBMHT250YXJpbzEPMA0GA1UEBxMGT3R0YXdhMRMwEQYLKwYBBAGCNzwCAQMT +AkNBMRgwFgYLKwYBBAGCNzwCAQITB09udGFyaW8xGDAWBgNVBAoTD0VudHJ1c3Qg +TGltaXRlZDEdMBsGA1UEDxMUUHJpdmF0ZSBPcmdhbml6YXRpb24xEzARBgNVBAUT +CjEwMDA0OTI4NzkxHDAaBgNVBAMTE3ZhbGlkZzQuZW50cnVzdC5uZXQwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCfUHGdeme0jraIiUzPYtuX1G9rlCU1 +eKDqDbsgp7VIS7rI/VgbsS7oKnE6KHP+qGrXRhYdvFLFDa+REY6fVOWkLuTXhVLb +5C7ym2pi0OUMKvrGtDLUxlHiEAmkmjPDl6TLMTDrLgWOLFMRzyeTcxnZtMrxUnAf +yzSPlqm1bkN/oRp2EOiXvuSbci8UA0QswV6g8EUbRB0qyv6OophoaQYo/+KRwTJT +k6S8YDsEJnlDb8tjEhfIUjp2Md5ThBxf5Ib29aXebZ5HFh2x5VPrzOwDUPk0fVNM +pWFfiX79RW6w5Vei5qtretLohbw6b5aJmaJ1LweAEkIlhy5eUuuG6v8Efm8JSAle +eKMtflTigmayaWMVCd2GeB6LajcflAw7BUU2brRMJwMpaeXXhL/mVpjbev/5TtVD ++H9IlW3PMyQnUJc0YuUVmdi1eOM5qoQaQE4BDPHz2G41eDgT8J9Gb1FX5mT+9l2I +iJD47pwcBIw5tHCn2nuz1+8CDuYpfH2+t2LPFHVI15h1scGotZvzUJ5TzPdQqZI7 +K2LTL49Zs2HsObrGr07Vj28WyzkjIfTrVSV/29hgz1zVjUa0uyTeOzrc3VIg7NTv +RoMTTYuUeUoMSmFQ8z9CSGh7cxFlrhGjFO+66++JFNwakAEp7kS5c2qTLaapY9dM +8UMIr5951z994QIDAQABo4IDEDCCAwwwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU +/EjjpmMa/SepMqPlglXS5AbGcScwHwYDVR0jBBgwFoAU7kfRhXHx/S23P7s+Y1h3 +F0lADpUwaAYIKwYBBQUHAQEEXDBaMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5l +bnRydXN0Lm5ldDAzBggrBgEFBQcwAoYnaHR0cDovL2FpYS5lbnRydXN0Lm5ldC9s +MW4tY2hhaW4yNTYuY2VyMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW50 +cnVzdC5uZXQvbGV2ZWwxbi5jcmwwHgYDVR0RBBcwFYITdmFsaWRnNC5lbnRydXN0 +Lm5ldDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF +BwMBMEsGA1UdIAREMEIwBwYFZ4EMAQEwNwYKYIZIAYb6bAoBAjApMCcGCCsGAQUF +BwIBFhtodHRwczovL3d3dy5lbnRydXN0Lm5ldC9ycGEwggF/BgorBgEEAdZ5AgQC +BIIBbwSCAWsBaQB2ABLxTjS9U3JMhAYZw48/ehP457Vih4icbTAFhOvlhiY6AAAB +kGDOC9YAAAQDAEcwRQIgWhFWhf2sBQ3ufMH0yubwLDt+3f/b5rScs09o1YEjg6MC +IQDpkgEMWBAM+NV2aCnC8QH+RH6xBqhPPt6JZTm3W+vHkwB3ABoE/0nQVB1Ar/ag +w7/x2MRnL07s7iNAaJhrF0Au3Il9AAABkGDODBQAAAQDAEgwRgIhAOgp+oas+jBr +9wOBo0QDdVQGmP8KJupfRf/MDKO+kSRjAiEA9JnEHTbFHre2TS9habVJA/3jM/t5 +CKtixwQqdpLXQUAAdgAN4fIwK9MNwUBiEgnqVS78R3R8sdfpMO8OQh60fk6qNAAA +AZBgzgwVAAAEAwBHMEUCIBOYI8rl87VepcPQlaGh6AbKhKw1UlbxIf7etR/d2M47 +AiEAkFXOVvzkP6kX/z1yRneYn0mlPbDvAFLsSDghl/gkdtYwDQYJKoZIhvcNAQEL +BQADggEBAJovgoheNHFBUpnodfOiKtpRo8AE6dLuOX1H2uRHiDg0Gza0/w95KkEE +BqjKmJIbJrs2TQJnkM0LjaubHn1TP4XC40qieMXB4ylJzC5FWDZBqMHZmLTvVY01 +irBMyub0On8d1BlEquD2r3KHQFnyUvi/uxzbNJOVbNJYglKhTI+UfcXk7zpHmNG+ ++SbBkpJkuqQ9ujG1K25FRa/01j1p4ZlDrJ3KCT7fDEf10TN0u5VX6moVT9cRVR2U +gX16BV8m/hoJVTD0fBCKIKjtklS//b+Jr49uxWFulrDwlRKyDWmBXLnqsZvpCobi +deDsWiUkcvd+DjNgpDTEHCTrXXjd8tU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGMjCCBBqgAwIBAgIRAKvsd/8bQQwHAAAAAFVl2AUwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE3MTEyMjIwMDQyMFoXDTMwMTIyMjIwMzQyMFowgboxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNCBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxLjAsBgNVBAMTJUVudHJ1c3Qg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBMMU4wggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDcSG+caYQ4xcvf+dt8bgCEHorO0g5j0H1NOtQzRXgUoG8y +QuRbJX9swyKqQZbsc18YvTV8OKA/uSNE46Jvq47TFPojWWTVLbNDqpM07e4EFYKs +A9NFzAUngijnf3ivnXA6iNPAMXaEhXmhY/YFjk8NoM7Y1PFsA0oj5hamKQ06iO/j +gvBScLmnQ1ju9Qj9IGIg18UL5AJNw0frspLUQBYVrLGaqAy5Nl2BUJKaZ4vnSLvP +nk6YrB15mo1phHae10Ba4fx7R3z8IZ/hby4OXTy/KZpu107VEQPAwTuDK8ZXxB5y +0DSzi4vaw27aLrUsq4aFqUo03gEfC31vWW76TNkFAgMBAAGjggErMIIBJzAOBgNV +HQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEF +BQcDAQYIKwYBBQUHAwIwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEW +Gmh0dHA6Ly93d3cuZW50cnVzdC5uZXQvcnBhMDMGCCsGAQUFBwEBBCcwJTAjBggr +BgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVzdC5uZXQwMAYDVR0fBCkwJzAloCOg +IYYfaHR0cDovL2NybC5lbnRydXN0Lm5ldC9nNGNhLmNybDAdBgNVHQ4EFgQU7kfR +hXHx/S23P7s+Y1h3F0lADpUwHwYDVR0jBBgwFoAUnzjEViPDOeigcWzoVEzk6Dqx +v2cwDQYJKoZIhvcNAQELBQADggIBACMeFFgsWmC7h6D1v8DJUkOpm/m5UhVhO0hb +pQMQKMhKkl744Y9SWG4WNmpQy743TTciEJPZFhc7ke2R6VmK8ZJUqro2awOw1RWZ +OtHla59Btf1NQd41vOVdU+qFhs8lFfXg9sK7YHTrfxHtMXLoGnkkamK3xJgn7sXa +/zUvUDBTpDCXcpO9SyHoKIQswmkIPpRyIdPF4biRdR3N+9MYmlfqN/Nk3OEZ73xZ +AUZP6Gu+f9cEiHTA8NdYHCPLJWyFnIHWK+QuTFEnKYnOYxCeroLBNOO64e8JWZ39 +kZ22BBXhHzqOCCczS7JOJTRF+JgvWuxbFwRstj8qf3fE+JndWmq2FC4hTHtpuK5K +ENuiRm5gdkXfsXmB+qB6y5gaajiTIMscGIcZIKTe2YdKrLoicvEz8k+loM7favik +vzFioTNTDHYGx3mkfElBE7ycY8n+jZE3QBBv33k28MeQi7XNgEaMc4tYwoZIdE9A +xVccXTzEQzka82dOkRB1dU0XZId9XAWv+CtNc2TjF6Wgx2seA/c6H8S0IfgQBIV2 +8iN2wZns2QFdawkdy3hMUqPnA++kuGhLW3GemsIY5dP/WxY8rd+OfLb/Ks9T1pCd +28t7PQRcQsgkYmouzrOW9ASBvYqLLdhl4y+fFXff8RkPIKMNoYP06WJvRKmky9R/ +41/nXRas +-----END CERTIFICATE----- diff --git a/test/jdk/sun/security/util/Debug/DebugOptions.java b/test/jdk/sun/security/util/Debug/DebugOptions.java new file mode 100644 index 00000000000..a52566e7aeb --- /dev/null +++ b/test/jdk/sun/security/util/Debug/DebugOptions.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8051959 + * @summary Option to print extra information in java.security.debug output + * @library /test/lib + * @run junit DebugOptions + */ + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.security.KeyStore; +import java.security.Security; +import java.util.stream.Stream; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class DebugOptions { + + static final String DATE_REGEX = "\\d{4}-\\d{2}-\\d{2}"; + + private static Stream patternMatches() { + return Stream.of( + // no extra info present + Arguments.of("properties", + "properties: Initial", + "properties\\["), + // thread info only + Arguments.of("properties+thread", + "properties\\[.*\\|main\\|.*java.*]:", + "properties\\[" + DATE_REGEX), + // timestamp info only + Arguments.of("properties+timestamp", + "properties\\[" + DATE_REGEX + ".*\\]", + "\\|main\\]:"), + // both thread and timestamp + Arguments.of("properties+timestamp+thread", + "properties\\[.*\\|main|" + DATE_REGEX + ".*\\]:", + "properties:"), + // flip the arguments of previous test + Arguments.of("properties+thread+timestamp", + "properties\\[.*\\|main|" + DATE_REGEX + ".*\\]:", + "properties:"), + // comma not valid separator, ignore extra info printing request + Arguments.of("properties,thread,timestamp", + "properties:", + "properties\\[.*\\|main|" + DATE_REGEX + ".*\\]:"), + // no extra info for keystore debug prints + Arguments.of("properties+thread+timestamp,keystore", + "properties\\[.*\\|main|" + DATE_REGEX + ".*\\]:", + "keystore\\["), + // flip arguments around in last test - same outcome expected + Arguments.of("keystore,properties+thread+timestamp", + "properties\\[.*\\|main|" + DATE_REGEX + ".*\\]:", + "keystore\\["), + // turn on thread info for both keystore and properties components + Arguments.of("keystore+thread,properties+thread", + "properties\\[.*\\|main|.*\\Rkeystore\\[.*\\|main|.*\\]:", + "\\|" + DATE_REGEX + ".*\\]:"), + // same as above with erroneous comma at end of string. same output expected + Arguments.of("keystore+thread,properties+thread,", + "properties\\[.*\\|main|.*\\Rkeystore\\[.*\\|main|.*\\]:", + "\\|" + DATE_REGEX + ".*\\]:"), + // turn on thread info for properties and timestamp for keystore + Arguments.of("keystore+timestamp,properties+thread", + "properties\\[.*\\|main|.*\\Rkeystore\\[" + DATE_REGEX + ".*\\]:", + "properties\\[.*\\|" + DATE_REGEX + ".*\\]:"), + // turn on thread info for all components + Arguments.of("all+thread", + "properties\\[.*\\|main.*((.*\\R)*)keystore\\[.*\\|main.*java.*\\]:", + "properties\\[" + DATE_REGEX + ".*\\]:"), + // turn on thread info and timestamp for all components + Arguments.of("all+thread+timestamp", + "properties\\[.*\\|main.*\\|" + DATE_REGEX + + ".*\\]((.*\\R)*)keystore\\[.*\\|main.*\\|" + DATE_REGEX + ".*\\]:", + "properties:"), + // all decorator option should override other component options + Arguments.of("all+thread+timestamp,properties", + "properties\\[.*\\|main.*\\|" + DATE_REGEX + + ".*\\]((.*\\R)*)keystore\\[.*\\|main.*\\|" + DATE_REGEX + ".*\\]:", + "properties:"), + // thread details should only be printed for properties option + Arguments.of("properties+thread,all", + "properties\\[.*\\|main\\|.*\\]:", + "keystore\\[.*\\|main\\|.*\\]:"), + // thread details should be printed for all statements + Arguments.of("properties,all+thread", + "properties\\[.*\\|main.*java" + + ".*\\]((.*\\R)*)keystore\\[.*\\|main.*java.*\\]:", + "properties:") + ); + } + + @ParameterizedTest + @MethodSource("patternMatches") + public void shouldContain(String params, String expected, String notExpected) throws Exception { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava( + "-Djava.security.debug=" + params, + "DebugOptions" + ); + outputAnalyzer.shouldHaveExitValue(0) + .shouldMatch(expected) + .shouldNotMatch(notExpected); + } + + public static void main(String[] args) throws Exception { + // something to trigger "properties" debug output + Security.getProperty("test"); + // trigger "keystore" debug output + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + } +} diff --git a/test/jdk/tools/launcher/Settings.java b/test/jdk/tools/launcher/Settings.java index 29af50d5c02..36ae06640a1 100644 --- a/test/jdk/tools/launcher/Settings.java +++ b/test/jdk/tools/launcher/Settings.java @@ -25,7 +25,7 @@ /* * @test - * @bug 6994753 7123582 8305950 8281658 + * @bug 6994753 7123582 8305950 8281658 8310201 * @summary tests -XshowSettings options * @modules jdk.compiler * jdk.zipfs @@ -67,6 +67,9 @@ static void checkNotContains(TestResult tr, String str) { private static final String VM_SETTINGS = "VM settings:"; private static final String PROP_SETTINGS = "Property settings:"; private static final String LOCALE_SETTINGS = "Locale settings:"; + private static final String LOCALE_SUMMARY_SETTINGS = + "Locale settings summary:"; + private static final String AVAILABLE_LOCALES = "available locales"; private static final String SEC_PROPS_SETTINGS = "Security properties:"; private static final String SEC_SUMMARY_PROPS_SETTINGS = "Security settings summary:"; @@ -81,7 +84,9 @@ static void checkNotContains(TestResult tr, String str) { static void containsAllOptions(TestResult tr) { checkContains(tr, VM_SETTINGS); checkContains(tr, PROP_SETTINGS); - checkContains(tr, LOCALE_SETTINGS); + checkNotContains(tr, LOCALE_SETTINGS); + checkNotContains(tr, AVAILABLE_LOCALES); + checkContains(tr, LOCALE_SUMMARY_SETTINGS); // no verbose security settings unless "security" used checkNotContains(tr, SEC_PROPS_SETTINGS); checkContains(tr, SEC_SUMMARY_PROPS_SETTINGS); @@ -153,6 +158,8 @@ static void runTestOptionLocale() throws IOException { checkNotContains(tr, VM_SETTINGS); checkNotContains(tr, PROP_SETTINGS); checkContains(tr, LOCALE_SETTINGS); + checkContains(tr, AVAILABLE_LOCALES); + checkNotContains(tr, LOCALE_SUMMARY_SETTINGS); checkContains(tr, TZDATA_SETTINGS); } diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index b4b79fab23a..af285a2bafa 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,6 @@ import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.foreign.CABI; @@ -84,10 +83,6 @@ public void put(String key, Supplier s) { } map.put(key, value); } - - public void putAll(Map map) { - map.entrySet().forEach(e -> put(e.getKey(), () -> e.getValue())); - } } /** @@ -107,6 +102,7 @@ public Map call() { map.put("vm.simpleArch", this::vmArch); map.put("vm.debug", this::vmDebug); map.put("vm.jvmci", this::vmJvmci); + map.put("vm.jvmci.enabled", this::vmJvmciEnabled); map.put("vm.emulatedClient", this::vmEmulatedClient); // vm.hasSA is "true" if the VM contains the serviceability agent // and jhsdb. @@ -135,7 +131,6 @@ public Map call() { map.put("jdk.containerized", this::jdkContainerized); map.put("vm.flagless", this::isFlagless); map.put("jdk.foreign.linker", this::jdkForeignLinker); - map.putAll(xOptFlags()); // -Xmx4g -> @requires vm.opt.x.Xmx == "4g" ) vmGC(map); // vm.gc.X = true/false vmGCforCDS(map); // may set vm.gc vmOptFinalFlags(map); @@ -272,6 +267,20 @@ protected String vmJvmci() { return "true"; } + + /** + * @return true if JVMCI is enabled + */ + protected String vmJvmciEnabled() { + // builds with jvmci have this flag + if ("false".equals(vmJvmci())) { + return "false"; + } + + return "" + Compiler.isJVMCIEnabled(); + } + + /** * @return true if VM runs in emulated-client mode and false otherwise. */ @@ -683,27 +692,6 @@ private Stream allFlags() { return Stream.of((System.getProperty("test.vm.opts", "") + " " + System.getProperty("test.java.opts", "")).trim().split("\\s+")); } - /** - * Parses extra options, options that start with -X excluding the - * bare -X option (as it is not considered an extra option). - * Ignores extra options not starting with -X - * - * This could be improved to handle extra options not starting - * with -X as well as "standard" options. - */ - private Map xOptFlags() { - return allFlags() - .filter(s -> s.startsWith("-X") && !s.startsWith("-XX:") && !s.equals("-X")) - .map(s -> s.replaceFirst("-", "")) - .map(flag -> flag.splitWithDelimiters("[:0123456789]", 2)) - .collect(Collectors.toMap(a -> "vm.opt.x." + a[0], - a -> (a.length == 1) - ? "true" // -Xnoclassgc - : (a[1].equals(":") - ? a[2] // ["-XshowSettings", ":", "system"] - : a[1] + a[2]))); // ["-Xmx", "4", "g"] - } - /* * A string indicating the foreign linker that is currently being used. See jdk.internal.foreign.CABI * for valid values. diff --git a/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java b/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java index 48106face35..d8539b8c656 100644 --- a/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java +++ b/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java @@ -30,7 +30,7 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.compiler/jdk.internal.shellsupport.doc * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask - * @run testng/timeout=900/othervm JavadocHelperTest + * @run testng/timeout=900/othervm -Xmx1024m JavadocHelperTest */ import java.io.IOException; diff --git a/test/langtools/jdk/javadoc/doclet/testBreakIterator/TestBreakIterator.java b/test/langtools/jdk/javadoc/doclet/testBreakIterator/TestBreakIterator.java index 72b1336dc59..31f1d3a66da 100644 --- a/test/langtools/jdk/javadoc/doclet/testBreakIterator/TestBreakIterator.java +++ b/test/langtools/jdk/javadoc/doclet/testBreakIterator/TestBreakIterator.java @@ -23,7 +23,7 @@ /* * @test - * @bug 4165985 + * @bug 4165985 8326332 * @summary Determine the end of the first sentence using BreakIterator. * If the first sentence of "method" is parsed correctly, the test passes. * Correct Answer: "This is a class (i.e. it is indeed a class)." @@ -76,5 +76,10 @@ public void test() { """
    A constant indicating that the keyLocation is indeterminate or not relevant.
    """); + + checkOutput("pkg/BreakIteratorTest.html", true, + """ + """); } } diff --git a/test/langtools/jdk/javadoc/doclet/testBreakIterator/pkg/BreakIteratorTest.java b/test/langtools/jdk/javadoc/doclet/testBreakIterator/pkg/BreakIteratorTest.java index 9370d162808..3ea965377f6 100644 --- a/test/langtools/jdk/javadoc/doclet/testBreakIterator/pkg/BreakIteratorTest.java +++ b/test/langtools/jdk/javadoc/doclet/testBreakIterator/pkg/BreakIteratorTest.java @@ -56,4 +56,9 @@ public void foobar(){} */ public void fe(){} + /** + * Inline tags extending + * beyond the first sentence. Tags are closed here. + */ + public void meh(){} } diff --git a/test/langtools/jdk/javadoc/doclet/testClassTree/TestClassTree.java b/test/langtools/jdk/javadoc/doclet/testClassTree/TestClassTree.java index 52a0e3ff55c..980a8622fa4 100644 --- a/test/langtools/jdk/javadoc/doclet/testClassTree/TestClassTree.java +++ b/test/langtools/jdk/javadoc/doclet/testClassTree/TestClassTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. * 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,26 +23,79 @@ /* * @test - * @bug 4632553 4973607 8026567 + * @bug 4632553 4973607 8026567 8242564 * @summary No need to include type name (class, interface, etc.) before * every single type in class tree. * Make sure class tree includes heirarchy for enums and annotation * types. - * @library ../../lib + * Make sure class tree handles undefined types in the class + * hierarchy. + * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool - * @build javadoc.tester.* + * @build toolbox.ToolBox javadoc.tester.* * @run main TestClassTree */ +import java.io.IOException; +import java.nio.file.Path; + import javadoc.tester.JavadocTester; +import toolbox.ToolBox; public class TestClassTree extends JavadocTester { + private final ToolBox tb = new ToolBox(); + public static void main(String... args) throws Exception { var tester = new TestClassTree(); tester.runTests(); } + /** + * Given badpkg package containing class ChildClass with UndefinedClass + * base class, implementing UndefinedInterface and a defined + * interface + * When the javadoc is generated with '--ignore-source-errors option' + * Then javadoc exits successfully + * And generates html for the ChildClass with UndefinedClass base class + * And UndefinedInterface is not present in html + */ + @Test + public void testBadPkg(Path base) throws IOException { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + """ + package badpkg; + public class ChildClass extends UndefinedClass + implements UndefinedInterface, Iterable { + + } + """ + ); + + javadoc("--ignore-source-errors", + "-d", base.resolve("badout").toString(), + "--no-platform-links", + "-sourcepath", src.toString(), + "badpkg"); + + + checkExit(Exit.OK); + checkOutput("badpkg/package-tree.html", true, + """ +
  • badpkg.ChildClass (implements java.lang.Iterable<T>)
  • + """); + checkOutput("badpkg/ChildClass.html", true, + """ +
    public class \ + ChildClass + extends UndefinedClass + implements java.lang.Iterable
    + """); + checkOutput("badpkg/ChildClass.html", false, "UndefinedInterface"); + } + @Test public void test() { javadoc("-d", "out", diff --git a/test/langtools/jdk/javadoc/doclet/testIOException/TestIOException.java b/test/langtools/jdk/javadoc/doclet/testIOException/TestIOException.java index 9127cdf86bb..5dd81b62d33 100644 --- a/test/langtools/jdk/javadoc/doclet/testIOException/TestIOException.java +++ b/test/langtools/jdk/javadoc/doclet/testIOException/TestIOException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,9 +23,9 @@ /* * @test - * @bug 8164130 + * @bug 8164130 8334332 * @summary test IOException handling - * @library ../../lib + * @library ../../lib /test/lib * @modules jdk.javadoc/jdk.javadoc.internal.tool * @build javadoc.tester.* * @run main TestIOException @@ -39,6 +39,7 @@ import java.util.Map; import javadoc.tester.JavadocTester; +import jtreg.SkippedException; /** * Tests IO Exception handling. @@ -61,16 +62,13 @@ public static void main(String... args) throws Exception { public void testReadOnlyDirectory() { File outDir = new File("out1"); if (!outDir.mkdir()) { - throw error(outDir, "Cannot create directory"); + throw skip(outDir, "Cannot create directory"); } if (!outDir.setReadOnly()) { - if (skip(outDir)) { - return; - } - throw error(outDir, "could not set directory read-only"); + throw skip(outDir, "could not set directory read-only"); } if (outDir.canWrite()) { - throw error(outDir, "directory is writable"); + throw skip(outDir, "directory is writable"); } try { @@ -93,15 +91,15 @@ public void testReadOnlyDirectory() { public void testReadOnlyFile() throws Exception { File outDir = new File("out2"); if (!outDir.mkdir()) { - throw error(outDir, "Cannot create directory"); + throw skip(outDir, "Cannot create directory"); } File index = new File(outDir, "index.html"); try (FileWriter fw = new FileWriter(index)) { } if (!index.setReadOnly()) { - throw error(index, "could not set index read-only"); + throw skip(index, "could not set index read-only"); } if (index.canWrite()) { - throw error(index, "index is writable"); + throw skip(index, "index is writable"); } try { @@ -139,16 +137,13 @@ public void testReadOnlySubdirectory() throws Exception { File outDir = new File("out3"); File pkgOutDir = new File(outDir, "p"); if (!pkgOutDir.mkdirs()) { - throw error(pkgOutDir, "Cannot create directory"); + throw skip(pkgOutDir, "Cannot create directory"); } if (!pkgOutDir.setReadOnly()) { - if (skip(pkgOutDir)) { - return; - } - throw error(pkgOutDir, "could not set directory read-only"); + throw skip(pkgOutDir, "could not set directory read-only"); } if (pkgOutDir.canWrite()) { - throw error(pkgOutDir, "directory is writable"); + throw skip(pkgOutDir, "directory is writable"); } // run javadoc and check results @@ -192,16 +187,13 @@ public void testReadOnlyDocFilesDir() throws Exception { File pkgOutDir = new File(outDir, "p"); File docFilesOutDir = new File(pkgOutDir, "doc-files"); if (!docFilesOutDir.mkdirs()) { - throw error(docFilesOutDir, "Cannot create directory"); + throw skip(docFilesOutDir, "Cannot create directory"); } if (!docFilesOutDir.setReadOnly()) { - if (skip(docFilesOutDir)) { - return; - } - throw error(docFilesOutDir, "could not set directory read-only"); + throw skip(docFilesOutDir, "could not set directory read-only"); } if (docFilesOutDir.canWrite()) { - throw error(docFilesOutDir, "directory is writable"); + throw skip(docFilesOutDir, "directory is writable"); } try { @@ -219,10 +211,11 @@ public void testReadOnlyDocFilesDir() throws Exception { } } - private Error error(File f, String message) { + private Error skip(File f, String message) { + out.print(System.getProperty("user.name")); out.println(f + ": " + message); showAllAttributes(f.toPath()); - throw new Error(f + ": " + message); + throw new SkippedException(f + ": " + message); } private void showAllAttributes(Path p) { @@ -242,20 +235,5 @@ private void showAttributes(Path p, String attributes) { out.println("Error accessing attributes " + attributes + ": " + t); } } - - private boolean skip(File dir) { - if (isWindows()) { - showAllAttributes(dir.toPath()); - out.println("Windows: cannot set directory read only:" + dir); - out.println("TEST CASE SKIPPED"); - return true; - } else { - return false; - } - } - - private boolean isWindows() { - return System.getProperty("os.name").toLowerCase(Locale.US).startsWith("windows"); - } } diff --git a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java index dce8e415ca3..84017f5699a 100644 --- a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java +++ b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java @@ -421,7 +421,7 @@ void checkSearchOutput(String fileName, boolean expectedOutput) { """, """ - + """, """ """, @@ -671,7 +671,7 @@ void checkInvalidUsageIndexTag() { void checkJqueryAndImageFiles(boolean expectedOutput) { checkFiles(expectedOutput, "search.js", - "script-dir/jquery-3.6.1.min.js", + "script-dir/jquery-3.7.1.min.js", "script-dir/jquery-ui.min.js", "script-dir/jquery-ui.min.css", "resources/x.png", diff --git a/test/langtools/jdk/javadoc/doclet/testSearchScript/javadoc-search.js b/test/langtools/jdk/javadoc/doclet/testSearchScript/javadoc-search.js index 668ca9f68ff..b3874d82236 100644 --- a/test/langtools/jdk/javadoc/doclet/testSearchScript/javadoc-search.js +++ b/test/langtools/jdk/javadoc/doclet/testSearchScript/javadoc-search.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ function loadIndexFiles(docsPath) { tryLoad(docsPath, "type-search-index.js"); tryLoad(docsPath, "member-search-index.js"); tryLoad(docsPath, "tag-search-index.js"); - load(docsPath + "/search.js"); + load(docsPath + "/script-files/search.js"); } function tryLoad(docsPath, file) { @@ -63,6 +63,12 @@ var $ = function(f) { f(); } else { return { + attr: function() { + return this; + }, + css: function() { + return this; + }, val: function() { return this; }, diff --git a/test/langtools/jdk/javadoc/tool/api/basic/APITest.java b/test/langtools/jdk/javadoc/tool/api/basic/APITest.java index 6ab0362b69e..350433e6501 100644 --- a/test/langtools/jdk/javadoc/tool/api/basic/APITest.java +++ b/test/langtools/jdk/javadoc/tool/api/basic/APITest.java @@ -202,7 +202,7 @@ protected void error(String msg) { "index-all.html", "index.html", "link.svg", - "script-dir/jquery-3.6.1.min.js", + "script-dir/jquery-3.7.1.min.js", "script-dir/jquery-ui.min.js", "script-dir/jquery-ui.min.css", "search.html", diff --git a/test/langtools/jdk/jshell/AnalyzeSnippetTest.java b/test/langtools/jdk/jshell/AnalyzeSnippetTest.java index b566a023caf..3e2e1a839e2 100644 --- a/test/langtools/jdk/jshell/AnalyzeSnippetTest.java +++ b/test/langtools/jdk/jshell/AnalyzeSnippetTest.java @@ -64,6 +64,7 @@ public void setUp() { state = JShell.builder() .out(new PrintStream(new ByteArrayOutputStream())) .err(new PrintStream(new ByteArrayOutputStream())) + .executionEngine(Presets.TEST_DEFAULT_EXECUTION) .build(); sca = state.sourceCodeAnalysis(); } diff --git a/test/langtools/jdk/jshell/CustomInputToolBuilder.java b/test/langtools/jdk/jshell/CustomInputToolBuilder.java index 3b3d5616a94..523981b3d91 100644 --- a/test/langtools/jdk/jshell/CustomInputToolBuilder.java +++ b/test/langtools/jdk/jshell/CustomInputToolBuilder.java @@ -90,7 +90,8 @@ private void doTest(boolean interactiveTerminal, String code, String... expected .interactiveTerminal(interactiveTerminal) .promptCapture(true) .persistence(new HashMap<>()) - .start("--no-startup"); + .start("--no-startup", + "--execution", Presets.TEST_DEFAULT_EXECUTION); String actual = new String(out.toByteArray()); List actualLines = Arrays.asList(actual.split("\\R")); diff --git a/test/langtools/jdk/jshell/ExecutionControlTestBase.java b/test/langtools/jdk/jshell/ExecutionControlTestBase.java index 9035d84d4a5..20336c902cf 100644 --- a/test/langtools/jdk/jshell/ExecutionControlTestBase.java +++ b/test/langtools/jdk/jshell/ExecutionControlTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * 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,28 +25,14 @@ import org.testng.annotations.Test; import jdk.jshell.VarSnippet; -import java.net.InetAddress; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.SubKind.*; public class ExecutionControlTestBase extends KullaTesting { - String standardListenSpec() { - String loopback = InetAddress.getLoopbackAddress().getHostAddress(); - return "jdi:hostname(" + loopback + ")"; - } - - String standardLaunchSpec() { - return "jdi:launch(true)"; - } - - String standardJdiSpec() { - return "jdi"; - } - - String standardSpecs() { - return "5(" + standardListenSpec() + "), 6(" + standardLaunchSpec() + "), 7(" + standardJdiSpec() + ")"; + String alwaysPassingSpec() { + return "5(local)"; } @Test diff --git a/test/langtools/jdk/jshell/FailOverDirectExecutionControlTest.java b/test/langtools/jdk/jshell/FailOverDirectExecutionControlTest.java index da838798f8e..a094ed4a86f 100644 --- a/test/langtools/jdk/jshell/FailOverDirectExecutionControlTest.java +++ b/test/langtools/jdk/jshell/FailOverDirectExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,9 +129,7 @@ public void setUp() { Map pm = provider.defaultParameters(); pm.put("0", "alwaysFailing"); pm.put("1", "alwaysFailing"); - pm.put("2", standardListenSpec()); - pm.put("3", standardLaunchSpec()); - pm.put("4", standardJdiSpec()); + pm.put("2", "local"); setUp(builder -> builder.executionEngine(provider, pm)); } @@ -159,9 +157,7 @@ public void variables() { assertTrue(log.contains("This operation intentionally broken"), log); log = logged.get(Level.FINEST).get(0); assertTrue( - log.contains("Success failover -- 2 = " + standardListenSpec()) - || log.contains("Success failover -- 3 = " + standardLaunchSpec()) - || log.contains("Success failover -- 4 = " + standardJdiSpec()), + log.contains("Success failover -- 2 = local"), log); } } diff --git a/test/langtools/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java b/test/langtools/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java index f3218fab7c7..31011960880 100644 --- a/test/langtools/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java +++ b/test/langtools/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,6 @@ public class FailOverExecutionControlDyingLaunchTest extends ExecutionControlTes public void setUp() { setUp(builder -> builder.executionEngine( "failover:0(jdi:remoteAgent(DyingRemoteAgent),launch(true)), " - + standardSpecs())); + + alwaysPassingSpec())); } } diff --git a/test/langtools/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java b/test/langtools/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java index 778d004915c..9958b7a3284 100644 --- a/test/langtools/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java +++ b/test/langtools/jdk/jshell/FailOverExecutionControlHangingLaunchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,6 @@ public class FailOverExecutionControlHangingLaunchTest extends ExecutionControlT public void setUp() { setUp(builder -> builder.executionEngine( "failover:0(jdi:remoteAgent(HangingRemoteAgent),launch(true)), " - + standardSpecs())); + + alwaysPassingSpec())); } } diff --git a/test/langtools/jdk/jshell/FailOverExecutionControlHangingListenTest.java b/test/langtools/jdk/jshell/FailOverExecutionControlHangingListenTest.java index f22dd821f40..4f29bfe9c7a 100644 --- a/test/langtools/jdk/jshell/FailOverExecutionControlHangingListenTest.java +++ b/test/langtools/jdk/jshell/FailOverExecutionControlHangingListenTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,6 @@ public void setUp() { String loopback = InetAddress.getLoopbackAddress().getHostAddress(); setUp(builder -> builder.executionEngine( "failover:0(jdi:remoteAgent(HangingRemoteAgent),hostname(" + loopback + "))," - + standardSpecs())); + + alwaysPassingSpec())); } } diff --git a/test/langtools/jdk/jshell/FailOverExecutionControlTest.java b/test/langtools/jdk/jshell/FailOverExecutionControlTest.java index 0843351815f..80dc56d72c4 100644 --- a/test/langtools/jdk/jshell/FailOverExecutionControlTest.java +++ b/test/langtools/jdk/jshell/FailOverExecutionControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * 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 @@ public class FailOverExecutionControlTest extends ExecutionControlTestBase { @Override public void setUp() { setUp(builder -> builder.executionEngine("failover:0(expectedFailureNonExistent1), 1(expectedFailureNonExistent2), " - + standardSpecs())); + + alwaysPassingSpec())); } } diff --git a/test/langtools/jdk/jshell/IdGeneratorTest.java b/test/langtools/jdk/jshell/IdGeneratorTest.java index 23727aef643..e8a38dfe7f0 100644 --- a/test/langtools/jdk/jshell/IdGeneratorTest.java +++ b/test/langtools/jdk/jshell/IdGeneratorTest.java @@ -53,7 +53,8 @@ public JShell.Builder getBuilder() { return JShell.builder() .in(inStream) .out(new PrintStream(outStream)) - .err(new PrintStream(errStream)); + .err(new PrintStream(errStream)) + .executionEngine(Presets.TEST_DEFAULT_EXECUTION); } public void testTempNameGenerator() { diff --git a/test/langtools/jdk/jshell/KullaTesting.java b/test/langtools/jdk/jshell/KullaTesting.java index 369b2ed1f44..d74f3484f4b 100644 --- a/test/langtools/jdk/jshell/KullaTesting.java +++ b/test/langtools/jdk/jshell/KullaTesting.java @@ -100,7 +100,9 @@ public class KullaTesting { private Set allSnippets = new LinkedHashSet<>(); static { - JShell js = JShell.create(); + JShell js = JShell.builder() + .executionEngine(Presets.TEST_DEFAULT_EXECUTION) + .build(); MAIN_SNIPPET = js.eval("MAIN_SNIPPET").get(0).snippet(); js.close(); assertTrue(MAIN_SNIPPET != null, "Bad MAIN_SNIPPET set-up -- must not be null"); @@ -192,7 +194,8 @@ public int read(byte[] b, int off, int len) throws IOException { JShell.Builder builder = JShell.builder() .in(in) .out(new PrintStream(outStream)) - .err(new PrintStream(errStream)); + .err(new PrintStream(errStream)) + .executionEngine(Presets.TEST_DEFAULT_EXECUTION); bc.accept(builder); state = builder.build(); allSnippets = new LinkedHashSet<>(); diff --git a/test/langtools/jdk/jshell/Presets.java b/test/langtools/jdk/jshell/Presets.java new file mode 100644 index 00000000000..b9a93c967dc --- /dev/null +++ b/test/langtools/jdk/jshell/Presets.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * 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.net.InetAddress; +import java.util.*; + +public class Presets { + public static final String TEST_DEFAULT_EXECUTION; + public static final String TEST_STANDARD_EXECUTION; + + static { + String loopback = InetAddress.getLoopbackAddress().getHostAddress(); + + TEST_DEFAULT_EXECUTION = "failover:0(jdi:hostname(" + loopback + "))," + + "1(jdi:launch(true)), 2(jdi), 3(local)"; + TEST_STANDARD_EXECUTION = "failover:0(jdi:hostname(" + loopback + "))," + + "1(jdi:launch(true)), 2(jdi)"; + } + + public static String[] addExecutionIfMissing(String[] args) { + if (Arrays.stream(args).noneMatch(Presets::remoteRelatedOption)) { + List augmentedArgs = new ArrayList<>(); + + augmentedArgs.add("--execution"); + augmentedArgs.add(Presets.TEST_DEFAULT_EXECUTION); + augmentedArgs.addAll(List.of(args)); + + return augmentedArgs.toArray(s -> new String[s]); + } + + return args; + } + + private static boolean remoteRelatedOption(String option) { + return "--execution".equals(option) || + "--add-modules".equals(option) || + option.startsWith("-R"); + } +} diff --git a/test/langtools/jdk/jshell/ReplToolTesting.java b/test/langtools/jdk/jshell/ReplToolTesting.java index 09ee4117c18..52eb2d5798c 100644 --- a/test/langtools/jdk/jshell/ReplToolTesting.java +++ b/test/langtools/jdk/jshell/ReplToolTesting.java @@ -304,7 +304,7 @@ protected JavaShellToolBuilder builder(Locale locale) { private void testRaw(Locale locale, String[] args, String expectedErrorOutput, ReplTest... tests) { testRawInit(tests); - testRawRun(locale, args); + testRawRun(locale, Presets.addExecutionIfMissing(args)); testRawCheck(locale, expectedErrorOutput); } diff --git a/test/langtools/jdk/jshell/StartOptionTest.java b/test/langtools/jdk/jshell/StartOptionTest.java index df445d49750..aa8d9be03a9 100644 --- a/test/langtools/jdk/jshell/StartOptionTest.java +++ b/test/langtools/jdk/jshell/StartOptionTest.java @@ -81,7 +81,7 @@ private JavaShellToolBuilder builder() { protected int runShell(String... args) { try { return builder() - .start(args); + .start(Presets.addExecutionIfMissing(args)); } catch (Exception ex) { fail("Repl tool died with exception", ex); } diff --git a/test/langtools/jdk/jshell/ToolReloadTest.java b/test/langtools/jdk/jshell/ToolReloadTest.java index 13d583e51f5..4709584cd12 100644 --- a/test/langtools/jdk/jshell/ToolReloadTest.java +++ b/test/langtools/jdk/jshell/ToolReloadTest.java @@ -201,7 +201,7 @@ public void testReloadCrashRestore() { } public void testEnvBadModule() { - test( + test(new String[] {"--execution", Presets.TEST_STANDARD_EXECUTION}, (a) -> assertVariable(a, "int", "x", "5", "5"), (a) -> assertMethod(a, "int m(int z) { return z * z; }", "(int)int", "m"), diff --git a/test/langtools/jdk/jshell/UITesting.java b/test/langtools/jdk/jshell/UITesting.java index 484bfde2662..473ba36c5ae 100644 --- a/test/langtools/jdk/jshell/UITesting.java +++ b/test/langtools/jdk/jshell/UITesting.java @@ -93,7 +93,8 @@ protected void doRunTest(Test test) throws Exception { .promptCapture(true) .persistence(new HashMap<>()) .locale(Locale.US) - .run("--no-startup"); + .run("--no-startup", + "--execution", Presets.TEST_DEFAULT_EXECUTION); } catch (Exception ex) { throw new IllegalStateException(ex); } diff --git a/test/langtools/tools/javac/patterns/T8312229.java b/test/langtools/tools/javac/patterns/T8312229.java new file mode 100644 index 00000000000..423864cdcc3 --- /dev/null +++ b/test/langtools/tools/javac/patterns/T8312229.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * 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 8312229 + * @summary Ensure javac does not crash when a variable is used from an anonymous class + * @compile T8312229.java + */ +public class T8312229 { + void test(Object o) { + Runnable r = () -> { + var l = switch (o) { + default -> { + Integer i = 42; + yield new Runnable() { + public void run() { + i.toString(); // should not crash here + } + }; + } + }; + }; + } +} diff --git a/test/langtools/tools/javac/patterns/TranslationTest.java b/test/langtools/tools/javac/patterns/TranslationTest.java index b509b2be3f9..f69783f6b85 100644 --- a/test/langtools/tools/javac/patterns/TranslationTest.java +++ b/test/langtools/tools/javac/patterns/TranslationTest.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8291769 + * @bug 8291769 8326129 * @summary Check expected translation of various pattern related constructs * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -31,7 +31,7 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util - * @build toolbox.ToolBox toolbox.JavacTask + * @build toolbox.ToolBox toolbox.JavacTask toolbox.JavaTask * @run main TranslationTest */ @@ -48,6 +48,7 @@ import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Context.Factory; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -56,6 +57,7 @@ import java.util.List; import toolbox.TestRunner; +import toolbox.JavaTask; import toolbox.JavacTask; import toolbox.Task; import toolbox.ToolBox; @@ -188,6 +190,38 @@ private int test(Object obj) { """); } + @Test //JDK-8326129 + public void testRunWithNull(Path base) throws Exception { + doRunTest(base, + new String[]{""" + package lib; + public record Box(Object o) {} + """}, + """ + import lib.*; + public class Test { + public static void main(String... args) { + System.err.println(new Test().test(new Box(null))); + } + private int test(Box b) { + return switch (b) { + case Box(Integer i) -> 0; + case Box(Object o) when check(o) -> 1; + case Box(Object o) -> 2; + }; + } + private static int c; + private boolean check(Object o) { + System.err.println("check: " + o); + if (c++ > 10) throw new IllegalStateException(); + return o != null; + } + } + """, + "check: null", + "2"); + } + private void doTest(Path base, String[] libraryCode, String testCode, Callback callback, String expectedOutput) throws IOException { Path current = base.resolve("."); @@ -322,4 +356,51 @@ public JCTree translateTopLevelClass(Env env, JCTree cdef, TreeMake } } + + private void doRunTest(Path base, String[] libraryCode, String testCode, + String... expectedOutput) throws IOException { + Path current = base.resolve("."); + Path libClasses = current.resolve("libClasses"); + + Files.createDirectories(libClasses); + + if (libraryCode.length != 0) { + Path libSrc = current.resolve("lib-src"); + + for (String code : libraryCode) { + tb.writeJavaFiles(libSrc, code); + } + + new JavacTask(tb) + .outdir(libClasses) + .files(tb.findJavaFiles(libSrc)) + .run(); + } + + Path src = current.resolve("src"); + tb.writeJavaFiles(src, testCode); + + Path classes = current.resolve("classes"); + + Files.createDirectories(classes); + + new JavacTask(tb) + .options("-Xlint:-preview", + "--class-path", libClasses.toString()) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run() + .writeAll(); + + List log = new JavaTask(tb) + .classpath(libClasses.toString() + File.pathSeparatorChar + classes.toString()) + .classArgs("Test") + .run() + .getOutputLines(Task.OutputKind.STDERR); + + if (!List.of(expectedOutput).equals(log)) { + throw new AssertionError("Expected: " + expectedOutput + + "but got: " + log); + } + } } diff --git a/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java b/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java index f8ce856bddd..e78e200ac24 100644 --- a/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java +++ b/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ private static enum MethodGroup { IGNORED("isEmulatedClient", "isDebugBuild", "isFastDebugBuild", "isMusl", "isSlowDebugBuild", "hasSA", "isRoot", "isTieredSupported", "areCustomLoadersSupportedForCDS", "isDefaultCDSArchiveSupported", - "isHardenedOSX", "hasOSXPlistEntries", "isOracleLinux7"); + "isHardenedOSX", "hasOSXPlistEntries", "isOracleLinux7", "isOnWayland"); public final List methodNames; diff --git a/test/lib/jdk/test/lib/Platform.java b/test/lib/jdk/test/lib/Platform.java index 92663c65d0f..e2451fc8366 100644 --- a/test/lib/jdk/test/lib/Platform.java +++ b/test/lib/jdk/test/lib/Platform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -473,4 +473,13 @@ public static boolean isDefaultCDSArchiveSupported() { public static boolean areCustomLoadersSupportedForCDS() { return (is64bit() && (isLinux() || isOSX() || isWindows())); } + + /** + * Checks if the current system is running on Wayland display server on Linux. + * + * @return {@code true} if the system is running on Wayland display server + */ + public static boolean isOnWayland() { + return System.getenv("WAYLAND_DISPLAY") != null; + } } diff --git a/test/lib/jdk/test/lib/process/OutputAnalyzer.java b/test/lib/jdk/test/lib/process/OutputAnalyzer.java index ad81fd64a1e..51bc3b73765 100644 --- a/test/lib/jdk/test/lib/process/OutputAnalyzer.java +++ b/test/lib/jdk/test/lib/process/OutputAnalyzer.java @@ -42,6 +42,8 @@ public final class OutputAnalyzer { private static final String deprecatedmsg = ".* VM warning:.* deprecated.*"; + private static final String FATAL_ERROR_PAT = "# A fatal error has been detected.*"; + private final OutputBuffer buffer; /** * Create an OutputAnalyzer, a utility class for verifying output and exit @@ -849,4 +851,11 @@ public void shouldContainMultiLinePattern(String... needles) { shouldContainMultiLinePattern(needles, true); } + /** + * Assert that we did not crash with a hard VM error (generating an hs_err_pidXXX.log) + */ + public void shouldNotHaveFatalError() { + shouldNotMatch(FATAL_ERROR_PAT); + } + } diff --git a/test/micro/org/openjdk/bench/java/security/CacheBench.java b/test/micro/org/openjdk/bench/java/security/CacheBench.java index 9b66b2b6337..9b7c39a3cf2 100644 --- a/test/micro/org/openjdk/bench/java/security/CacheBench.java +++ b/test/micro/org/openjdk/bench/java/security/CacheBench.java @@ -44,7 +44,7 @@ @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) -@Fork(value = 3, jvmArgsAppend = {"--add-exports", "java.base/sun.security.util=ALL-UNNAMED", "-Xmx1g"}) +@Fork(value = 3, jvmArgsAppend = {"--add-exports", "java.base/sun.security.util=ALL-UNNAMED"}) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) public class CacheBench { diff --git a/test/micro/org/openjdk/bench/java/security/SSLHandshake.java b/test/micro/org/openjdk/bench/java/security/SSLHandshake.java index 67e51e9532d..62c45045585 100644 --- a/test/micro/org/openjdk/bench/java/security/SSLHandshake.java +++ b/test/micro/org/openjdk/bench/java/security/SSLHandshake.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,11 +80,12 @@ public void init() throws Exception { KeyStore ks = TestCertificates.getKeyStore(); KeyStore ts = TestCertificates.getTrustStore(); - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + KeyManagerFactory kmf = KeyManagerFactory.getInstance( + KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, new char[0]); - TrustManagerFactory tmf = - TrustManagerFactory.getInstance("SunX509"); + TrustManagerFactory tmf = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ts); SSLContext sslCtx = SSLContext.getInstance(tlsVersion); diff --git a/test/micro/org/openjdk/bench/java/security/TestCertificates.java b/test/micro/org/openjdk/bench/java/security/TestCertificates.java index 50d8401c070..752f0442a93 100644 --- a/test/micro/org/openjdk/bench/java/security/TestCertificates.java +++ b/test/micro/org/openjdk/bench/java/security/TestCertificates.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,12 +115,12 @@ class TestCertificates { private TestCertificates() {} public static KeyStore getKeyStore() throws GeneralSecurityException, IOException { - KeyStore result = KeyStore.getInstance("JKS"); + KeyStore result = KeyStore.getInstance(KeyStore.getDefaultType()); result.load(null, null); CertificateFactory cf = CertificateFactory.getInstance("X.509"); Certificate serverCert = cf.generateCertificate( new ByteArrayInputStream( - TestCertificates.SERVER_CERT.getBytes(StandardCharsets.ISO_8859_1))); + SERVER_CERT.getBytes(StandardCharsets.ISO_8859_1))); Certificate caCert = cf.generateCertificate( new ByteArrayInputStream( CA_CERT.getBytes(StandardCharsets.ISO_8859_1))); @@ -135,7 +135,7 @@ public static KeyStore getKeyStore() throws GeneralSecurityException, IOExceptio } public static KeyStore getTrustStore() throws GeneralSecurityException, IOException { - KeyStore result = KeyStore.getInstance("JKS"); + KeyStore result = KeyStore.getInstance(KeyStore.getDefaultType()); result.load(null, null); CertificateFactory cf = CertificateFactory.getInstance("X.509"); Certificate rootcaCert = cf.generateCertificate( diff --git a/test/micro/org/openjdk/bench/java/util/zip/InflaterInputStreams.java b/test/micro/org/openjdk/bench/java/util/zip/InflaterInputStreams.java index ab6be0e9374..33704ad3f9f 100644 --- a/test/micro/org/openjdk/bench/java/util/zip/InflaterInputStreams.java +++ b/test/micro/org/openjdk/bench/java/util/zip/InflaterInputStreams.java @@ -108,7 +108,10 @@ public void beforeIteration() throws IOException { @Benchmark public void inflaterInputStreamRead() throws IOException { deflated.reset(); - InflaterInputStream iis = new InflaterInputStream(deflated); - while (iis.read(inflated, 0, inflated.length) != -1); + // We close the InflaterInputStream to release underlying native resources of the Inflater. + // The "deflated" ByteArrayInputStream remains unaffected. + try (InflaterInputStream iis = new InflaterInputStream(deflated)) { + while (iis.read(inflated, 0, inflated.length) != -1); + } } }